@tscircuit/core 0.0.550 → 0.0.552
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1200 -1211
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -54,7 +54,7 @@ __export(components_exports, {
|
|
|
54
54
|
Subcircuit: () => Subcircuit,
|
|
55
55
|
Switch: () => Switch,
|
|
56
56
|
TestPoint: () => TestPoint,
|
|
57
|
-
Trace: () =>
|
|
57
|
+
Trace: () => Trace3,
|
|
58
58
|
TraceHint: () => TraceHint,
|
|
59
59
|
Transistor: () => Transistor,
|
|
60
60
|
Via: () => Via
|
|
@@ -3602,10 +3602,10 @@ var getNumericSchPinStyle = (pinStyles, pinLabels) => {
|
|
|
3602
3602
|
};
|
|
3603
3603
|
|
|
3604
3604
|
// lib/components/primitive-components/Trace/Trace.ts
|
|
3605
|
-
import
|
|
3605
|
+
import "@tscircuit/infgrid-ijump-astar";
|
|
3606
3606
|
import { traceProps } from "@tscircuit/props";
|
|
3607
3607
|
import "circuit-json";
|
|
3608
|
-
import
|
|
3608
|
+
import "circuit-json-to-connectivity-map";
|
|
3609
3609
|
|
|
3610
3610
|
// lib/utils/autorouting/DirectLineRouter.ts
|
|
3611
3611
|
var DirectLineRouter = class {
|
|
@@ -3890,198 +3890,7 @@ function tryNow(fn) {
|
|
|
3890
3890
|
// lib/components/primitive-components/Trace/Trace.ts
|
|
3891
3891
|
import "zod";
|
|
3892
3892
|
|
|
3893
|
-
// lib/components/primitive-components/Trace/
|
|
3894
|
-
function getTraceLength(route) {
|
|
3895
|
-
let totalLength = 0;
|
|
3896
|
-
for (let i = 0; i < route.length; i++) {
|
|
3897
|
-
const point = route[i];
|
|
3898
|
-
if (point.route_type === "wire") {
|
|
3899
|
-
const nextPoint = route[i + 1];
|
|
3900
|
-
if (nextPoint) {
|
|
3901
|
-
const dx = nextPoint.x - point.x;
|
|
3902
|
-
const dy = nextPoint.y - point.y;
|
|
3903
|
-
totalLength += Math.sqrt(dx * dx + dy * dy);
|
|
3904
|
-
}
|
|
3905
|
-
} else if (point.route_type === "via") {
|
|
3906
|
-
totalLength += 1.6;
|
|
3907
|
-
}
|
|
3908
|
-
}
|
|
3909
|
-
return totalLength;
|
|
3910
|
-
}
|
|
3911
|
-
|
|
3912
|
-
// lib/components/primitive-components/Trace/create-schematic-trace-crossing-segments.ts
|
|
3913
|
-
import { distance as distance2, doesLineIntersectLine } from "@tscircuit/math-utils";
|
|
3914
|
-
|
|
3915
|
-
// lib/components/primitive-components/Trace/get-other-schematic-traces.ts
|
|
3916
|
-
var getOtherSchematicTraces = ({
|
|
3917
|
-
db,
|
|
3918
|
-
source_trace_id,
|
|
3919
|
-
sameNetOnly,
|
|
3920
|
-
differentNetOnly
|
|
3921
|
-
}) => {
|
|
3922
|
-
if (!sameNetOnly && !differentNetOnly) {
|
|
3923
|
-
differentNetOnly = true;
|
|
3924
|
-
}
|
|
3925
|
-
const mySourceTrace = db.source_trace.get(source_trace_id);
|
|
3926
|
-
const traces = [];
|
|
3927
|
-
for (const otherSchematicTrace of db.schematic_trace.list()) {
|
|
3928
|
-
if (otherSchematicTrace.source_trace_id === source_trace_id) continue;
|
|
3929
|
-
const otherSourceTrace = db.source_trace.get(
|
|
3930
|
-
otherSchematicTrace.source_trace_id
|
|
3931
|
-
);
|
|
3932
|
-
const isSameNet = otherSourceTrace?.subcircuit_connectivity_map_key === mySourceTrace.subcircuit_connectivity_map_key;
|
|
3933
|
-
if (differentNetOnly && isSameNet) {
|
|
3934
|
-
continue;
|
|
3935
|
-
}
|
|
3936
|
-
if (sameNetOnly && !isSameNet) {
|
|
3937
|
-
continue;
|
|
3938
|
-
}
|
|
3939
|
-
traces.push(otherSchematicTrace);
|
|
3940
|
-
}
|
|
3941
|
-
return traces;
|
|
3942
|
-
};
|
|
3943
|
-
|
|
3944
|
-
// lib/components/primitive-components/Trace/create-schematic-trace-crossing-segments.ts
|
|
3945
|
-
import { getUnitVectorFromPointAToB } from "@tscircuit/math-utils";
|
|
3946
|
-
var createSchematicTraceCrossingSegments = ({
|
|
3947
|
-
edges: inputEdges,
|
|
3948
|
-
otherEdges
|
|
3949
|
-
}) => {
|
|
3950
|
-
const edges = [...inputEdges];
|
|
3951
|
-
for (let i = 0; i < edges.length; i++) {
|
|
3952
|
-
if (i > 2e3) {
|
|
3953
|
-
throw new Error(
|
|
3954
|
-
"Over 2000 iterations spent inside createSchematicTraceCrossingSegments, you have triggered an infinite loop, please report this!"
|
|
3955
|
-
);
|
|
3956
|
-
}
|
|
3957
|
-
const edge = edges[i];
|
|
3958
|
-
const edgeOrientation = Math.abs(edge.from.x - edge.to.x) < 0.01 ? "vertical" : edge.from.y === edge.to.y ? "horizontal" : "not-orthogonal";
|
|
3959
|
-
if (edgeOrientation === "not-orthogonal") {
|
|
3960
|
-
continue;
|
|
3961
|
-
}
|
|
3962
|
-
const otherEdgesIntersections = [];
|
|
3963
|
-
for (const otherEdge of otherEdges) {
|
|
3964
|
-
const otherOrientation = otherEdge.from.x === otherEdge.to.x ? "vertical" : otherEdge.from.y === otherEdge.to.y ? "horizontal" : "not-orthogonal";
|
|
3965
|
-
if (otherOrientation === "not-orthogonal") continue;
|
|
3966
|
-
if (edgeOrientation === otherOrientation)
|
|
3967
|
-
continue;
|
|
3968
|
-
const hasIntersection = doesLineIntersectLine(
|
|
3969
|
-
[edge.from, edge.to],
|
|
3970
|
-
[otherEdge.from, otherEdge.to],
|
|
3971
|
-
{ lineThickness: 0.01 }
|
|
3972
|
-
);
|
|
3973
|
-
if (hasIntersection) {
|
|
3974
|
-
const intersectX = edgeOrientation === "vertical" ? edge.from.x : otherEdge.from.x;
|
|
3975
|
-
const intersectY = edgeOrientation === "vertical" ? otherEdge.from.y : edge.from.y;
|
|
3976
|
-
const crossingPoint2 = { x: intersectX, y: intersectY };
|
|
3977
|
-
otherEdgesIntersections.push({
|
|
3978
|
-
otherEdge,
|
|
3979
|
-
crossingPoint: crossingPoint2,
|
|
3980
|
-
distanceFromEdgeFrom: distance2(edge.from, crossingPoint2)
|
|
3981
|
-
});
|
|
3982
|
-
}
|
|
3983
|
-
}
|
|
3984
|
-
if (otherEdgesIntersections.length === 0) continue;
|
|
3985
|
-
let closestIntersection = otherEdgesIntersections[0];
|
|
3986
|
-
for (const intersection of otherEdgesIntersections) {
|
|
3987
|
-
if (intersection.distanceFromEdgeFrom < closestIntersection.distanceFromEdgeFrom) {
|
|
3988
|
-
closestIntersection = intersection;
|
|
3989
|
-
}
|
|
3990
|
-
}
|
|
3991
|
-
const crossingPoint = closestIntersection.crossingPoint;
|
|
3992
|
-
const crossingSegmentLength = 0.075;
|
|
3993
|
-
if (crossingPoint.x === edge.from.x && crossingPoint.y === edge.from.y) {
|
|
3994
|
-
continue;
|
|
3995
|
-
}
|
|
3996
|
-
const crossingUnitVec = getUnitVectorFromPointAToB(edge.from, crossingPoint);
|
|
3997
|
-
const beforeCrossing = {
|
|
3998
|
-
x: crossingPoint.x - crossingUnitVec.x * crossingSegmentLength / 2,
|
|
3999
|
-
y: crossingPoint.y - crossingUnitVec.y * crossingSegmentLength / 2
|
|
4000
|
-
};
|
|
4001
|
-
const afterCrossing = {
|
|
4002
|
-
x: crossingPoint.x + crossingUnitVec.x * crossingSegmentLength / 2,
|
|
4003
|
-
y: crossingPoint.y + crossingUnitVec.y * crossingSegmentLength / 2
|
|
4004
|
-
};
|
|
4005
|
-
const overshot = distance2(afterCrossing, edge.to) < crossingSegmentLength;
|
|
4006
|
-
const newEdges = [
|
|
4007
|
-
{ from: edge.from, to: beforeCrossing },
|
|
4008
|
-
{ from: beforeCrossing, to: afterCrossing, is_crossing: true },
|
|
4009
|
-
{ from: afterCrossing, to: edge.to }
|
|
4010
|
-
];
|
|
4011
|
-
edges.splice(i, 1, ...newEdges);
|
|
4012
|
-
i += newEdges.length - 2;
|
|
4013
|
-
if (overshot) {
|
|
4014
|
-
i++;
|
|
4015
|
-
}
|
|
4016
|
-
}
|
|
4017
|
-
return edges;
|
|
4018
|
-
};
|
|
4019
|
-
|
|
4020
|
-
// lib/components/primitive-components/Trace/create-schematic-trace-junctions.ts
|
|
4021
|
-
var getIntersectionPoint = (edge1, edge2) => {
|
|
4022
|
-
if (edge1.from.x === edge1.to.x && edge2.from.x === edge2.to.x) {
|
|
4023
|
-
return null;
|
|
4024
|
-
}
|
|
4025
|
-
if (edge1.from.x === edge1.to.x) {
|
|
4026
|
-
const x2 = edge1.from.x;
|
|
4027
|
-
const m22 = (edge2.to.y - edge2.from.y) / (edge2.to.x - edge2.from.x);
|
|
4028
|
-
const b22 = edge2.from.y - m22 * edge2.from.x;
|
|
4029
|
-
const y2 = m22 * x2 + b22;
|
|
4030
|
-
if (x2 >= Math.min(edge2.from.x, edge2.to.x) && x2 <= Math.max(edge2.from.x, edge2.to.x) && y2 >= Math.min(edge2.from.y, edge2.to.y) && y2 <= Math.max(edge2.from.y, edge2.to.y)) {
|
|
4031
|
-
return { x: x2, y: y2 };
|
|
4032
|
-
}
|
|
4033
|
-
return null;
|
|
4034
|
-
}
|
|
4035
|
-
if (edge2.from.x === edge2.to.x) {
|
|
4036
|
-
const x2 = edge2.from.x;
|
|
4037
|
-
const m12 = (edge1.to.y - edge1.from.y) / (edge1.to.x - edge1.from.x);
|
|
4038
|
-
const b12 = edge1.from.y - m12 * edge1.from.x;
|
|
4039
|
-
const y2 = m12 * x2 + b12;
|
|
4040
|
-
if (x2 >= Math.min(edge1.from.x, edge1.to.x) && x2 <= Math.max(edge1.from.x, edge1.to.x) && y2 >= Math.min(edge1.from.y, edge1.to.y) && y2 <= Math.max(edge1.from.y, edge1.to.y)) {
|
|
4041
|
-
return { x: x2, y: y2 };
|
|
4042
|
-
}
|
|
4043
|
-
return null;
|
|
4044
|
-
}
|
|
4045
|
-
const m1 = (edge1.to.y - edge1.from.y) / (edge1.to.x - edge1.from.x);
|
|
4046
|
-
const b1 = edge1.from.y - m1 * edge1.from.x;
|
|
4047
|
-
const m2 = (edge2.to.y - edge2.from.y) / (edge2.to.x - edge2.from.x);
|
|
4048
|
-
const b2 = edge2.from.y - m2 * edge2.from.x;
|
|
4049
|
-
if (m1 === m2) {
|
|
4050
|
-
return null;
|
|
4051
|
-
}
|
|
4052
|
-
const x = (b2 - b1) / (m1 - m2);
|
|
4053
|
-
const y = m1 * x + b1;
|
|
4054
|
-
const isWithinEdge1 = x >= Math.min(edge1.from.x, edge1.to.x) && x <= Math.max(edge1.from.x, edge1.to.x) && y >= Math.min(edge1.from.y, edge1.to.y) && y <= Math.max(edge1.from.y, edge1.to.y);
|
|
4055
|
-
const isWithinEdge2 = x >= Math.min(edge2.from.x, edge2.to.x) && x <= Math.max(edge2.from.x, edge2.to.x) && y >= Math.min(edge2.from.y, edge2.to.y) && y <= Math.max(edge2.from.y, edge2.to.y);
|
|
4056
|
-
if (isWithinEdge1 && isWithinEdge2) {
|
|
4057
|
-
return { x, y };
|
|
4058
|
-
}
|
|
4059
|
-
return null;
|
|
4060
|
-
};
|
|
4061
|
-
var createSchematicTraceJunctions = ({
|
|
4062
|
-
edges: myEdges,
|
|
4063
|
-
db,
|
|
4064
|
-
source_trace_id
|
|
4065
|
-
}) => {
|
|
4066
|
-
const otherEdges = getOtherSchematicTraces({
|
|
4067
|
-
db,
|
|
4068
|
-
source_trace_id,
|
|
4069
|
-
sameNetOnly: true
|
|
4070
|
-
}).flatMap((t) => t.edges);
|
|
4071
|
-
const junctions = /* @__PURE__ */ new Set();
|
|
4072
|
-
for (const myEdge of myEdges) {
|
|
4073
|
-
for (const otherEdge of otherEdges) {
|
|
4074
|
-
const intersection = getIntersectionPoint(myEdge, otherEdge);
|
|
4075
|
-
if (intersection) {
|
|
4076
|
-
const pointKey = `${intersection.x},${intersection.y}`;
|
|
4077
|
-
return [{ x: intersection.x, y: intersection.y }];
|
|
4078
|
-
}
|
|
4079
|
-
}
|
|
4080
|
-
}
|
|
4081
|
-
return [];
|
|
4082
|
-
};
|
|
4083
|
-
|
|
4084
|
-
// lib/components/primitive-components/Trace/get-max-length-from-connected-capacitors.ts
|
|
3893
|
+
// lib/components/primitive-components/Trace/trace-utils/get-max-length-from-connected-capacitors.ts
|
|
4085
3894
|
var getMaxLengthFromConnectedCapacitors = (ports, { db }) => {
|
|
4086
3895
|
const capacitorMaxLengths = ports.map((port) => {
|
|
4087
3896
|
const sourcePort = db.source_port.get(port.source_port_id);
|
|
@@ -4098,219 +3907,20 @@ var getMaxLengthFromConnectedCapacitors = (ports, { db }) => {
|
|
|
4098
3907
|
return Math.min(...capacitorMaxLengths);
|
|
4099
3908
|
};
|
|
4100
3909
|
|
|
4101
|
-
// lib/components/primitive-components/Trace/get-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
let cx, cy, w, h;
|
|
4109
|
-
if (elm.type === "schematic_component") {
|
|
4110
|
-
cx = elm.center?.x;
|
|
4111
|
-
cy = elm.center?.y;
|
|
4112
|
-
w = elm.size?.width;
|
|
4113
|
-
h = elm.size?.height;
|
|
4114
|
-
} else if (elm.type === "schematic_box") {
|
|
4115
|
-
cx = elm.x;
|
|
4116
|
-
cy = elm.y;
|
|
4117
|
-
w = elm.width;
|
|
4118
|
-
h = elm.height;
|
|
4119
|
-
} else if (elm.type === "schematic_port") {
|
|
4120
|
-
cx = elm.center?.x;
|
|
4121
|
-
cy = elm.center?.y;
|
|
4122
|
-
w = 0.2;
|
|
4123
|
-
h = 0.2;
|
|
4124
|
-
} else if (elm.type === "schematic_text") {
|
|
4125
|
-
cx = elm.position?.x;
|
|
4126
|
-
cy = elm.position?.y;
|
|
4127
|
-
w = (elm.text?.length ?? 0) * 0.1;
|
|
4128
|
-
h = 0.2;
|
|
4129
|
-
}
|
|
4130
|
-
if (typeof cx === "number" && typeof cy === "number" && typeof w === "number" && typeof h === "number") {
|
|
4131
|
-
minX = Math.min(minX, cx - w / 2);
|
|
4132
|
-
maxX = Math.max(maxX, cx + w / 2);
|
|
4133
|
-
minY = Math.min(minY, cy - h / 2);
|
|
4134
|
-
maxY = Math.max(maxY, cy + h / 2);
|
|
4135
|
-
}
|
|
3910
|
+
// lib/components/primitive-components/Trace/trace-utils/get-trace-display-name.ts
|
|
3911
|
+
function getTraceDisplayName({
|
|
3912
|
+
ports,
|
|
3913
|
+
nets
|
|
3914
|
+
}) {
|
|
3915
|
+
if (ports.length >= 2) {
|
|
3916
|
+
return `${ports[0]?.selector} to ${ports[1]?.selector}`;
|
|
4136
3917
|
}
|
|
4137
|
-
|
|
3918
|
+
if (ports.length === 1 && nets.length === 1) {
|
|
3919
|
+
return `${ports[0]?.selector} to net.${nets[0]._parsedProps.name}`;
|
|
3920
|
+
}
|
|
3921
|
+
return void 0;
|
|
4138
3922
|
}
|
|
4139
3923
|
|
|
4140
|
-
// lib/utils/autorouting/getObstaclesFromBounds.ts
|
|
4141
|
-
function getObstaclesFromBounds(bounds, opts = {}) {
|
|
4142
|
-
const { minX, maxX, minY, maxY } = bounds;
|
|
4143
|
-
const PADDING = opts.padding ?? 1;
|
|
4144
|
-
if (!isFinite(minX) || !isFinite(maxX) || !isFinite(minY) || !isFinite(maxY))
|
|
4145
|
-
return [];
|
|
4146
|
-
const left = minX - PADDING;
|
|
4147
|
-
const right = maxX + PADDING;
|
|
4148
|
-
const top = maxY + PADDING;
|
|
4149
|
-
const bottom = minY - PADDING;
|
|
4150
|
-
const thickness = 0.01;
|
|
4151
|
-
return [
|
|
4152
|
-
// Top border (horizontal)
|
|
4153
|
-
{
|
|
4154
|
-
type: "rect",
|
|
4155
|
-
layers: ["top"],
|
|
4156
|
-
center: { x: (left + right) / 2, y: top },
|
|
4157
|
-
width: right - left,
|
|
4158
|
-
height: thickness,
|
|
4159
|
-
connectedTo: []
|
|
4160
|
-
},
|
|
4161
|
-
// Bottom border (horizontal)
|
|
4162
|
-
{
|
|
4163
|
-
type: "rect",
|
|
4164
|
-
layers: ["top"],
|
|
4165
|
-
center: { x: (left + right) / 2, y: bottom },
|
|
4166
|
-
width: right - left,
|
|
4167
|
-
height: thickness,
|
|
4168
|
-
connectedTo: []
|
|
4169
|
-
},
|
|
4170
|
-
// Left border (vertical)
|
|
4171
|
-
{
|
|
4172
|
-
type: "rect",
|
|
4173
|
-
layers: ["top"],
|
|
4174
|
-
center: { x: left, y: (top + bottom) / 2 },
|
|
4175
|
-
width: thickness,
|
|
4176
|
-
height: top - bottom,
|
|
4177
|
-
connectedTo: []
|
|
4178
|
-
},
|
|
4179
|
-
// Right border (vertical)
|
|
4180
|
-
{
|
|
4181
|
-
type: "rect",
|
|
4182
|
-
layers: ["top"],
|
|
4183
|
-
center: { x: right, y: (top + bottom) / 2 },
|
|
4184
|
-
width: thickness,
|
|
4185
|
-
height: top - bottom,
|
|
4186
|
-
connectedTo: []
|
|
4187
|
-
}
|
|
4188
|
-
];
|
|
4189
|
-
}
|
|
4190
|
-
|
|
4191
|
-
// lib/components/primitive-components/Trace/get-obstacles-for-trace.ts
|
|
4192
|
-
var getSchematicObstaclesForTrace = (trace) => {
|
|
4193
|
-
const db = trace.root.db;
|
|
4194
|
-
const connectedPorts = trace._findConnectedPorts().ports ?? [];
|
|
4195
|
-
const connectedPortIds = new Set(
|
|
4196
|
-
connectedPorts.map((p) => p.schematic_port_id)
|
|
4197
|
-
);
|
|
4198
|
-
const obstacles = [];
|
|
4199
|
-
for (const elm of db.toArray()) {
|
|
4200
|
-
if (elm.type === "schematic_component") {
|
|
4201
|
-
const isSymbol = Boolean(elm.symbol_name);
|
|
4202
|
-
const dominateAxis = elm.size.width > elm.size.height ? "horz" : "vert";
|
|
4203
|
-
obstacles.push({
|
|
4204
|
-
type: "rect",
|
|
4205
|
-
layers: ["top"],
|
|
4206
|
-
center: elm.center,
|
|
4207
|
-
width: elm.size.width + (isSymbol && dominateAxis === "horz" ? -0.5 : 0),
|
|
4208
|
-
height: elm.size.height + (isSymbol && dominateAxis === "vert" ? -0.5 : 0),
|
|
4209
|
-
connectedTo: []
|
|
4210
|
-
});
|
|
4211
|
-
}
|
|
4212
|
-
if (elm.type === "schematic_port") {
|
|
4213
|
-
if (connectedPortIds.has(elm.schematic_port_id)) {
|
|
4214
|
-
continue;
|
|
4215
|
-
}
|
|
4216
|
-
const dirVec = elm.facing_direction ? getUnitVectorFromDirection(elm.facing_direction) : {
|
|
4217
|
-
x: 0,
|
|
4218
|
-
y: 0
|
|
4219
|
-
};
|
|
4220
|
-
obstacles.push({
|
|
4221
|
-
type: "rect",
|
|
4222
|
-
layers: ["top"],
|
|
4223
|
-
center: {
|
|
4224
|
-
x: elm.center.x - dirVec.x * 0.1,
|
|
4225
|
-
y: elm.center.y - dirVec.y * 0.1
|
|
4226
|
-
},
|
|
4227
|
-
width: 0.1 + Math.abs(dirVec.x) * 0.3,
|
|
4228
|
-
height: 0.1 + Math.abs(dirVec.y) * 0.3,
|
|
4229
|
-
connectedTo: []
|
|
4230
|
-
});
|
|
4231
|
-
}
|
|
4232
|
-
if (elm.type === "schematic_text") {
|
|
4233
|
-
obstacles.push({
|
|
4234
|
-
type: "rect",
|
|
4235
|
-
layers: ["top"],
|
|
4236
|
-
center: elm.position,
|
|
4237
|
-
width: (elm.text?.length ?? 0) * 0.1,
|
|
4238
|
-
height: 0.2,
|
|
4239
|
-
connectedTo: []
|
|
4240
|
-
});
|
|
4241
|
-
}
|
|
4242
|
-
if (elm.type === "schematic_box") {
|
|
4243
|
-
obstacles.push({
|
|
4244
|
-
type: "rect",
|
|
4245
|
-
layers: ["top"],
|
|
4246
|
-
center: { x: elm.x, y: elm.y },
|
|
4247
|
-
width: elm.width,
|
|
4248
|
-
height: elm.height,
|
|
4249
|
-
connectedTo: []
|
|
4250
|
-
});
|
|
4251
|
-
}
|
|
4252
|
-
}
|
|
4253
|
-
const bounds = getBoundsForSchematic(db.toArray());
|
|
4254
|
-
obstacles.push(...getObstaclesFromBounds(bounds, { padding: 1 }));
|
|
4255
|
-
return obstacles;
|
|
4256
|
-
};
|
|
4257
|
-
|
|
4258
|
-
// lib/components/primitive-components/Trace/get-trace-display-name.ts
|
|
4259
|
-
function getTraceDisplayName({
|
|
4260
|
-
ports,
|
|
4261
|
-
nets
|
|
4262
|
-
}) {
|
|
4263
|
-
if (ports.length >= 2) {
|
|
4264
|
-
return `${ports[0]?.selector} to ${ports[1]?.selector}`;
|
|
4265
|
-
}
|
|
4266
|
-
if (ports.length === 1 && nets.length === 1) {
|
|
4267
|
-
return `${ports[0]?.selector} to net.${nets[0]._parsedProps.name}`;
|
|
4268
|
-
}
|
|
4269
|
-
return void 0;
|
|
4270
|
-
}
|
|
4271
|
-
|
|
4272
|
-
// lib/components/primitive-components/Trace/push-edges-of-schematic-trace-to-prevent-overlap.ts
|
|
4273
|
-
import { doesLineIntersectLine as doesLineIntersectLine2 } from "@tscircuit/math-utils";
|
|
4274
|
-
var pushEdgesOfSchematicTraceToPreventOverlap = ({
|
|
4275
|
-
edges,
|
|
4276
|
-
db,
|
|
4277
|
-
source_trace_id
|
|
4278
|
-
}) => {
|
|
4279
|
-
const mySourceTrace = db.source_trace.get(source_trace_id);
|
|
4280
|
-
const otherEdges = getOtherSchematicTraces({
|
|
4281
|
-
db,
|
|
4282
|
-
source_trace_id,
|
|
4283
|
-
differentNetOnly: true
|
|
4284
|
-
}).flatMap((t) => t.edges);
|
|
4285
|
-
const edgeOrientation = (edge) => {
|
|
4286
|
-
const { from, to } = edge;
|
|
4287
|
-
return from.x === to.x ? "vertical" : "horizontal";
|
|
4288
|
-
};
|
|
4289
|
-
for (const mySegment of edges) {
|
|
4290
|
-
const mySegmentOrientation = edgeOrientation(mySegment);
|
|
4291
|
-
const findOverlappingParallelSegment = () => otherEdges.find(
|
|
4292
|
-
(otherEdge) => edgeOrientation(otherEdge) === mySegmentOrientation && doesLineIntersectLine2(
|
|
4293
|
-
[mySegment.from, mySegment.to],
|
|
4294
|
-
[otherEdge.from, otherEdge.to],
|
|
4295
|
-
{
|
|
4296
|
-
lineThickness: 0.05
|
|
4297
|
-
}
|
|
4298
|
-
)
|
|
4299
|
-
);
|
|
4300
|
-
let overlappingParallelSegmentFromOtherTrace = findOverlappingParallelSegment();
|
|
4301
|
-
while (overlappingParallelSegmentFromOtherTrace) {
|
|
4302
|
-
if (mySegmentOrientation === "horizontal") {
|
|
4303
|
-
mySegment.from.y += 0.1;
|
|
4304
|
-
mySegment.to.y += 0.1;
|
|
4305
|
-
} else {
|
|
4306
|
-
mySegment.from.x += 0.1;
|
|
4307
|
-
mySegment.to.x += 0.1;
|
|
4308
|
-
}
|
|
4309
|
-
overlappingParallelSegmentFromOtherTrace = findOverlappingParallelSegment();
|
|
4310
|
-
}
|
|
4311
|
-
}
|
|
4312
|
-
};
|
|
4313
|
-
|
|
4314
3924
|
// lib/utils/is-route-outside-board.ts
|
|
4315
3925
|
var isRouteOutsideBoard = (mergedRoute, { db }) => {
|
|
4316
3926
|
const pcbBoard = db.pcb_board.list()[0];
|
|
@@ -4760,122 +4370,1116 @@ var computeSchematicNetLabelCenter = ({
|
|
|
4760
4370
|
return center;
|
|
4761
4371
|
};
|
|
4762
4372
|
|
|
4763
|
-
// lib/components/primitive-components/Trace/
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
var
|
|
4772
|
-
|
|
4773
|
-
source_trace_id
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
constructor(props) {
|
|
4780
|
-
super(props);
|
|
4781
|
-
this._portsRoutedOnPcb = [];
|
|
4782
|
-
}
|
|
4783
|
-
get config() {
|
|
4784
|
-
return {
|
|
4785
|
-
zodProps: traceProps,
|
|
4786
|
-
componentName: "Trace"
|
|
4787
|
-
};
|
|
4373
|
+
// lib/components/primitive-components/Trace/Trace_doInitialSchematicTraceRender.ts
|
|
4374
|
+
import { MultilayerIjump } from "@tscircuit/infgrid-ijump-astar";
|
|
4375
|
+
import "circuit-json";
|
|
4376
|
+
|
|
4377
|
+
// lib/components/primitive-components/Trace/trace-utils/create-schematic-trace-crossing-segments.ts
|
|
4378
|
+
import { distance as distance2, doesLineIntersectLine } from "@tscircuit/math-utils";
|
|
4379
|
+
|
|
4380
|
+
// lib/components/primitive-components/Trace/trace-utils/get-other-schematic-traces.ts
|
|
4381
|
+
var getOtherSchematicTraces = ({
|
|
4382
|
+
db,
|
|
4383
|
+
source_trace_id,
|
|
4384
|
+
sameNetOnly,
|
|
4385
|
+
differentNetOnly
|
|
4386
|
+
}) => {
|
|
4387
|
+
if (!sameNetOnly && !differentNetOnly) {
|
|
4388
|
+
differentNetOnly = true;
|
|
4788
4389
|
}
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
-
|
|
4794
|
-
|
|
4390
|
+
const mySourceTrace = db.source_trace.get(source_trace_id);
|
|
4391
|
+
const traces = [];
|
|
4392
|
+
for (const otherSchematicTrace of db.schematic_trace.list()) {
|
|
4393
|
+
if (otherSchematicTrace.source_trace_id === source_trace_id) continue;
|
|
4394
|
+
const otherSourceTrace = db.source_trace.get(
|
|
4395
|
+
otherSchematicTrace.source_trace_id
|
|
4396
|
+
);
|
|
4397
|
+
const isSameNet = otherSourceTrace?.subcircuit_connectivity_map_key === mySourceTrace.subcircuit_connectivity_map_key;
|
|
4398
|
+
if (differentNetOnly && isSameNet) {
|
|
4399
|
+
continue;
|
|
4795
4400
|
}
|
|
4796
|
-
if (
|
|
4797
|
-
|
|
4798
|
-
(p) => typeof p === "string" ? p : p.getPortSelector()
|
|
4799
|
-
);
|
|
4401
|
+
if (sameNetOnly && !isSameNet) {
|
|
4402
|
+
continue;
|
|
4800
4403
|
}
|
|
4801
|
-
|
|
4802
|
-
}
|
|
4803
|
-
getTracePortPathSelectors() {
|
|
4804
|
-
return this._getTracePortOrNetSelectorListFromProps().filter(
|
|
4805
|
-
(selector) => !selector.includes("net.")
|
|
4806
|
-
);
|
|
4807
|
-
}
|
|
4808
|
-
getTracePathNetSelectors() {
|
|
4809
|
-
return this._getTracePortOrNetSelectorListFromProps().filter(
|
|
4810
|
-
(selector) => selector.includes("net.")
|
|
4811
|
-
);
|
|
4404
|
+
traces.push(otherSchematicTrace);
|
|
4812
4405
|
}
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
|
|
4816
|
-
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
|
|
4820
|
-
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
|
|
4828
|
-
parentSelector = selector.slice(0, dotIndex);
|
|
4829
|
-
portToken = selector.slice(dotIndex + 1);
|
|
4830
|
-
} else {
|
|
4831
|
-
const match = selector.match(/^(.*[ >])?([^ >]+)$/);
|
|
4832
|
-
parentSelector = match?.[1]?.trim() ?? "";
|
|
4833
|
-
portToken = match?.[2] ?? selector;
|
|
4834
|
-
}
|
|
4835
|
-
let targetComponent = parentSelector ? this.getSubcircuit().selectOne(parentSelector) : null;
|
|
4836
|
-
if (!targetComponent && parentSelector && !/[.#\[]/.test(parentSelector)) {
|
|
4837
|
-
targetComponent = this.getSubcircuit().selectOne(`.${parentSelector}`);
|
|
4838
|
-
}
|
|
4839
|
-
if (!targetComponent) {
|
|
4840
|
-
if (parentSelector) {
|
|
4841
|
-
this.renderError(
|
|
4842
|
-
`Could not find port for selector "${selector}". Component "${parentSelector}" not found`
|
|
4843
|
-
);
|
|
4844
|
-
} else {
|
|
4845
|
-
this.renderError(`Could not find port for selector "${selector}"`);
|
|
4846
|
-
}
|
|
4847
|
-
} else {
|
|
4848
|
-
const ports = targetComponent.children.filter(
|
|
4849
|
-
(c) => c.componentName === "Port"
|
|
4850
|
-
);
|
|
4851
|
-
const portLabel = portToken.includes(".") ? portToken.split(".").pop() ?? "" : portToken;
|
|
4852
|
-
const portNames = ports.map((c) => c.getNameAndAliases()).flat();
|
|
4853
|
-
const hasCustomLabels = portNames.some(
|
|
4854
|
-
(n) => !/^(pin\d+|\d+)$/.test(n)
|
|
4855
|
-
);
|
|
4856
|
-
const labelList = Array.from(new Set(portNames)).join(", ");
|
|
4857
|
-
let detail;
|
|
4858
|
-
if (ports.length === 0) {
|
|
4859
|
-
detail = "It has no ports";
|
|
4860
|
-
} else if (!hasCustomLabels) {
|
|
4861
|
-
detail = `It has ${ports.length} pins and no pinLabels (consider adding pinLabels)`;
|
|
4862
|
-
} else {
|
|
4863
|
-
detail = `It has [${labelList}]`;
|
|
4864
|
-
}
|
|
4865
|
-
this.renderError(
|
|
4866
|
-
`Could not find port for selector "${selector}". Component "${targetComponent.props.name ?? parentSelector}" found, but does not have pin "${portLabel}". ${detail}`
|
|
4867
|
-
);
|
|
4868
|
-
}
|
|
4869
|
-
}
|
|
4406
|
+
return traces;
|
|
4407
|
+
};
|
|
4408
|
+
|
|
4409
|
+
// lib/components/primitive-components/Trace/trace-utils/create-schematic-trace-crossing-segments.ts
|
|
4410
|
+
import { getUnitVectorFromPointAToB } from "@tscircuit/math-utils";
|
|
4411
|
+
var createSchematicTraceCrossingSegments = ({
|
|
4412
|
+
edges: inputEdges,
|
|
4413
|
+
otherEdges
|
|
4414
|
+
}) => {
|
|
4415
|
+
const edges = [...inputEdges];
|
|
4416
|
+
for (let i = 0; i < edges.length; i++) {
|
|
4417
|
+
if (i > 2e3) {
|
|
4418
|
+
throw new Error(
|
|
4419
|
+
"Over 2000 iterations spent inside createSchematicTraceCrossingSegments, you have triggered an infinite loop, please report this!"
|
|
4420
|
+
);
|
|
4870
4421
|
}
|
|
4871
|
-
|
|
4872
|
-
|
|
4422
|
+
const edge = edges[i];
|
|
4423
|
+
const edgeOrientation = Math.abs(edge.from.x - edge.to.x) < 0.01 ? "vertical" : edge.from.y === edge.to.y ? "horizontal" : "not-orthogonal";
|
|
4424
|
+
if (edgeOrientation === "not-orthogonal") {
|
|
4425
|
+
continue;
|
|
4426
|
+
}
|
|
4427
|
+
const otherEdgesIntersections = [];
|
|
4428
|
+
for (const otherEdge of otherEdges) {
|
|
4429
|
+
const otherOrientation = otherEdge.from.x === otherEdge.to.x ? "vertical" : otherEdge.from.y === otherEdge.to.y ? "horizontal" : "not-orthogonal";
|
|
4430
|
+
if (otherOrientation === "not-orthogonal") continue;
|
|
4431
|
+
if (edgeOrientation === otherOrientation)
|
|
4432
|
+
continue;
|
|
4433
|
+
const hasIntersection = doesLineIntersectLine(
|
|
4434
|
+
[edge.from, edge.to],
|
|
4435
|
+
[otherEdge.from, otherEdge.to],
|
|
4436
|
+
{ lineThickness: 0.01 }
|
|
4437
|
+
);
|
|
4438
|
+
if (hasIntersection) {
|
|
4439
|
+
const intersectX = edgeOrientation === "vertical" ? edge.from.x : otherEdge.from.x;
|
|
4440
|
+
const intersectY = edgeOrientation === "vertical" ? otherEdge.from.y : edge.from.y;
|
|
4441
|
+
const crossingPoint2 = { x: intersectX, y: intersectY };
|
|
4442
|
+
otherEdgesIntersections.push({
|
|
4443
|
+
otherEdge,
|
|
4444
|
+
crossingPoint: crossingPoint2,
|
|
4445
|
+
distanceFromEdgeFrom: distance2(edge.from, crossingPoint2)
|
|
4446
|
+
});
|
|
4447
|
+
}
|
|
4448
|
+
}
|
|
4449
|
+
if (otherEdgesIntersections.length === 0) continue;
|
|
4450
|
+
let closestIntersection = otherEdgesIntersections[0];
|
|
4451
|
+
for (const intersection of otherEdgesIntersections) {
|
|
4452
|
+
if (intersection.distanceFromEdgeFrom < closestIntersection.distanceFromEdgeFrom) {
|
|
4453
|
+
closestIntersection = intersection;
|
|
4454
|
+
}
|
|
4455
|
+
}
|
|
4456
|
+
const crossingPoint = closestIntersection.crossingPoint;
|
|
4457
|
+
const crossingSegmentLength = 0.075;
|
|
4458
|
+
if (crossingPoint.x === edge.from.x && crossingPoint.y === edge.from.y) {
|
|
4459
|
+
continue;
|
|
4460
|
+
}
|
|
4461
|
+
const crossingUnitVec = getUnitVectorFromPointAToB(edge.from, crossingPoint);
|
|
4462
|
+
const beforeCrossing = {
|
|
4463
|
+
x: crossingPoint.x - crossingUnitVec.x * crossingSegmentLength / 2,
|
|
4464
|
+
y: crossingPoint.y - crossingUnitVec.y * crossingSegmentLength / 2
|
|
4465
|
+
};
|
|
4466
|
+
const afterCrossing = {
|
|
4467
|
+
x: crossingPoint.x + crossingUnitVec.x * crossingSegmentLength / 2,
|
|
4468
|
+
y: crossingPoint.y + crossingUnitVec.y * crossingSegmentLength / 2
|
|
4469
|
+
};
|
|
4470
|
+
const overshot = distance2(afterCrossing, edge.to) < crossingSegmentLength;
|
|
4471
|
+
const newEdges = [
|
|
4472
|
+
{ from: edge.from, to: beforeCrossing },
|
|
4473
|
+
{ from: beforeCrossing, to: afterCrossing, is_crossing: true },
|
|
4474
|
+
{ from: afterCrossing, to: edge.to }
|
|
4475
|
+
];
|
|
4476
|
+
edges.splice(i, 1, ...newEdges);
|
|
4477
|
+
i += newEdges.length - 2;
|
|
4478
|
+
if (overshot) {
|
|
4479
|
+
i++;
|
|
4480
|
+
}
|
|
4481
|
+
}
|
|
4482
|
+
return edges;
|
|
4483
|
+
};
|
|
4484
|
+
|
|
4485
|
+
// lib/components/primitive-components/Trace/trace-utils/create-schematic-trace-junctions.ts
|
|
4486
|
+
var getIntersectionPoint = (edge1, edge2) => {
|
|
4487
|
+
if (edge1.from.x === edge1.to.x && edge2.from.x === edge2.to.x) {
|
|
4488
|
+
return null;
|
|
4489
|
+
}
|
|
4490
|
+
if (edge1.from.x === edge1.to.x) {
|
|
4491
|
+
const x2 = edge1.from.x;
|
|
4492
|
+
const m22 = (edge2.to.y - edge2.from.y) / (edge2.to.x - edge2.from.x);
|
|
4493
|
+
const b22 = edge2.from.y - m22 * edge2.from.x;
|
|
4494
|
+
const y2 = m22 * x2 + b22;
|
|
4495
|
+
if (x2 >= Math.min(edge2.from.x, edge2.to.x) && x2 <= Math.max(edge2.from.x, edge2.to.x) && y2 >= Math.min(edge2.from.y, edge2.to.y) && y2 <= Math.max(edge2.from.y, edge2.to.y)) {
|
|
4496
|
+
return { x: x2, y: y2 };
|
|
4497
|
+
}
|
|
4498
|
+
return null;
|
|
4499
|
+
}
|
|
4500
|
+
if (edge2.from.x === edge2.to.x) {
|
|
4501
|
+
const x2 = edge2.from.x;
|
|
4502
|
+
const m12 = (edge1.to.y - edge1.from.y) / (edge1.to.x - edge1.from.x);
|
|
4503
|
+
const b12 = edge1.from.y - m12 * edge1.from.x;
|
|
4504
|
+
const y2 = m12 * x2 + b12;
|
|
4505
|
+
if (x2 >= Math.min(edge1.from.x, edge1.to.x) && x2 <= Math.max(edge1.from.x, edge1.to.x) && y2 >= Math.min(edge1.from.y, edge1.to.y) && y2 <= Math.max(edge1.from.y, edge1.to.y)) {
|
|
4506
|
+
return { x: x2, y: y2 };
|
|
4507
|
+
}
|
|
4508
|
+
return null;
|
|
4509
|
+
}
|
|
4510
|
+
const m1 = (edge1.to.y - edge1.from.y) / (edge1.to.x - edge1.from.x);
|
|
4511
|
+
const b1 = edge1.from.y - m1 * edge1.from.x;
|
|
4512
|
+
const m2 = (edge2.to.y - edge2.from.y) / (edge2.to.x - edge2.from.x);
|
|
4513
|
+
const b2 = edge2.from.y - m2 * edge2.from.x;
|
|
4514
|
+
if (m1 === m2) {
|
|
4515
|
+
return null;
|
|
4516
|
+
}
|
|
4517
|
+
const x = (b2 - b1) / (m1 - m2);
|
|
4518
|
+
const y = m1 * x + b1;
|
|
4519
|
+
const isWithinEdge1 = x >= Math.min(edge1.from.x, edge1.to.x) && x <= Math.max(edge1.from.x, edge1.to.x) && y >= Math.min(edge1.from.y, edge1.to.y) && y <= Math.max(edge1.from.y, edge1.to.y);
|
|
4520
|
+
const isWithinEdge2 = x >= Math.min(edge2.from.x, edge2.to.x) && x <= Math.max(edge2.from.x, edge2.to.x) && y >= Math.min(edge2.from.y, edge2.to.y) && y <= Math.max(edge2.from.y, edge2.to.y);
|
|
4521
|
+
if (isWithinEdge1 && isWithinEdge2) {
|
|
4522
|
+
return { x, y };
|
|
4523
|
+
}
|
|
4524
|
+
return null;
|
|
4525
|
+
};
|
|
4526
|
+
var createSchematicTraceJunctions = ({
|
|
4527
|
+
edges: myEdges,
|
|
4528
|
+
db,
|
|
4529
|
+
source_trace_id
|
|
4530
|
+
}) => {
|
|
4531
|
+
const otherEdges = getOtherSchematicTraces({
|
|
4532
|
+
db,
|
|
4533
|
+
source_trace_id,
|
|
4534
|
+
sameNetOnly: true
|
|
4535
|
+
}).flatMap((t) => t.edges);
|
|
4536
|
+
const junctions = /* @__PURE__ */ new Set();
|
|
4537
|
+
for (const myEdge of myEdges) {
|
|
4538
|
+
for (const otherEdge of otherEdges) {
|
|
4539
|
+
const intersection = getIntersectionPoint(myEdge, otherEdge);
|
|
4540
|
+
if (intersection) {
|
|
4541
|
+
const pointKey = `${intersection.x},${intersection.y}`;
|
|
4542
|
+
return [{ x: intersection.x, y: intersection.y }];
|
|
4543
|
+
}
|
|
4544
|
+
}
|
|
4545
|
+
}
|
|
4546
|
+
return [];
|
|
4547
|
+
};
|
|
4548
|
+
|
|
4549
|
+
// lib/components/primitive-components/Trace/trace-utils/get-obstacles-for-trace.ts
|
|
4550
|
+
import { getUnitVectorFromDirection } from "@tscircuit/math-utils";
|
|
4551
|
+
|
|
4552
|
+
// lib/utils/autorouting/getBoundsForSchematic.ts
|
|
4553
|
+
function getBoundsForSchematic(db) {
|
|
4554
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
4555
|
+
for (const elm of db) {
|
|
4556
|
+
let cx, cy, w, h;
|
|
4557
|
+
if (elm.type === "schematic_component") {
|
|
4558
|
+
cx = elm.center?.x;
|
|
4559
|
+
cy = elm.center?.y;
|
|
4560
|
+
w = elm.size?.width;
|
|
4561
|
+
h = elm.size?.height;
|
|
4562
|
+
} else if (elm.type === "schematic_box") {
|
|
4563
|
+
cx = elm.x;
|
|
4564
|
+
cy = elm.y;
|
|
4565
|
+
w = elm.width;
|
|
4566
|
+
h = elm.height;
|
|
4567
|
+
} else if (elm.type === "schematic_port") {
|
|
4568
|
+
cx = elm.center?.x;
|
|
4569
|
+
cy = elm.center?.y;
|
|
4570
|
+
w = 0.2;
|
|
4571
|
+
h = 0.2;
|
|
4572
|
+
} else if (elm.type === "schematic_text") {
|
|
4573
|
+
cx = elm.position?.x;
|
|
4574
|
+
cy = elm.position?.y;
|
|
4575
|
+
w = (elm.text?.length ?? 0) * 0.1;
|
|
4576
|
+
h = 0.2;
|
|
4577
|
+
}
|
|
4578
|
+
if (typeof cx === "number" && typeof cy === "number" && typeof w === "number" && typeof h === "number") {
|
|
4579
|
+
minX = Math.min(minX, cx - w / 2);
|
|
4580
|
+
maxX = Math.max(maxX, cx + w / 2);
|
|
4581
|
+
minY = Math.min(minY, cy - h / 2);
|
|
4582
|
+
maxY = Math.max(maxY, cy + h / 2);
|
|
4583
|
+
}
|
|
4584
|
+
}
|
|
4585
|
+
return { minX, maxX, minY, maxY };
|
|
4586
|
+
}
|
|
4587
|
+
|
|
4588
|
+
// lib/utils/autorouting/getObstaclesFromBounds.ts
|
|
4589
|
+
function getObstaclesFromBounds(bounds, opts = {}) {
|
|
4590
|
+
const { minX, maxX, minY, maxY } = bounds;
|
|
4591
|
+
const PADDING = opts.padding ?? 1;
|
|
4592
|
+
if (!isFinite(minX) || !isFinite(maxX) || !isFinite(minY) || !isFinite(maxY))
|
|
4593
|
+
return [];
|
|
4594
|
+
const left = minX - PADDING;
|
|
4595
|
+
const right = maxX + PADDING;
|
|
4596
|
+
const top = maxY + PADDING;
|
|
4597
|
+
const bottom = minY - PADDING;
|
|
4598
|
+
const thickness = 0.01;
|
|
4599
|
+
return [
|
|
4600
|
+
// Top border (horizontal)
|
|
4601
|
+
{
|
|
4602
|
+
type: "rect",
|
|
4603
|
+
layers: ["top"],
|
|
4604
|
+
center: { x: (left + right) / 2, y: top },
|
|
4605
|
+
width: right - left,
|
|
4606
|
+
height: thickness,
|
|
4607
|
+
connectedTo: []
|
|
4608
|
+
},
|
|
4609
|
+
// Bottom border (horizontal)
|
|
4610
|
+
{
|
|
4611
|
+
type: "rect",
|
|
4612
|
+
layers: ["top"],
|
|
4613
|
+
center: { x: (left + right) / 2, y: bottom },
|
|
4614
|
+
width: right - left,
|
|
4615
|
+
height: thickness,
|
|
4616
|
+
connectedTo: []
|
|
4617
|
+
},
|
|
4618
|
+
// Left border (vertical)
|
|
4619
|
+
{
|
|
4620
|
+
type: "rect",
|
|
4621
|
+
layers: ["top"],
|
|
4622
|
+
center: { x: left, y: (top + bottom) / 2 },
|
|
4623
|
+
width: thickness,
|
|
4624
|
+
height: top - bottom,
|
|
4625
|
+
connectedTo: []
|
|
4626
|
+
},
|
|
4627
|
+
// Right border (vertical)
|
|
4628
|
+
{
|
|
4629
|
+
type: "rect",
|
|
4630
|
+
layers: ["top"],
|
|
4631
|
+
center: { x: right, y: (top + bottom) / 2 },
|
|
4632
|
+
width: thickness,
|
|
4633
|
+
height: top - bottom,
|
|
4634
|
+
connectedTo: []
|
|
4635
|
+
}
|
|
4636
|
+
];
|
|
4637
|
+
}
|
|
4638
|
+
|
|
4639
|
+
// lib/components/primitive-components/Trace/trace-utils/get-obstacles-for-trace.ts
|
|
4640
|
+
var getSchematicObstaclesForTrace = (trace) => {
|
|
4641
|
+
const db = trace.root.db;
|
|
4642
|
+
const connectedPorts = trace._findConnectedPorts().ports ?? [];
|
|
4643
|
+
const connectedPortIds = new Set(
|
|
4644
|
+
connectedPorts.map((p) => p.schematic_port_id)
|
|
4645
|
+
);
|
|
4646
|
+
const obstacles = [];
|
|
4647
|
+
for (const elm of db.toArray()) {
|
|
4648
|
+
if (elm.type === "schematic_component") {
|
|
4649
|
+
const isSymbol = Boolean(elm.symbol_name);
|
|
4650
|
+
const dominateAxis = elm.size.width > elm.size.height ? "horz" : "vert";
|
|
4651
|
+
obstacles.push({
|
|
4652
|
+
type: "rect",
|
|
4653
|
+
layers: ["top"],
|
|
4654
|
+
center: elm.center,
|
|
4655
|
+
width: elm.size.width + (isSymbol && dominateAxis === "horz" ? -0.5 : 0),
|
|
4656
|
+
height: elm.size.height + (isSymbol && dominateAxis === "vert" ? -0.5 : 0),
|
|
4657
|
+
connectedTo: []
|
|
4658
|
+
});
|
|
4659
|
+
}
|
|
4660
|
+
if (elm.type === "schematic_port") {
|
|
4661
|
+
if (connectedPortIds.has(elm.schematic_port_id)) {
|
|
4662
|
+
continue;
|
|
4663
|
+
}
|
|
4664
|
+
const dirVec = elm.facing_direction ? getUnitVectorFromDirection(elm.facing_direction) : {
|
|
4665
|
+
x: 0,
|
|
4666
|
+
y: 0
|
|
4667
|
+
};
|
|
4668
|
+
obstacles.push({
|
|
4669
|
+
type: "rect",
|
|
4670
|
+
layers: ["top"],
|
|
4671
|
+
center: {
|
|
4672
|
+
x: elm.center.x - dirVec.x * 0.1,
|
|
4673
|
+
y: elm.center.y - dirVec.y * 0.1
|
|
4674
|
+
},
|
|
4675
|
+
width: 0.1 + Math.abs(dirVec.x) * 0.3,
|
|
4676
|
+
height: 0.1 + Math.abs(dirVec.y) * 0.3,
|
|
4677
|
+
connectedTo: []
|
|
4678
|
+
});
|
|
4679
|
+
}
|
|
4680
|
+
if (elm.type === "schematic_text") {
|
|
4681
|
+
obstacles.push({
|
|
4682
|
+
type: "rect",
|
|
4683
|
+
layers: ["top"],
|
|
4684
|
+
center: elm.position,
|
|
4685
|
+
width: (elm.text?.length ?? 0) * 0.1,
|
|
4686
|
+
height: 0.2,
|
|
4687
|
+
connectedTo: []
|
|
4688
|
+
});
|
|
4689
|
+
}
|
|
4690
|
+
if (elm.type === "schematic_box") {
|
|
4691
|
+
obstacles.push({
|
|
4692
|
+
type: "rect",
|
|
4693
|
+
layers: ["top"],
|
|
4694
|
+
center: { x: elm.x, y: elm.y },
|
|
4695
|
+
width: elm.width,
|
|
4696
|
+
height: elm.height,
|
|
4697
|
+
connectedTo: []
|
|
4698
|
+
});
|
|
4699
|
+
}
|
|
4700
|
+
}
|
|
4701
|
+
const bounds = getBoundsForSchematic(db.toArray());
|
|
4702
|
+
obstacles.push(...getObstaclesFromBounds(bounds, { padding: 1 }));
|
|
4703
|
+
return obstacles;
|
|
4704
|
+
};
|
|
4705
|
+
|
|
4706
|
+
// lib/components/primitive-components/Trace/trace-utils/push-edges-of-schematic-trace-to-prevent-overlap.ts
|
|
4707
|
+
import { doesLineIntersectLine as doesLineIntersectLine2 } from "@tscircuit/math-utils";
|
|
4708
|
+
var pushEdgesOfSchematicTraceToPreventOverlap = ({
|
|
4709
|
+
edges,
|
|
4710
|
+
db,
|
|
4711
|
+
source_trace_id
|
|
4712
|
+
}) => {
|
|
4713
|
+
const mySourceTrace = db.source_trace.get(source_trace_id);
|
|
4714
|
+
const otherEdges = getOtherSchematicTraces({
|
|
4715
|
+
db,
|
|
4716
|
+
source_trace_id,
|
|
4717
|
+
differentNetOnly: true
|
|
4718
|
+
}).flatMap((t) => t.edges);
|
|
4719
|
+
const edgeOrientation = (edge) => {
|
|
4720
|
+
const { from, to } = edge;
|
|
4721
|
+
return from.x === to.x ? "vertical" : "horizontal";
|
|
4722
|
+
};
|
|
4723
|
+
for (const mySegment of edges) {
|
|
4724
|
+
const mySegmentOrientation = edgeOrientation(mySegment);
|
|
4725
|
+
const findOverlappingParallelSegment = () => otherEdges.find(
|
|
4726
|
+
(otherEdge) => edgeOrientation(otherEdge) === mySegmentOrientation && doesLineIntersectLine2(
|
|
4727
|
+
[mySegment.from, mySegment.to],
|
|
4728
|
+
[otherEdge.from, otherEdge.to],
|
|
4729
|
+
{
|
|
4730
|
+
lineThickness: 0.05
|
|
4731
|
+
}
|
|
4732
|
+
)
|
|
4733
|
+
);
|
|
4734
|
+
let overlappingParallelSegmentFromOtherTrace = findOverlappingParallelSegment();
|
|
4735
|
+
while (overlappingParallelSegmentFromOtherTrace) {
|
|
4736
|
+
if (mySegmentOrientation === "horizontal") {
|
|
4737
|
+
mySegment.from.y += 0.1;
|
|
4738
|
+
mySegment.to.y += 0.1;
|
|
4739
|
+
} else {
|
|
4740
|
+
mySegment.from.x += 0.1;
|
|
4741
|
+
mySegment.to.x += 0.1;
|
|
4742
|
+
}
|
|
4743
|
+
overlappingParallelSegmentFromOtherTrace = findOverlappingParallelSegment();
|
|
4744
|
+
}
|
|
4745
|
+
}
|
|
4746
|
+
};
|
|
4747
|
+
|
|
4748
|
+
// lib/components/primitive-components/Trace/Trace_doInitialSchematicTraceRender.ts
|
|
4749
|
+
var Trace_doInitialSchematicTraceRender = (trace) => {
|
|
4750
|
+
if (trace.root?.schematicDisabled) return;
|
|
4751
|
+
const { db } = trace.root;
|
|
4752
|
+
const { _parsedProps: props, parent } = trace;
|
|
4753
|
+
if (!parent) throw new Error("Trace has no parent");
|
|
4754
|
+
const { allPortsFound, portsWithSelectors: connectedPorts } = trace._findConnectedPorts();
|
|
4755
|
+
const { netsWithSelectors } = trace._findConnectedNets();
|
|
4756
|
+
if (!allPortsFound) return;
|
|
4757
|
+
const portIds = connectedPorts.map((p) => p.port.schematic_port_id).sort();
|
|
4758
|
+
const portPairKey = portIds.join(",");
|
|
4759
|
+
const board = trace.root?._getBoard();
|
|
4760
|
+
if (board?._connectedSchematicPortPairs) {
|
|
4761
|
+
if (board._connectedSchematicPortPairs.has(portPairKey)) {
|
|
4762
|
+
return;
|
|
4763
|
+
}
|
|
4764
|
+
}
|
|
4765
|
+
const connection = {
|
|
4766
|
+
name: trace.source_trace_id,
|
|
4767
|
+
pointsToConnect: []
|
|
4768
|
+
};
|
|
4769
|
+
const obstacles = getSchematicObstaclesForTrace(trace);
|
|
4770
|
+
const portsWithPosition = connectedPorts.map(({ port }) => ({
|
|
4771
|
+
port,
|
|
4772
|
+
position: port._getGlobalSchematicPositionAfterLayout(),
|
|
4773
|
+
schematic_port_id: port.schematic_port_id ?? void 0,
|
|
4774
|
+
facingDirection: port.facingDirection
|
|
4775
|
+
}));
|
|
4776
|
+
const isPortAndNetConnection = portsWithPosition.length === 1 && netsWithSelectors.length === 1;
|
|
4777
|
+
if (isPortAndNetConnection) {
|
|
4778
|
+
const net = netsWithSelectors[0].net;
|
|
4779
|
+
const { port, position: anchorPos } = portsWithPosition[0];
|
|
4780
|
+
let connectedNetLabel = trace.getSubcircuit().selectAll("netlabel").find((nl) => {
|
|
4781
|
+
const conn = nl._parsedProps.connection ?? nl._parsedProps.connectsTo;
|
|
4782
|
+
if (!conn) return false;
|
|
4783
|
+
if (Array.isArray(conn)) {
|
|
4784
|
+
return conn.some((selector) => {
|
|
4785
|
+
const targetPort2 = trace.getSubcircuit().selectOne(selector, {
|
|
4786
|
+
port: true
|
|
4787
|
+
});
|
|
4788
|
+
return targetPort2 === port;
|
|
4789
|
+
});
|
|
4790
|
+
}
|
|
4791
|
+
const targetPort = trace.getSubcircuit().selectOne(conn, {
|
|
4792
|
+
port: true
|
|
4793
|
+
});
|
|
4794
|
+
return targetPort === port;
|
|
4795
|
+
});
|
|
4796
|
+
if (!connectedNetLabel) {
|
|
4797
|
+
const dbNetLabel = db.schematic_net_label.getWhere({
|
|
4798
|
+
source_trace_id: trace.source_trace_id
|
|
4799
|
+
});
|
|
4800
|
+
if (dbNetLabel) {
|
|
4801
|
+
connectedNetLabel = dbNetLabel;
|
|
4802
|
+
}
|
|
4803
|
+
}
|
|
4804
|
+
if (connectedNetLabel) {
|
|
4805
|
+
const labelPos = "_getGlobalSchematicPositionBeforeLayout" in connectedNetLabel ? connectedNetLabel._getGlobalSchematicPositionBeforeLayout() : connectedNetLabel.anchor_position;
|
|
4806
|
+
const edges2 = [];
|
|
4807
|
+
if (anchorPos.x === labelPos.x || anchorPos.y === labelPos.y) {
|
|
4808
|
+
edges2.push({ from: anchorPos, to: labelPos });
|
|
4809
|
+
} else {
|
|
4810
|
+
edges2.push({ from: anchorPos, to: { x: labelPos.x, y: anchorPos.y } });
|
|
4811
|
+
edges2.push({ from: { x: labelPos.x, y: anchorPos.y }, to: labelPos });
|
|
4812
|
+
}
|
|
4813
|
+
const dbTrace2 = db.schematic_trace.insert({
|
|
4814
|
+
source_trace_id: trace.source_trace_id,
|
|
4815
|
+
edges: edges2,
|
|
4816
|
+
junctions: []
|
|
4817
|
+
});
|
|
4818
|
+
trace.schematic_trace_id = dbTrace2.schematic_trace_id;
|
|
4819
|
+
return;
|
|
4820
|
+
}
|
|
4821
|
+
if (trace.props.schDisplayLabel) {
|
|
4822
|
+
const side2 = getEnteringEdgeFromDirection(port.facingDirection) ?? "bottom";
|
|
4823
|
+
db.schematic_net_label.insert({
|
|
4824
|
+
text: trace.props.schDisplayLabel,
|
|
4825
|
+
source_net_id: net.source_net_id,
|
|
4826
|
+
anchor_position: anchorPos,
|
|
4827
|
+
center: computeSchematicNetLabelCenter({
|
|
4828
|
+
anchor_position: anchorPos,
|
|
4829
|
+
anchor_side: side2,
|
|
4830
|
+
text: trace.props.schDisplayLabel
|
|
4831
|
+
}),
|
|
4832
|
+
anchor_side: side2
|
|
4833
|
+
});
|
|
4834
|
+
return;
|
|
4835
|
+
}
|
|
4836
|
+
const side = getEnteringEdgeFromDirection(port.facingDirection) ?? "bottom";
|
|
4837
|
+
const netLabel = db.schematic_net_label.insert({
|
|
4838
|
+
text: net._parsedProps.name,
|
|
4839
|
+
source_net_id: net.source_net_id,
|
|
4840
|
+
anchor_position: anchorPos,
|
|
4841
|
+
center: computeSchematicNetLabelCenter({
|
|
4842
|
+
anchor_position: anchorPos,
|
|
4843
|
+
anchor_side: side,
|
|
4844
|
+
text: net._parsedProps.name
|
|
4845
|
+
}),
|
|
4846
|
+
anchor_side: side
|
|
4847
|
+
});
|
|
4848
|
+
return;
|
|
4849
|
+
}
|
|
4850
|
+
if (trace.props.schDisplayLabel) {
|
|
4851
|
+
if ("from" in trace.props && "to" in trace.props || "path" in trace.props) {
|
|
4852
|
+
trace._doInitialSchematicTraceRenderWithDisplayLabel();
|
|
4853
|
+
return;
|
|
4854
|
+
}
|
|
4855
|
+
}
|
|
4856
|
+
if (portsWithPosition.length < 2) {
|
|
4857
|
+
return;
|
|
4858
|
+
}
|
|
4859
|
+
connection.pointsToConnect = portsWithPosition.map(({ position }) => ({
|
|
4860
|
+
...position,
|
|
4861
|
+
layer: "top"
|
|
4862
|
+
}));
|
|
4863
|
+
const bounds = computeObstacleBounds(obstacles);
|
|
4864
|
+
const BOUNDS_MARGIN = 2;
|
|
4865
|
+
const simpleRouteJsonInput = {
|
|
4866
|
+
minTraceWidth: 0.1,
|
|
4867
|
+
obstacles,
|
|
4868
|
+
connections: [connection],
|
|
4869
|
+
bounds: {
|
|
4870
|
+
minX: bounds.minX - BOUNDS_MARGIN,
|
|
4871
|
+
maxX: bounds.maxX + BOUNDS_MARGIN,
|
|
4872
|
+
minY: bounds.minY - BOUNDS_MARGIN,
|
|
4873
|
+
maxY: bounds.maxY + BOUNDS_MARGIN
|
|
4874
|
+
},
|
|
4875
|
+
layerCount: 1
|
|
4876
|
+
};
|
|
4877
|
+
let Autorouter = MultilayerIjump;
|
|
4878
|
+
let skipOtherTraceInteraction = false;
|
|
4879
|
+
if (trace.getSubcircuit().props._schDirectLineRoutingEnabled) {
|
|
4880
|
+
Autorouter = DirectLineRouter;
|
|
4881
|
+
skipOtherTraceInteraction = true;
|
|
4882
|
+
}
|
|
4883
|
+
const autorouter = new Autorouter({
|
|
4884
|
+
input: simpleRouteJsonInput,
|
|
4885
|
+
MAX_ITERATIONS: 100,
|
|
4886
|
+
OBSTACLE_MARGIN: 0.1,
|
|
4887
|
+
isRemovePathLoopsEnabled: true,
|
|
4888
|
+
isShortenPathWithShortcutsEnabled: true,
|
|
4889
|
+
marginsWithCosts: [
|
|
4890
|
+
{
|
|
4891
|
+
margin: 1,
|
|
4892
|
+
enterCost: 0,
|
|
4893
|
+
travelCostFactor: 1
|
|
4894
|
+
},
|
|
4895
|
+
{
|
|
4896
|
+
margin: 0.3,
|
|
4897
|
+
enterCost: 0,
|
|
4898
|
+
travelCostFactor: 1
|
|
4899
|
+
},
|
|
4900
|
+
{
|
|
4901
|
+
margin: 0.2,
|
|
4902
|
+
enterCost: 0,
|
|
4903
|
+
travelCostFactor: 2
|
|
4904
|
+
},
|
|
4905
|
+
{
|
|
4906
|
+
margin: 0.1,
|
|
4907
|
+
enterCost: 0,
|
|
4908
|
+
travelCostFactor: 3
|
|
4909
|
+
}
|
|
4910
|
+
]
|
|
4911
|
+
});
|
|
4912
|
+
let results = autorouter.solveAndMapToTraces();
|
|
4913
|
+
if (results.length === 0) {
|
|
4914
|
+
if (trace._isSymbolToChipConnection() || trace._isSymbolToSymbolConnection() || trace._isChipToChipConnection()) {
|
|
4915
|
+
trace._doInitialSchematicTraceRenderWithDisplayLabel();
|
|
4916
|
+
return;
|
|
4917
|
+
}
|
|
4918
|
+
const directLineRouter = new DirectLineRouter({
|
|
4919
|
+
input: simpleRouteJsonInput
|
|
4920
|
+
});
|
|
4921
|
+
results = directLineRouter.solveAndMapToTraces();
|
|
4922
|
+
skipOtherTraceInteraction = true;
|
|
4923
|
+
}
|
|
4924
|
+
const [{ route }] = results;
|
|
4925
|
+
let edges = [];
|
|
4926
|
+
for (let i = 0; i < route.length - 1; i++) {
|
|
4927
|
+
edges.push({
|
|
4928
|
+
from: route[i],
|
|
4929
|
+
to: route[i + 1]
|
|
4930
|
+
});
|
|
4931
|
+
}
|
|
4932
|
+
const source_trace_id = trace.source_trace_id;
|
|
4933
|
+
let junctions = [];
|
|
4934
|
+
if (!skipOtherTraceInteraction) {
|
|
4935
|
+
pushEdgesOfSchematicTraceToPreventOverlap({ edges, db, source_trace_id });
|
|
4936
|
+
const otherEdges = getOtherSchematicTraces({
|
|
4937
|
+
db,
|
|
4938
|
+
source_trace_id,
|
|
4939
|
+
differentNetOnly: true
|
|
4940
|
+
}).flatMap((t) => t.edges);
|
|
4941
|
+
edges = createSchematicTraceCrossingSegments({ edges, otherEdges });
|
|
4942
|
+
junctions = createSchematicTraceJunctions({
|
|
4943
|
+
edges,
|
|
4944
|
+
db,
|
|
4945
|
+
source_trace_id: trace.source_trace_id
|
|
4946
|
+
});
|
|
4947
|
+
}
|
|
4948
|
+
const lastEdge = edges[edges.length - 1];
|
|
4949
|
+
const lastEdgePort = portsWithPosition[portsWithPosition.length - 1];
|
|
4950
|
+
const lastDominantDirection = getDominantDirection(lastEdge);
|
|
4951
|
+
edges.push(...getStubEdges({ lastEdge, lastEdgePort, lastDominantDirection }));
|
|
4952
|
+
const firstEdge = edges[0];
|
|
4953
|
+
const firstEdgePort = portsWithPosition[0];
|
|
4954
|
+
const firstDominantDirection = getDominantDirection(firstEdge);
|
|
4955
|
+
edges.unshift(
|
|
4956
|
+
...getStubEdges({
|
|
4957
|
+
firstEdge,
|
|
4958
|
+
firstEdgePort,
|
|
4959
|
+
firstDominantDirection
|
|
4960
|
+
})
|
|
4961
|
+
);
|
|
4962
|
+
if (!trace.source_trace_id) {
|
|
4963
|
+
throw new Error("Missing source_trace_id for schematic trace insertion.");
|
|
4964
|
+
}
|
|
4965
|
+
if (trace.getSubcircuit()._parsedProps.schTraceAutoLabelEnabled && countComplexElements(junctions, edges) >= 5 && (trace._isSymbolToChipConnection() || trace._isSymbolToSymbolConnection() || trace._isChipToChipConnection())) {
|
|
4966
|
+
trace._doInitialSchematicTraceRenderWithDisplayLabel();
|
|
4967
|
+
return;
|
|
4968
|
+
}
|
|
4969
|
+
const dbTrace = db.schematic_trace.insert({
|
|
4970
|
+
source_trace_id: trace.source_trace_id,
|
|
4971
|
+
edges,
|
|
4972
|
+
junctions
|
|
4973
|
+
});
|
|
4974
|
+
trace.schematic_trace_id = dbTrace.schematic_trace_id;
|
|
4975
|
+
if (board?._connectedSchematicPortPairs)
|
|
4976
|
+
board._connectedSchematicPortPairs.add(portPairKey);
|
|
4977
|
+
};
|
|
4978
|
+
|
|
4979
|
+
// lib/components/primitive-components/Trace/Trace_doInitialPcbTraceRender.ts
|
|
4980
|
+
import { MultilayerIjump as MultilayerIjump2 } from "@tscircuit/infgrid-ijump-astar";
|
|
4981
|
+
import "circuit-json";
|
|
4982
|
+
import { getFullConnectivityMapFromCircuitJson } from "circuit-json-to-connectivity-map";
|
|
4983
|
+
|
|
4984
|
+
// lib/components/primitive-components/Trace/trace-utils/compute-trace-length.ts
|
|
4985
|
+
function getTraceLength(route) {
|
|
4986
|
+
let totalLength = 0;
|
|
4987
|
+
for (let i = 0; i < route.length; i++) {
|
|
4988
|
+
const point = route[i];
|
|
4989
|
+
if (point.route_type === "wire") {
|
|
4990
|
+
const nextPoint = route[i + 1];
|
|
4991
|
+
if (nextPoint) {
|
|
4992
|
+
const dx = nextPoint.x - point.x;
|
|
4993
|
+
const dy = nextPoint.y - point.y;
|
|
4994
|
+
totalLength += Math.sqrt(dx * dx + dy * dy);
|
|
4995
|
+
}
|
|
4996
|
+
} else if (point.route_type === "via") {
|
|
4997
|
+
totalLength += 1.6;
|
|
4998
|
+
}
|
|
4999
|
+
}
|
|
5000
|
+
return totalLength;
|
|
5001
|
+
}
|
|
5002
|
+
|
|
5003
|
+
// lib/components/primitive-components/Trace/Trace_doInitialPcbTraceRender.ts
|
|
5004
|
+
var portToObjective = (port) => {
|
|
5005
|
+
const portPosition = port._getGlobalPcbPositionAfterLayout();
|
|
5006
|
+
return {
|
|
5007
|
+
...portPosition,
|
|
5008
|
+
layers: port.getAvailablePcbLayers()
|
|
5009
|
+
};
|
|
5010
|
+
};
|
|
5011
|
+
var SHOULD_USE_SINGLE_LAYER_ROUTING = false;
|
|
5012
|
+
function Trace_doInitialPcbTraceRender(trace) {
|
|
5013
|
+
if (trace.root?.pcbDisabled) return;
|
|
5014
|
+
const { db } = trace.root;
|
|
5015
|
+
const { _parsedProps: props, parent } = trace;
|
|
5016
|
+
const subcircuit = trace.getSubcircuit();
|
|
5017
|
+
if (!parent) throw new Error("Trace has no parent");
|
|
5018
|
+
if (subcircuit._parsedProps.routingDisabled) {
|
|
5019
|
+
return;
|
|
5020
|
+
}
|
|
5021
|
+
const cachedRoute = subcircuit._parsedProps.pcbRouteCache?.pcbTraces;
|
|
5022
|
+
if (cachedRoute) {
|
|
5023
|
+
const pcb_trace2 = db.pcb_trace.insert({
|
|
5024
|
+
route: cachedRoute.flatMap((trace2) => trace2.route),
|
|
5025
|
+
source_trace_id: trace.source_trace_id,
|
|
5026
|
+
subcircuit_id: subcircuit?.subcircuit_id ?? void 0,
|
|
5027
|
+
pcb_group_id: trace.getGroup()?.pcb_group_id ?? void 0
|
|
5028
|
+
});
|
|
5029
|
+
trace.pcb_trace_id = pcb_trace2.pcb_trace_id;
|
|
5030
|
+
return;
|
|
5031
|
+
}
|
|
5032
|
+
if (!subcircuit._shouldUseTraceByTraceRouting()) {
|
|
5033
|
+
return;
|
|
5034
|
+
}
|
|
5035
|
+
const { allPortsFound, ports } = trace._findConnectedPorts();
|
|
5036
|
+
const portsConnectedOnPcbViaNet = [];
|
|
5037
|
+
if (!allPortsFound) return;
|
|
5038
|
+
const portsWithoutMatchedPcbPrimitive = [];
|
|
5039
|
+
for (const port of ports) {
|
|
5040
|
+
if (!port._hasMatchedPcbPrimitive()) {
|
|
5041
|
+
portsWithoutMatchedPcbPrimitive.push(port);
|
|
5042
|
+
}
|
|
5043
|
+
}
|
|
5044
|
+
if (portsWithoutMatchedPcbPrimitive.length > 0) {
|
|
5045
|
+
db.pcb_trace_error.insert({
|
|
5046
|
+
error_type: "pcb_trace_error",
|
|
5047
|
+
source_trace_id: trace.source_trace_id,
|
|
5048
|
+
message: `Some ports did not have a matching PCB primitive (e.g. a pad or plated hole), this can happen if a footprint is missing. As a result, ${trace} wasn't routed. Missing ports: ${portsWithoutMatchedPcbPrimitive.map((p) => p.getString()).join(", ")}`,
|
|
5049
|
+
pcb_trace_id: trace.pcb_trace_id,
|
|
5050
|
+
pcb_component_ids: [],
|
|
5051
|
+
pcb_port_ids: portsWithoutMatchedPcbPrimitive.map((p) => p.pcb_port_id).filter(Boolean)
|
|
5052
|
+
});
|
|
5053
|
+
return;
|
|
5054
|
+
}
|
|
5055
|
+
const nets = trace._findConnectedNets().netsWithSelectors;
|
|
5056
|
+
if (ports.length === 0 && nets.length === 2) {
|
|
5057
|
+
trace.renderError(
|
|
5058
|
+
`Trace connects two nets, we haven't implemented a way to route this yet`
|
|
5059
|
+
);
|
|
5060
|
+
return;
|
|
5061
|
+
} else if (ports.length === 1 && nets.length === 1) {
|
|
5062
|
+
const port = ports[0];
|
|
5063
|
+
const portsInNet = nets[0].net.getAllConnectedPorts();
|
|
5064
|
+
const otherPortsInNet = portsInNet.filter((p) => p !== port);
|
|
5065
|
+
if (otherPortsInNet.length === 0) {
|
|
5066
|
+
console.log(
|
|
5067
|
+
"Nothing to connect this port to, the net is empty. TODO should emit a warning!"
|
|
5068
|
+
);
|
|
5069
|
+
return;
|
|
5070
|
+
}
|
|
5071
|
+
const closestPortInNet = getClosest(port, otherPortsInNet);
|
|
5072
|
+
portsConnectedOnPcbViaNet.push(closestPortInNet);
|
|
5073
|
+
ports.push(closestPortInNet);
|
|
5074
|
+
} else if (ports.length > 1 && nets.length >= 1) {
|
|
5075
|
+
trace.renderError(
|
|
5076
|
+
`Trace has more than one port and one or more nets, we don't currently support this type of complex trace routing`
|
|
5077
|
+
);
|
|
5078
|
+
return;
|
|
5079
|
+
}
|
|
5080
|
+
const hints = ports.flatMap(
|
|
5081
|
+
(port) => port.matchedComponents.filter((c) => c.componentName === "TraceHint")
|
|
5082
|
+
);
|
|
5083
|
+
const pcbRouteHints = (trace._parsedProps.pcbRouteHints ?? []).concat(
|
|
5084
|
+
hints.flatMap((h) => h.getPcbRouteHints())
|
|
5085
|
+
);
|
|
5086
|
+
if (ports.length > 2) {
|
|
5087
|
+
trace.renderError(
|
|
5088
|
+
`Trace has more than two ports (${ports.map((p) => p.getString()).join(
|
|
5089
|
+
", "
|
|
5090
|
+
)}), routing between more than two ports for a single trace is not implemented`
|
|
5091
|
+
);
|
|
5092
|
+
return;
|
|
5093
|
+
}
|
|
5094
|
+
const alreadyRoutedTraces = trace.getSubcircuit().selectAll("trace").filter(
|
|
5095
|
+
(trace2) => trace2.renderPhaseStates.PcbTraceRender.initialized
|
|
5096
|
+
);
|
|
5097
|
+
const isAlreadyRouted = alreadyRoutedTraces.some(
|
|
5098
|
+
(trace2) => trace2._portsRoutedOnPcb.length === ports.length && trace2._portsRoutedOnPcb.every(
|
|
5099
|
+
(portRoutedByOtherTrace) => ports.includes(portRoutedByOtherTrace)
|
|
5100
|
+
)
|
|
5101
|
+
);
|
|
5102
|
+
if (isAlreadyRouted) {
|
|
5103
|
+
return;
|
|
5104
|
+
}
|
|
5105
|
+
let orderedRouteObjectives = [];
|
|
5106
|
+
if (pcbRouteHints.length === 0) {
|
|
5107
|
+
orderedRouteObjectives = [
|
|
5108
|
+
portToObjective(ports[0]),
|
|
5109
|
+
portToObjective(ports[1])
|
|
5110
|
+
];
|
|
5111
|
+
} else {
|
|
5112
|
+
orderedRouteObjectives = [
|
|
5113
|
+
portToObjective(ports[0]),
|
|
5114
|
+
...pcbRouteHints,
|
|
5115
|
+
portToObjective(ports[1])
|
|
5116
|
+
];
|
|
5117
|
+
}
|
|
5118
|
+
const candidateLayerCombinations = findPossibleTraceLayerCombinations(
|
|
5119
|
+
orderedRouteObjectives
|
|
5120
|
+
);
|
|
5121
|
+
if (SHOULD_USE_SINGLE_LAYER_ROUTING && candidateLayerCombinations.length === 0) {
|
|
5122
|
+
trace.renderError(
|
|
5123
|
+
`Could not find a common layer (using hints) for trace ${trace.getString()}`
|
|
5124
|
+
);
|
|
5125
|
+
return;
|
|
5126
|
+
}
|
|
5127
|
+
const connMap = getFullConnectivityMapFromCircuitJson(
|
|
5128
|
+
trace.root.db.toArray()
|
|
5129
|
+
);
|
|
5130
|
+
const [obstacles, errGettingObstacles] = tryNow(
|
|
5131
|
+
() => getObstaclesFromCircuitJson(trace.root.db.toArray())
|
|
5132
|
+
// Remove as any when autorouting-dataset gets updated
|
|
5133
|
+
);
|
|
5134
|
+
if (errGettingObstacles) {
|
|
5135
|
+
trace.renderError({
|
|
5136
|
+
type: "pcb_trace_error",
|
|
5137
|
+
error_type: "pcb_trace_error",
|
|
5138
|
+
pcb_trace_error_id: trace.pcb_trace_id,
|
|
5139
|
+
message: `Error getting obstacles for autorouting: ${errGettingObstacles.message}`,
|
|
5140
|
+
source_trace_id: trace.source_trace_id,
|
|
5141
|
+
center: { x: 0, y: 0 },
|
|
5142
|
+
pcb_port_ids: ports.map((p) => p.pcb_port_id),
|
|
5143
|
+
pcb_trace_id: trace.pcb_trace_id,
|
|
5144
|
+
pcb_component_ids: []
|
|
5145
|
+
});
|
|
5146
|
+
return;
|
|
5147
|
+
}
|
|
5148
|
+
for (const obstacle of obstacles) {
|
|
5149
|
+
const connectedTo = obstacle.connectedTo;
|
|
5150
|
+
if (connectedTo.length > 0) {
|
|
5151
|
+
const netId = connMap.getNetConnectedToId(obstacle.connectedTo[0]);
|
|
5152
|
+
if (netId) {
|
|
5153
|
+
obstacle.connectedTo.push(netId);
|
|
5154
|
+
}
|
|
5155
|
+
}
|
|
5156
|
+
}
|
|
5157
|
+
let orderedRoutePoints = [];
|
|
5158
|
+
if (candidateLayerCombinations.length === 0) {
|
|
5159
|
+
orderedRoutePoints = orderedRouteObjectives;
|
|
5160
|
+
} else {
|
|
5161
|
+
const candidateLayerSelections = candidateLayerCombinations[0].layer_path;
|
|
5162
|
+
orderedRoutePoints = orderedRouteObjectives.map((t, idx) => {
|
|
5163
|
+
if (t.via) {
|
|
5164
|
+
return {
|
|
5165
|
+
...t,
|
|
5166
|
+
via_to_layer: candidateLayerSelections[idx]
|
|
5167
|
+
};
|
|
5168
|
+
}
|
|
5169
|
+
return { ...t, layers: [candidateLayerSelections[idx]] };
|
|
5170
|
+
});
|
|
5171
|
+
}
|
|
5172
|
+
;
|
|
5173
|
+
orderedRoutePoints[0].pcb_port_id = ports[0].pcb_port_id;
|
|
5174
|
+
orderedRoutePoints[orderedRoutePoints.length - 1].pcb_port_id = ports[1].pcb_port_id;
|
|
5175
|
+
const routes = [];
|
|
5176
|
+
for (const [a, b] of pairs(orderedRoutePoints)) {
|
|
5177
|
+
const dominantLayer = "via_to_layer" in a ? a.via_to_layer : null;
|
|
5178
|
+
const BOUNDS_MARGIN = 2;
|
|
5179
|
+
const aLayer = "layers" in a && a.layers.length === 1 ? a.layers[0] : dominantLayer ?? "top";
|
|
5180
|
+
const bLayer = "layers" in b && b.layers.length === 1 ? b.layers[0] : dominantLayer ?? "top";
|
|
5181
|
+
const pcbPortA = "pcb_port_id" in a ? a.pcb_port_id : null;
|
|
5182
|
+
const pcbPortB = "pcb_port_id" in b ? b.pcb_port_id : null;
|
|
5183
|
+
const minTraceWidth = trace.getSubcircuit()._parsedProps.minTraceWidth ?? 0.16;
|
|
5184
|
+
const ijump = new MultilayerIjump2({
|
|
5185
|
+
OBSTACLE_MARGIN: minTraceWidth * 2,
|
|
5186
|
+
isRemovePathLoopsEnabled: true,
|
|
5187
|
+
optimizeWithGoalBoxes: Boolean(pcbPortA && pcbPortB),
|
|
5188
|
+
connMap,
|
|
5189
|
+
input: {
|
|
5190
|
+
obstacles,
|
|
5191
|
+
minTraceWidth,
|
|
5192
|
+
connections: [
|
|
5193
|
+
{
|
|
5194
|
+
name: trace.source_trace_id,
|
|
5195
|
+
pointsToConnect: [
|
|
5196
|
+
{ ...a, layer: aLayer, pcb_port_id: pcbPortA },
|
|
5197
|
+
{ ...b, layer: bLayer, pcb_port_id: pcbPortB }
|
|
5198
|
+
]
|
|
5199
|
+
}
|
|
5200
|
+
],
|
|
5201
|
+
layerCount: 2,
|
|
5202
|
+
bounds: {
|
|
5203
|
+
minX: Math.min(a.x, b.x) - BOUNDS_MARGIN,
|
|
5204
|
+
maxX: Math.max(a.x, b.x) + BOUNDS_MARGIN,
|
|
5205
|
+
minY: Math.min(a.y, b.y) - BOUNDS_MARGIN,
|
|
5206
|
+
maxY: Math.max(a.y, b.y) + BOUNDS_MARGIN
|
|
5207
|
+
}
|
|
5208
|
+
}
|
|
5209
|
+
});
|
|
5210
|
+
let traces = null;
|
|
5211
|
+
try {
|
|
5212
|
+
traces = ijump.solveAndMapToTraces();
|
|
5213
|
+
} catch (e) {
|
|
5214
|
+
trace.renderError({
|
|
5215
|
+
type: "pcb_trace_error",
|
|
5216
|
+
pcb_trace_error_id: trace.source_trace_id,
|
|
5217
|
+
error_type: "pcb_trace_error",
|
|
5218
|
+
message: `error solving route: ${e.message}`,
|
|
5219
|
+
source_trace_id: trace.pcb_trace_id,
|
|
5220
|
+
center: { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 },
|
|
5221
|
+
pcb_port_ids: ports.map((p) => p.pcb_port_id),
|
|
5222
|
+
pcb_trace_id: trace.pcb_trace_id,
|
|
5223
|
+
pcb_component_ids: ports.map((p) => p.pcb_component_id)
|
|
5224
|
+
});
|
|
5225
|
+
}
|
|
5226
|
+
if (!traces) return;
|
|
5227
|
+
if (traces.length === 0) {
|
|
5228
|
+
trace.renderError({
|
|
5229
|
+
type: "pcb_trace_error",
|
|
5230
|
+
error_type: "pcb_trace_error",
|
|
5231
|
+
pcb_trace_error_id: trace.pcb_trace_id,
|
|
5232
|
+
message: `Could not find a route for ${trace}`,
|
|
5233
|
+
source_trace_id: trace.source_trace_id,
|
|
5234
|
+
center: { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 },
|
|
5235
|
+
pcb_port_ids: ports.map((p) => p.pcb_port_id),
|
|
5236
|
+
pcb_trace_id: trace.pcb_trace_id,
|
|
5237
|
+
pcb_component_ids: ports.map((p) => p.pcb_component_id)
|
|
5238
|
+
});
|
|
5239
|
+
return;
|
|
5240
|
+
}
|
|
5241
|
+
const [autoroutedTrace] = traces;
|
|
5242
|
+
if (dominantLayer) {
|
|
5243
|
+
autoroutedTrace.route = autoroutedTrace.route.map((p) => {
|
|
5244
|
+
if (p.route_type === "wire" && !p.layer) {
|
|
5245
|
+
p.layer = dominantLayer;
|
|
5246
|
+
}
|
|
5247
|
+
return p;
|
|
5248
|
+
});
|
|
5249
|
+
}
|
|
5250
|
+
if (pcbPortA && autoroutedTrace.route[0].route_type === "wire") {
|
|
5251
|
+
autoroutedTrace.route[0].start_pcb_port_id = pcbPortA;
|
|
5252
|
+
}
|
|
5253
|
+
const lastRoutePoint = autoroutedTrace.route[autoroutedTrace.route.length - 1];
|
|
5254
|
+
if (pcbPortB && lastRoutePoint.route_type === "wire") {
|
|
5255
|
+
lastRoutePoint.end_pcb_port_id = pcbPortB;
|
|
5256
|
+
}
|
|
5257
|
+
routes.push(autoroutedTrace.route);
|
|
5258
|
+
}
|
|
5259
|
+
const mergedRoute = mergeRoutes(routes);
|
|
5260
|
+
const traceLength = getTraceLength(mergedRoute);
|
|
5261
|
+
const pcb_trace = db.pcb_trace.insert({
|
|
5262
|
+
route: mergedRoute,
|
|
5263
|
+
source_trace_id: trace.source_trace_id,
|
|
5264
|
+
subcircuit_id: trace.getSubcircuit()?.subcircuit_id,
|
|
5265
|
+
trace_length: traceLength
|
|
5266
|
+
});
|
|
5267
|
+
trace._portsRoutedOnPcb = ports;
|
|
5268
|
+
trace.pcb_trace_id = pcb_trace.pcb_trace_id;
|
|
5269
|
+
for (const point of mergedRoute) {
|
|
5270
|
+
if (point.route_type === "via") {
|
|
5271
|
+
db.pcb_via.insert({
|
|
5272
|
+
pcb_trace_id: pcb_trace.pcb_trace_id,
|
|
5273
|
+
x: point.x,
|
|
5274
|
+
y: point.y,
|
|
5275
|
+
hole_diameter: 0.3,
|
|
5276
|
+
outer_diameter: 0.6,
|
|
5277
|
+
layers: [point.from_layer, point.to_layer],
|
|
5278
|
+
from_layer: point.from_layer,
|
|
5279
|
+
to_layer: point.to_layer
|
|
5280
|
+
});
|
|
5281
|
+
}
|
|
5282
|
+
}
|
|
5283
|
+
trace._insertErrorIfTraceIsOutsideBoard(mergedRoute, ports);
|
|
5284
|
+
}
|
|
5285
|
+
|
|
5286
|
+
// lib/components/primitive-components/Trace/Trace__doInitialSchematicTraceRenderWithDisplayLabel.ts
|
|
5287
|
+
function Trace__doInitialSchematicTraceRenderWithDisplayLabel(trace) {
|
|
5288
|
+
if (trace.root?.schematicDisabled) return;
|
|
5289
|
+
const { db } = trace.root;
|
|
5290
|
+
const { _parsedProps: props, parent } = trace;
|
|
5291
|
+
if (!parent) throw new Error("Trace has no parent");
|
|
5292
|
+
const { allPortsFound, portsWithSelectors: connectedPorts } = trace._findConnectedPorts();
|
|
5293
|
+
if (!allPortsFound) return;
|
|
5294
|
+
const portsWithPosition = connectedPorts.map(({ port }) => ({
|
|
5295
|
+
port,
|
|
5296
|
+
position: port._getGlobalSchematicPositionAfterLayout(),
|
|
5297
|
+
schematic_port_id: port.schematic_port_id,
|
|
5298
|
+
facingDirection: port.facingDirection
|
|
5299
|
+
}));
|
|
5300
|
+
if (portsWithPosition.length < 2) {
|
|
5301
|
+
throw new Error("Expected at least two ports in portsWithPosition.");
|
|
5302
|
+
}
|
|
5303
|
+
let fromPortName;
|
|
5304
|
+
let toPortName;
|
|
5305
|
+
const fromAnchorPos = portsWithPosition[0].position;
|
|
5306
|
+
const fromPort = portsWithPosition[0].port;
|
|
5307
|
+
if ("path" in trace.props) {
|
|
5308
|
+
if (trace.props.path.length !== 2) {
|
|
5309
|
+
throw new Error("Invalid 'path': Must contain exactly two elements.");
|
|
5310
|
+
}
|
|
5311
|
+
;
|
|
5312
|
+
[fromPortName, toPortName] = trace.props.path;
|
|
5313
|
+
} else {
|
|
5314
|
+
if (!("from" in trace.props && "to" in trace.props)) {
|
|
5315
|
+
throw new Error("Missing 'from' or 'to' properties in props.");
|
|
5316
|
+
}
|
|
5317
|
+
fromPortName = trace.props.from;
|
|
5318
|
+
toPortName = trace.props.to;
|
|
5319
|
+
}
|
|
5320
|
+
if (!fromPort.source_port_id) {
|
|
5321
|
+
throw new Error(
|
|
5322
|
+
`Missing source_port_id for the 'from' port (${fromPortName}).`
|
|
5323
|
+
);
|
|
5324
|
+
}
|
|
5325
|
+
const toAnchorPos = portsWithPosition[1].position;
|
|
5326
|
+
const toPort = portsWithPosition[1].port;
|
|
5327
|
+
if (!toPort.source_port_id) {
|
|
5328
|
+
throw new Error(`Missing source_port_id for the 'to' port (${toPortName}).`);
|
|
5329
|
+
}
|
|
5330
|
+
const existingFromNetLabel = db.schematic_net_label.list().find((label) => label.source_net_id === fromPort.source_port_id);
|
|
5331
|
+
const existingToNetLabel = db.schematic_net_label.list().find((label) => label.source_net_id === toPort.source_port_id);
|
|
5332
|
+
const [firstPort, secondPort] = connectedPorts.map(({ port }) => port);
|
|
5333
|
+
const isFirstPortSchematicBox = firstPort.parent?.config.shouldRenderAsSchematicBox;
|
|
5334
|
+
const pinFullName = isFirstPortSchematicBox ? `${firstPort?.parent?.props.name}_${firstPort?.props.name}` : `${secondPort?.parent?.props.name}_${secondPort?.props.name}`;
|
|
5335
|
+
const netLabelText = trace.props.schDisplayLabel ?? pinFullName;
|
|
5336
|
+
if (existingFromNetLabel && existingFromNetLabel.text !== netLabelText) {
|
|
5337
|
+
existingFromNetLabel.text = `${netLabelText} / ${existingFromNetLabel.text}`;
|
|
5338
|
+
}
|
|
5339
|
+
if (existingToNetLabel && existingToNetLabel?.text !== netLabelText) {
|
|
5340
|
+
existingToNetLabel.text = `${netLabelText} / ${existingToNetLabel.text}`;
|
|
5341
|
+
}
|
|
5342
|
+
if (!existingToNetLabel) {
|
|
5343
|
+
const toSide = getEnteringEdgeFromDirection(toPort.facingDirection) ?? "bottom";
|
|
5344
|
+
db.schematic_net_label.insert({
|
|
5345
|
+
text: trace.props.schDisplayLabel ?? pinFullName,
|
|
5346
|
+
source_net_id: toPort.source_port_id,
|
|
5347
|
+
anchor_position: toAnchorPos,
|
|
5348
|
+
center: computeSchematicNetLabelCenter({
|
|
5349
|
+
anchor_position: toAnchorPos,
|
|
5350
|
+
anchor_side: toSide,
|
|
5351
|
+
text: trace.props.schDisplayLabel ?? pinFullName
|
|
5352
|
+
}),
|
|
5353
|
+
anchor_side: toSide
|
|
5354
|
+
});
|
|
5355
|
+
}
|
|
5356
|
+
if (!existingFromNetLabel) {
|
|
5357
|
+
const fromSide = getEnteringEdgeFromDirection(fromPort.facingDirection) ?? "bottom";
|
|
5358
|
+
db.schematic_net_label.insert({
|
|
5359
|
+
text: trace.props.schDisplayLabel ?? pinFullName,
|
|
5360
|
+
source_net_id: fromPort.source_port_id,
|
|
5361
|
+
anchor_position: fromAnchorPos,
|
|
5362
|
+
center: computeSchematicNetLabelCenter({
|
|
5363
|
+
anchor_position: fromAnchorPos,
|
|
5364
|
+
anchor_side: fromSide,
|
|
5365
|
+
text: trace.props.schDisplayLabel ?? pinFullName
|
|
5366
|
+
}),
|
|
5367
|
+
anchor_side: fromSide
|
|
5368
|
+
});
|
|
5369
|
+
}
|
|
5370
|
+
}
|
|
5371
|
+
|
|
5372
|
+
// lib/components/primitive-components/Trace/Trace__findConnectedPorts.ts
|
|
5373
|
+
function Trace__findConnectedPorts(trace) {
|
|
5374
|
+
const { db } = trace.root;
|
|
5375
|
+
const { _parsedProps: props, parent } = trace;
|
|
5376
|
+
if (!parent) throw new Error("Trace has no parent");
|
|
5377
|
+
const portSelectors = trace.getTracePortPathSelectors();
|
|
5378
|
+
const portsWithSelectors = portSelectors.map((selector) => ({
|
|
5379
|
+
selector,
|
|
5380
|
+
port: trace.getSubcircuit().selectOne(selector, { type: "port" }) ?? null
|
|
5381
|
+
}));
|
|
5382
|
+
for (const { selector, port } of portsWithSelectors) {
|
|
5383
|
+
if (!port) {
|
|
5384
|
+
let parentSelector;
|
|
5385
|
+
let portToken;
|
|
5386
|
+
const dotIndex = selector.lastIndexOf(".");
|
|
5387
|
+
if (dotIndex !== -1 && dotIndex > selector.lastIndexOf(" ")) {
|
|
5388
|
+
parentSelector = selector.slice(0, dotIndex);
|
|
5389
|
+
portToken = selector.slice(dotIndex + 1);
|
|
5390
|
+
} else {
|
|
5391
|
+
const match = selector.match(/^(.*[ >])?([^ >]+)$/);
|
|
5392
|
+
parentSelector = match?.[1]?.trim() ?? "";
|
|
5393
|
+
portToken = match?.[2] ?? selector;
|
|
5394
|
+
}
|
|
5395
|
+
let targetComponent = parentSelector ? trace.getSubcircuit().selectOne(parentSelector) : null;
|
|
5396
|
+
if (!targetComponent && parentSelector && !/[.#\[]/.test(parentSelector)) {
|
|
5397
|
+
targetComponent = trace.getSubcircuit().selectOne(`.${parentSelector}`);
|
|
5398
|
+
}
|
|
5399
|
+
if (!targetComponent) {
|
|
5400
|
+
if (parentSelector) {
|
|
5401
|
+
trace.renderError(
|
|
5402
|
+
`Could not find port for selector "${selector}". Component "${parentSelector}" not found`
|
|
5403
|
+
);
|
|
5404
|
+
} else {
|
|
5405
|
+
trace.renderError(`Could not find port for selector "${selector}"`);
|
|
5406
|
+
}
|
|
5407
|
+
} else {
|
|
5408
|
+
const ports = targetComponent.children.filter(
|
|
5409
|
+
(c) => c.componentName === "Port"
|
|
5410
|
+
);
|
|
5411
|
+
const portLabel = portToken.includes(".") ? portToken.split(".").pop() ?? "" : portToken;
|
|
5412
|
+
const portNames = ports.flatMap((c) => c.getNameAndAliases());
|
|
5413
|
+
const hasCustomLabels = portNames.some((n) => !/^(pin\d+|\d+)$/.test(n));
|
|
5414
|
+
const labelList = Array.from(new Set(portNames)).join(", ");
|
|
5415
|
+
let detail;
|
|
5416
|
+
if (ports.length === 0) {
|
|
5417
|
+
detail = "It has no ports";
|
|
5418
|
+
} else if (!hasCustomLabels) {
|
|
5419
|
+
detail = `It has ${ports.length} pins and no pinLabels (consider adding pinLabels)`;
|
|
5420
|
+
} else {
|
|
5421
|
+
detail = `It has [${labelList}]`;
|
|
5422
|
+
}
|
|
5423
|
+
trace.renderError(
|
|
5424
|
+
`Could not find port for selector "${selector}". Component "${targetComponent.props.name ?? parentSelector}" found, but does not have pin "${portLabel}". ${detail}`
|
|
5425
|
+
);
|
|
5426
|
+
}
|
|
5427
|
+
}
|
|
5428
|
+
}
|
|
5429
|
+
if (portsWithSelectors.some((p) => !p.port)) {
|
|
5430
|
+
return { allPortsFound: false };
|
|
5431
|
+
}
|
|
5432
|
+
return {
|
|
5433
|
+
allPortsFound: true,
|
|
5434
|
+
portsWithSelectors,
|
|
5435
|
+
ports: portsWithSelectors.map(({ port }) => port)
|
|
5436
|
+
};
|
|
5437
|
+
}
|
|
5438
|
+
|
|
5439
|
+
// lib/components/primitive-components/Trace/Trace.ts
|
|
5440
|
+
var Trace3 = class extends PrimitiveComponent2 {
|
|
5441
|
+
source_trace_id = null;
|
|
5442
|
+
pcb_trace_id = null;
|
|
5443
|
+
schematic_trace_id = null;
|
|
5444
|
+
_portsRoutedOnPcb;
|
|
5445
|
+
subcircuit_connectivity_map_key = null;
|
|
5446
|
+
_traceConnectionHash = null;
|
|
5447
|
+
constructor(props) {
|
|
5448
|
+
super(props);
|
|
5449
|
+
this._portsRoutedOnPcb = [];
|
|
5450
|
+
}
|
|
5451
|
+
get config() {
|
|
5452
|
+
return {
|
|
5453
|
+
zodProps: traceProps,
|
|
5454
|
+
componentName: "Trace"
|
|
5455
|
+
};
|
|
5456
|
+
}
|
|
5457
|
+
_getTracePortOrNetSelectorListFromProps() {
|
|
5458
|
+
if ("from" in this.props && "to" in this.props) {
|
|
5459
|
+
return [
|
|
5460
|
+
typeof this.props.from === "string" ? this.props.from : this.props.from.getPortSelector(),
|
|
5461
|
+
typeof this.props.to === "string" ? this.props.to : this.props.to.getPortSelector()
|
|
5462
|
+
];
|
|
5463
|
+
}
|
|
5464
|
+
if ("path" in this.props) {
|
|
5465
|
+
return this.props.path.map(
|
|
5466
|
+
(p) => typeof p === "string" ? p : p.getPortSelector()
|
|
5467
|
+
);
|
|
4873
5468
|
}
|
|
4874
|
-
return
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
5469
|
+
return [];
|
|
5470
|
+
}
|
|
5471
|
+
getTracePortPathSelectors() {
|
|
5472
|
+
return this._getTracePortOrNetSelectorListFromProps().filter(
|
|
5473
|
+
(selector) => !selector.includes("net.")
|
|
5474
|
+
);
|
|
5475
|
+
}
|
|
5476
|
+
getTracePathNetSelectors() {
|
|
5477
|
+
return this._getTracePortOrNetSelectorListFromProps().filter(
|
|
5478
|
+
(selector) => selector.includes("net.")
|
|
5479
|
+
);
|
|
5480
|
+
}
|
|
5481
|
+
_findConnectedPorts() {
|
|
5482
|
+
return Trace__findConnectedPorts(this);
|
|
4879
5483
|
}
|
|
4880
5484
|
_resolveNet(selector) {
|
|
4881
5485
|
const direct = this.getSubcircuit().selectOne(selector, {
|
|
@@ -4997,363 +5601,10 @@ var Trace2 = class extends PrimitiveComponent2 {
|
|
|
4997
5601
|
}
|
|
4998
5602
|
}
|
|
4999
5603
|
doInitialPcbTraceRender() {
|
|
5000
|
-
|
|
5001
|
-
const { db } = this.root;
|
|
5002
|
-
const { _parsedProps: props, parent } = this;
|
|
5003
|
-
const subcircuit = this.getSubcircuit();
|
|
5004
|
-
if (!parent) throw new Error("Trace has no parent");
|
|
5005
|
-
if (subcircuit._parsedProps.routingDisabled) {
|
|
5006
|
-
return;
|
|
5007
|
-
}
|
|
5008
|
-
const cachedRoute = subcircuit._parsedProps.pcbRouteCache?.pcbTraces;
|
|
5009
|
-
if (cachedRoute) {
|
|
5010
|
-
const pcb_trace2 = db.pcb_trace.insert({
|
|
5011
|
-
route: cachedRoute.flatMap((trace) => trace.route),
|
|
5012
|
-
source_trace_id: this.source_trace_id,
|
|
5013
|
-
subcircuit_id: subcircuit?.subcircuit_id ?? void 0,
|
|
5014
|
-
pcb_group_id: this.getGroup()?.pcb_group_id ?? void 0
|
|
5015
|
-
});
|
|
5016
|
-
this.pcb_trace_id = pcb_trace2.pcb_trace_id;
|
|
5017
|
-
return;
|
|
5018
|
-
}
|
|
5019
|
-
if (!subcircuit._shouldUseTraceByTraceRouting()) {
|
|
5020
|
-
return;
|
|
5021
|
-
}
|
|
5022
|
-
const { allPortsFound, ports } = this._findConnectedPorts();
|
|
5023
|
-
const portsConnectedOnPcbViaNet = [];
|
|
5024
|
-
if (!allPortsFound) return;
|
|
5025
|
-
const portsWithoutMatchedPcbPrimitive = [];
|
|
5026
|
-
for (const port of ports) {
|
|
5027
|
-
if (!port._hasMatchedPcbPrimitive()) {
|
|
5028
|
-
portsWithoutMatchedPcbPrimitive.push(port);
|
|
5029
|
-
}
|
|
5030
|
-
}
|
|
5031
|
-
if (portsWithoutMatchedPcbPrimitive.length > 0) {
|
|
5032
|
-
db.pcb_trace_error.insert({
|
|
5033
|
-
error_type: "pcb_trace_error",
|
|
5034
|
-
source_trace_id: this.source_trace_id,
|
|
5035
|
-
message: `Some ports did not have a matching PCB primitive (e.g. a pad or plated hole), this can happen if a footprint is missing. As a result, ${this} wasn't routed. Missing ports: ${portsWithoutMatchedPcbPrimitive.map((p) => p.getString()).join(", ")}`,
|
|
5036
|
-
pcb_trace_id: this.pcb_trace_id,
|
|
5037
|
-
pcb_component_ids: [],
|
|
5038
|
-
pcb_port_ids: portsWithoutMatchedPcbPrimitive.map((p) => p.pcb_port_id).filter(Boolean)
|
|
5039
|
-
});
|
|
5040
|
-
return;
|
|
5041
|
-
}
|
|
5042
|
-
const nets = this._findConnectedNets().netsWithSelectors;
|
|
5043
|
-
if (ports.length === 0 && nets.length === 2) {
|
|
5044
|
-
this.renderError(
|
|
5045
|
-
`Trace connects two nets, we haven't implemented a way to route this yet`
|
|
5046
|
-
);
|
|
5047
|
-
return;
|
|
5048
|
-
} else if (ports.length === 1 && nets.length === 1) {
|
|
5049
|
-
const port = ports[0];
|
|
5050
|
-
const portsInNet = nets[0].net.getAllConnectedPorts();
|
|
5051
|
-
const otherPortsInNet = portsInNet.filter((p) => p !== port);
|
|
5052
|
-
if (otherPortsInNet.length === 0) {
|
|
5053
|
-
console.log(
|
|
5054
|
-
"Nothing to connect this port to, the net is empty. TODO should emit a warning!"
|
|
5055
|
-
);
|
|
5056
|
-
return;
|
|
5057
|
-
}
|
|
5058
|
-
const closestPortInNet = getClosest(port, otherPortsInNet);
|
|
5059
|
-
portsConnectedOnPcbViaNet.push(closestPortInNet);
|
|
5060
|
-
ports.push(closestPortInNet);
|
|
5061
|
-
} else if (ports.length > 1 && nets.length >= 1) {
|
|
5062
|
-
this.renderError(
|
|
5063
|
-
`Trace has more than one port and one or more nets, we don't currently support this type of complex trace routing`
|
|
5064
|
-
);
|
|
5065
|
-
return;
|
|
5066
|
-
}
|
|
5067
|
-
const hints = ports.flatMap(
|
|
5068
|
-
(port) => port.matchedComponents.filter((c) => c.componentName === "TraceHint")
|
|
5069
|
-
);
|
|
5070
|
-
const pcbRouteHints = (this._parsedProps.pcbRouteHints ?? []).concat(
|
|
5071
|
-
hints.flatMap((h) => h.getPcbRouteHints())
|
|
5072
|
-
);
|
|
5073
|
-
if (ports.length > 2) {
|
|
5074
|
-
this.renderError(
|
|
5075
|
-
`Trace has more than two ports (${ports.map((p) => p.getString()).join(
|
|
5076
|
-
", "
|
|
5077
|
-
)}), routing between more than two ports for a single trace is not implemented`
|
|
5078
|
-
);
|
|
5079
|
-
return;
|
|
5080
|
-
}
|
|
5081
|
-
const alreadyRoutedTraces = this.getSubcircuit().selectAll("trace").filter(
|
|
5082
|
-
(trace) => trace.renderPhaseStates.PcbTraceRender.initialized
|
|
5083
|
-
);
|
|
5084
|
-
const isAlreadyRouted = alreadyRoutedTraces.some(
|
|
5085
|
-
(trace) => trace._portsRoutedOnPcb.length === ports.length && trace._portsRoutedOnPcb.every(
|
|
5086
|
-
(portRoutedByOtherTrace) => ports.includes(portRoutedByOtherTrace)
|
|
5087
|
-
)
|
|
5088
|
-
);
|
|
5089
|
-
if (isAlreadyRouted) {
|
|
5090
|
-
return;
|
|
5091
|
-
}
|
|
5092
|
-
let orderedRouteObjectives = [];
|
|
5093
|
-
if (pcbRouteHints.length === 0) {
|
|
5094
|
-
orderedRouteObjectives = [
|
|
5095
|
-
portToObjective(ports[0]),
|
|
5096
|
-
portToObjective(ports[1])
|
|
5097
|
-
];
|
|
5098
|
-
} else {
|
|
5099
|
-
orderedRouteObjectives = [
|
|
5100
|
-
portToObjective(ports[0]),
|
|
5101
|
-
...pcbRouteHints,
|
|
5102
|
-
portToObjective(ports[1])
|
|
5103
|
-
];
|
|
5104
|
-
}
|
|
5105
|
-
const candidateLayerCombinations = findPossibleTraceLayerCombinations(
|
|
5106
|
-
orderedRouteObjectives
|
|
5107
|
-
);
|
|
5108
|
-
if (SHOULD_USE_SINGLE_LAYER_ROUTING && candidateLayerCombinations.length === 0) {
|
|
5109
|
-
this.renderError(
|
|
5110
|
-
`Could not find a common layer (using hints) for trace ${this.getString()}`
|
|
5111
|
-
);
|
|
5112
|
-
return;
|
|
5113
|
-
}
|
|
5114
|
-
const connMap = getFullConnectivityMapFromCircuitJson(
|
|
5115
|
-
this.root.db.toArray()
|
|
5116
|
-
);
|
|
5117
|
-
const [obstacles, errGettingObstacles] = tryNow(
|
|
5118
|
-
() => getObstaclesFromCircuitJson(this.root.db.toArray())
|
|
5119
|
-
// Remove as any when autorouting-dataset gets updated
|
|
5120
|
-
);
|
|
5121
|
-
if (errGettingObstacles) {
|
|
5122
|
-
this.renderError({
|
|
5123
|
-
type: "pcb_trace_error",
|
|
5124
|
-
error_type: "pcb_trace_error",
|
|
5125
|
-
pcb_trace_error_id: this.pcb_trace_id,
|
|
5126
|
-
message: `Error getting obstacles for autorouting: ${errGettingObstacles.message}`,
|
|
5127
|
-
source_trace_id: this.source_trace_id,
|
|
5128
|
-
center: { x: 0, y: 0 },
|
|
5129
|
-
pcb_port_ids: ports.map((p) => p.pcb_port_id),
|
|
5130
|
-
pcb_trace_id: this.pcb_trace_id,
|
|
5131
|
-
pcb_component_ids: []
|
|
5132
|
-
});
|
|
5133
|
-
return;
|
|
5134
|
-
}
|
|
5135
|
-
for (const obstacle of obstacles) {
|
|
5136
|
-
const connectedTo = obstacle.connectedTo;
|
|
5137
|
-
if (connectedTo.length > 0) {
|
|
5138
|
-
const netId = connMap.getNetConnectedToId(obstacle.connectedTo[0]);
|
|
5139
|
-
if (netId) {
|
|
5140
|
-
obstacle.connectedTo.push(netId);
|
|
5141
|
-
}
|
|
5142
|
-
}
|
|
5143
|
-
}
|
|
5144
|
-
let orderedRoutePoints = [];
|
|
5145
|
-
if (candidateLayerCombinations.length === 0) {
|
|
5146
|
-
orderedRoutePoints = orderedRouteObjectives;
|
|
5147
|
-
} else {
|
|
5148
|
-
const candidateLayerSelections = candidateLayerCombinations[0].layer_path;
|
|
5149
|
-
orderedRoutePoints = orderedRouteObjectives.map((t, idx) => {
|
|
5150
|
-
if (t.via) {
|
|
5151
|
-
return {
|
|
5152
|
-
...t,
|
|
5153
|
-
via_to_layer: candidateLayerSelections[idx]
|
|
5154
|
-
};
|
|
5155
|
-
}
|
|
5156
|
-
return { ...t, layers: [candidateLayerSelections[idx]] };
|
|
5157
|
-
});
|
|
5158
|
-
}
|
|
5159
|
-
;
|
|
5160
|
-
orderedRoutePoints[0].pcb_port_id = ports[0].pcb_port_id;
|
|
5161
|
-
orderedRoutePoints[orderedRoutePoints.length - 1].pcb_port_id = ports[1].pcb_port_id;
|
|
5162
|
-
const routes = [];
|
|
5163
|
-
for (const [a, b] of pairs(orderedRoutePoints)) {
|
|
5164
|
-
const dominantLayer = "via_to_layer" in a ? a.via_to_layer : null;
|
|
5165
|
-
const BOUNDS_MARGIN = 2;
|
|
5166
|
-
const aLayer = "layers" in a && a.layers.length === 1 ? a.layers[0] : dominantLayer ?? "top";
|
|
5167
|
-
const bLayer = "layers" in b && b.layers.length === 1 ? b.layers[0] : dominantLayer ?? "top";
|
|
5168
|
-
const pcbPortA = "pcb_port_id" in a ? a.pcb_port_id : null;
|
|
5169
|
-
const pcbPortB = "pcb_port_id" in b ? b.pcb_port_id : null;
|
|
5170
|
-
const minTraceWidth = this.getSubcircuit()._parsedProps.minTraceWidth ?? 0.16;
|
|
5171
|
-
const ijump = new MultilayerIjump({
|
|
5172
|
-
OBSTACLE_MARGIN: minTraceWidth * 2,
|
|
5173
|
-
isRemovePathLoopsEnabled: true,
|
|
5174
|
-
optimizeWithGoalBoxes: Boolean(pcbPortA && pcbPortB),
|
|
5175
|
-
connMap,
|
|
5176
|
-
input: {
|
|
5177
|
-
obstacles,
|
|
5178
|
-
minTraceWidth,
|
|
5179
|
-
connections: [
|
|
5180
|
-
{
|
|
5181
|
-
name: this.source_trace_id,
|
|
5182
|
-
pointsToConnect: [
|
|
5183
|
-
{ ...a, layer: aLayer, pcb_port_id: pcbPortA },
|
|
5184
|
-
{ ...b, layer: bLayer, pcb_port_id: pcbPortB }
|
|
5185
|
-
]
|
|
5186
|
-
}
|
|
5187
|
-
],
|
|
5188
|
-
layerCount: 2,
|
|
5189
|
-
bounds: {
|
|
5190
|
-
minX: Math.min(a.x, b.x) - BOUNDS_MARGIN,
|
|
5191
|
-
maxX: Math.max(a.x, b.x) + BOUNDS_MARGIN,
|
|
5192
|
-
minY: Math.min(a.y, b.y) - BOUNDS_MARGIN,
|
|
5193
|
-
maxY: Math.max(a.y, b.y) + BOUNDS_MARGIN
|
|
5194
|
-
}
|
|
5195
|
-
}
|
|
5196
|
-
});
|
|
5197
|
-
let traces = null;
|
|
5198
|
-
try {
|
|
5199
|
-
traces = ijump.solveAndMapToTraces();
|
|
5200
|
-
} catch (e) {
|
|
5201
|
-
this.renderError({
|
|
5202
|
-
type: "pcb_trace_error",
|
|
5203
|
-
pcb_trace_error_id: this.source_trace_id,
|
|
5204
|
-
error_type: "pcb_trace_error",
|
|
5205
|
-
message: `error solving route: ${e.message}`,
|
|
5206
|
-
source_trace_id: this.pcb_trace_id,
|
|
5207
|
-
center: { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 },
|
|
5208
|
-
pcb_port_ids: ports.map((p) => p.pcb_port_id),
|
|
5209
|
-
pcb_trace_id: this.pcb_trace_id,
|
|
5210
|
-
pcb_component_ids: ports.map((p) => p.pcb_component_id)
|
|
5211
|
-
});
|
|
5212
|
-
}
|
|
5213
|
-
if (!traces) return;
|
|
5214
|
-
if (traces.length === 0) {
|
|
5215
|
-
this.renderError({
|
|
5216
|
-
type: "pcb_trace_error",
|
|
5217
|
-
error_type: "pcb_trace_error",
|
|
5218
|
-
pcb_trace_error_id: this.pcb_trace_id,
|
|
5219
|
-
message: `Could not find a route for ${this}`,
|
|
5220
|
-
source_trace_id: this.source_trace_id,
|
|
5221
|
-
center: { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 },
|
|
5222
|
-
pcb_port_ids: ports.map((p) => p.pcb_port_id),
|
|
5223
|
-
pcb_trace_id: this.pcb_trace_id,
|
|
5224
|
-
pcb_component_ids: ports.map((p) => p.pcb_component_id)
|
|
5225
|
-
});
|
|
5226
|
-
return;
|
|
5227
|
-
}
|
|
5228
|
-
const [trace] = traces;
|
|
5229
|
-
if (dominantLayer) {
|
|
5230
|
-
trace.route = trace.route.map((p) => {
|
|
5231
|
-
if (p.route_type === "wire" && !p.layer) {
|
|
5232
|
-
p.layer = dominantLayer;
|
|
5233
|
-
}
|
|
5234
|
-
return p;
|
|
5235
|
-
});
|
|
5236
|
-
}
|
|
5237
|
-
if (pcbPortA && trace.route[0].route_type === "wire") {
|
|
5238
|
-
trace.route[0].start_pcb_port_id = pcbPortA;
|
|
5239
|
-
}
|
|
5240
|
-
const lastRoutePoint = trace.route[trace.route.length - 1];
|
|
5241
|
-
if (pcbPortB && lastRoutePoint.route_type === "wire") {
|
|
5242
|
-
lastRoutePoint.end_pcb_port_id = pcbPortB;
|
|
5243
|
-
}
|
|
5244
|
-
routes.push(trace.route);
|
|
5245
|
-
}
|
|
5246
|
-
const mergedRoute = mergeRoutes(routes);
|
|
5247
|
-
const traceLength = getTraceLength(mergedRoute);
|
|
5248
|
-
const pcb_trace = db.pcb_trace.insert({
|
|
5249
|
-
route: mergedRoute,
|
|
5250
|
-
source_trace_id: this.source_trace_id,
|
|
5251
|
-
subcircuit_id: this.getSubcircuit()?.subcircuit_id,
|
|
5252
|
-
trace_length: traceLength
|
|
5253
|
-
});
|
|
5254
|
-
this._portsRoutedOnPcb = ports;
|
|
5255
|
-
this.pcb_trace_id = pcb_trace.pcb_trace_id;
|
|
5256
|
-
for (const point of mergedRoute) {
|
|
5257
|
-
if (point.route_type === "via") {
|
|
5258
|
-
db.pcb_via.insert({
|
|
5259
|
-
pcb_trace_id: pcb_trace.pcb_trace_id,
|
|
5260
|
-
x: point.x,
|
|
5261
|
-
y: point.y,
|
|
5262
|
-
hole_diameter: 0.3,
|
|
5263
|
-
outer_diameter: 0.6,
|
|
5264
|
-
layers: [point.from_layer, point.to_layer],
|
|
5265
|
-
from_layer: point.from_layer,
|
|
5266
|
-
to_layer: point.to_layer
|
|
5267
|
-
});
|
|
5268
|
-
}
|
|
5269
|
-
}
|
|
5270
|
-
this._insertErrorIfTraceIsOutsideBoard(mergedRoute, ports);
|
|
5604
|
+
Trace_doInitialPcbTraceRender(this);
|
|
5271
5605
|
}
|
|
5272
5606
|
_doInitialSchematicTraceRenderWithDisplayLabel() {
|
|
5273
|
-
|
|
5274
|
-
const { db } = this.root;
|
|
5275
|
-
const { _parsedProps: props, parent } = this;
|
|
5276
|
-
if (!parent) throw new Error("Trace has no parent");
|
|
5277
|
-
const { allPortsFound, portsWithSelectors: connectedPorts } = this._findConnectedPorts();
|
|
5278
|
-
if (!allPortsFound) return;
|
|
5279
|
-
const portsWithPosition = connectedPorts.map(({ port }) => ({
|
|
5280
|
-
port,
|
|
5281
|
-
position: port._getGlobalSchematicPositionAfterLayout(),
|
|
5282
|
-
schematic_port_id: port.schematic_port_id,
|
|
5283
|
-
facingDirection: port.facingDirection
|
|
5284
|
-
}));
|
|
5285
|
-
if (portsWithPosition.length < 2) {
|
|
5286
|
-
throw new Error("Expected at least two ports in portsWithPosition.");
|
|
5287
|
-
}
|
|
5288
|
-
let fromPortName;
|
|
5289
|
-
let toPortName;
|
|
5290
|
-
const fromAnchorPos = portsWithPosition[0].position;
|
|
5291
|
-
const fromPort = portsWithPosition[0].port;
|
|
5292
|
-
if ("path" in this.props) {
|
|
5293
|
-
if (this.props.path.length !== 2) {
|
|
5294
|
-
throw new Error("Invalid 'path': Must contain exactly two elements.");
|
|
5295
|
-
}
|
|
5296
|
-
;
|
|
5297
|
-
[fromPortName, toPortName] = this.props.path;
|
|
5298
|
-
} else {
|
|
5299
|
-
if (!("from" in this.props && "to" in this.props)) {
|
|
5300
|
-
throw new Error("Missing 'from' or 'to' properties in props.");
|
|
5301
|
-
}
|
|
5302
|
-
fromPortName = this.props.from;
|
|
5303
|
-
toPortName = this.props.to;
|
|
5304
|
-
}
|
|
5305
|
-
if (!fromPort.source_port_id) {
|
|
5306
|
-
throw new Error(
|
|
5307
|
-
`Missing source_port_id for the 'from' port (${fromPortName}).`
|
|
5308
|
-
);
|
|
5309
|
-
}
|
|
5310
|
-
const toAnchorPos = portsWithPosition[1].position;
|
|
5311
|
-
const toPort = portsWithPosition[1].port;
|
|
5312
|
-
if (!toPort.source_port_id) {
|
|
5313
|
-
throw new Error(
|
|
5314
|
-
`Missing source_port_id for the 'to' port (${toPortName}).`
|
|
5315
|
-
);
|
|
5316
|
-
}
|
|
5317
|
-
const existingFromNetLabel = db.schematic_net_label.list().find((label) => label.source_net_id === fromPort.source_port_id);
|
|
5318
|
-
const existingToNetLabel = db.schematic_net_label.list().find((label) => label.source_net_id === toPort.source_port_id);
|
|
5319
|
-
const [firstPort, secondPort] = connectedPorts.map(({ port }) => port);
|
|
5320
|
-
const isFirstPortSchematicBox = firstPort.parent?.config.shouldRenderAsSchematicBox;
|
|
5321
|
-
const pinFullName = isFirstPortSchematicBox ? `${firstPort?.parent?.props.name}_${firstPort?.props.name}` : `${secondPort?.parent?.props.name}_${secondPort?.props.name}`;
|
|
5322
|
-
const netLabelText = this.props.schDisplayLabel ?? pinFullName;
|
|
5323
|
-
if (existingFromNetLabel && existingFromNetLabel.text !== netLabelText) {
|
|
5324
|
-
existingFromNetLabel.text = `${netLabelText} / ${existingFromNetLabel.text}`;
|
|
5325
|
-
}
|
|
5326
|
-
if (existingToNetLabel && existingToNetLabel?.text !== netLabelText) {
|
|
5327
|
-
existingToNetLabel.text = `${netLabelText} / ${existingToNetLabel.text}`;
|
|
5328
|
-
}
|
|
5329
|
-
if (!existingToNetLabel) {
|
|
5330
|
-
const toSide = getEnteringEdgeFromDirection(toPort.facingDirection) ?? "bottom";
|
|
5331
|
-
db.schematic_net_label.insert({
|
|
5332
|
-
text: this.props.schDisplayLabel ?? pinFullName,
|
|
5333
|
-
source_net_id: toPort.source_port_id,
|
|
5334
|
-
anchor_position: toAnchorPos,
|
|
5335
|
-
center: computeSchematicNetLabelCenter({
|
|
5336
|
-
anchor_position: toAnchorPos,
|
|
5337
|
-
anchor_side: toSide,
|
|
5338
|
-
text: this.props.schDisplayLabel ?? pinFullName
|
|
5339
|
-
}),
|
|
5340
|
-
anchor_side: toSide
|
|
5341
|
-
});
|
|
5342
|
-
}
|
|
5343
|
-
if (!existingFromNetLabel) {
|
|
5344
|
-
const fromSide = getEnteringEdgeFromDirection(fromPort.facingDirection) ?? "bottom";
|
|
5345
|
-
db.schematic_net_label.insert({
|
|
5346
|
-
text: this.props.schDisplayLabel ?? pinFullName,
|
|
5347
|
-
source_net_id: fromPort.source_port_id,
|
|
5348
|
-
anchor_position: fromAnchorPos,
|
|
5349
|
-
center: computeSchematicNetLabelCenter({
|
|
5350
|
-
anchor_position: fromAnchorPos,
|
|
5351
|
-
anchor_side: fromSide,
|
|
5352
|
-
text: this.props.schDisplayLabel ?? pinFullName
|
|
5353
|
-
}),
|
|
5354
|
-
anchor_side: fromSide
|
|
5355
|
-
});
|
|
5356
|
-
}
|
|
5607
|
+
Trace__doInitialSchematicTraceRenderWithDisplayLabel(this);
|
|
5357
5608
|
}
|
|
5358
5609
|
_isSymbolToChipConnection() {
|
|
5359
5610
|
const { allPortsFound, ports } = this._findConnectedPorts();
|
|
@@ -5383,235 +5634,7 @@ var Trace2 = class extends PrimitiveComponent2 {
|
|
|
5383
5634
|
return isPort1Chip && isPort2Chip;
|
|
5384
5635
|
}
|
|
5385
5636
|
doInitialSchematicTraceRender() {
|
|
5386
|
-
|
|
5387
|
-
const { db } = this.root;
|
|
5388
|
-
const { _parsedProps: props, parent } = this;
|
|
5389
|
-
if (!parent) throw new Error("Trace has no parent");
|
|
5390
|
-
const { allPortsFound, portsWithSelectors: connectedPorts } = this._findConnectedPorts();
|
|
5391
|
-
const { netsWithSelectors } = this._findConnectedNets();
|
|
5392
|
-
if (!allPortsFound) return;
|
|
5393
|
-
const portIds = connectedPorts.map((p) => p.port.schematic_port_id).sort();
|
|
5394
|
-
const portPairKey = portIds.join(",");
|
|
5395
|
-
const board = this.root?._getBoard();
|
|
5396
|
-
if (board?._connectedSchematicPortPairs) {
|
|
5397
|
-
if (board._connectedSchematicPortPairs.has(portPairKey)) {
|
|
5398
|
-
return;
|
|
5399
|
-
}
|
|
5400
|
-
}
|
|
5401
|
-
const connection = {
|
|
5402
|
-
name: this.source_trace_id,
|
|
5403
|
-
pointsToConnect: []
|
|
5404
|
-
};
|
|
5405
|
-
const obstacles = getSchematicObstaclesForTrace(this);
|
|
5406
|
-
const portsWithPosition = connectedPorts.map(({ port }) => ({
|
|
5407
|
-
port,
|
|
5408
|
-
position: port._getGlobalSchematicPositionAfterLayout(),
|
|
5409
|
-
schematic_port_id: port.schematic_port_id ?? void 0,
|
|
5410
|
-
facingDirection: port.facingDirection
|
|
5411
|
-
}));
|
|
5412
|
-
const isPortAndNetConnection = portsWithPosition.length === 1 && netsWithSelectors.length === 1;
|
|
5413
|
-
if (isPortAndNetConnection) {
|
|
5414
|
-
const net = netsWithSelectors[0].net;
|
|
5415
|
-
const { port, position: anchorPos } = portsWithPosition[0];
|
|
5416
|
-
let connectedNetLabel = this.getSubcircuit().selectAll("netlabel").find((nl) => {
|
|
5417
|
-
const conn = nl._parsedProps.connection ?? nl._parsedProps.connectsTo;
|
|
5418
|
-
if (!conn) return false;
|
|
5419
|
-
if (Array.isArray(conn)) {
|
|
5420
|
-
return conn.some((selector) => {
|
|
5421
|
-
const targetPort2 = this.getSubcircuit().selectOne(selector, {
|
|
5422
|
-
port: true
|
|
5423
|
-
});
|
|
5424
|
-
return targetPort2 === port;
|
|
5425
|
-
});
|
|
5426
|
-
}
|
|
5427
|
-
const targetPort = this.getSubcircuit().selectOne(conn, {
|
|
5428
|
-
port: true
|
|
5429
|
-
});
|
|
5430
|
-
return targetPort === port;
|
|
5431
|
-
});
|
|
5432
|
-
if (!connectedNetLabel) {
|
|
5433
|
-
const dbNetLabel = db.schematic_net_label.getWhere({
|
|
5434
|
-
source_trace_id: this.source_trace_id
|
|
5435
|
-
});
|
|
5436
|
-
if (dbNetLabel) {
|
|
5437
|
-
connectedNetLabel = dbNetLabel;
|
|
5438
|
-
}
|
|
5439
|
-
}
|
|
5440
|
-
if (connectedNetLabel) {
|
|
5441
|
-
const labelPos = "_getGlobalSchematicPositionBeforeLayout" in connectedNetLabel ? connectedNetLabel._getGlobalSchematicPositionBeforeLayout() : connectedNetLabel.anchor_position;
|
|
5442
|
-
const edges2 = [];
|
|
5443
|
-
if (anchorPos.x === labelPos.x || anchorPos.y === labelPos.y) {
|
|
5444
|
-
edges2.push({ from: anchorPos, to: labelPos });
|
|
5445
|
-
} else {
|
|
5446
|
-
edges2.push({ from: anchorPos, to: { x: labelPos.x, y: anchorPos.y } });
|
|
5447
|
-
edges2.push({ from: { x: labelPos.x, y: anchorPos.y }, to: labelPos });
|
|
5448
|
-
}
|
|
5449
|
-
const trace2 = db.schematic_trace.insert({
|
|
5450
|
-
source_trace_id: this.source_trace_id,
|
|
5451
|
-
edges: edges2,
|
|
5452
|
-
junctions: []
|
|
5453
|
-
});
|
|
5454
|
-
this.schematic_trace_id = trace2.schematic_trace_id;
|
|
5455
|
-
return;
|
|
5456
|
-
}
|
|
5457
|
-
if (this.props.schDisplayLabel) {
|
|
5458
|
-
const side2 = getEnteringEdgeFromDirection(port.facingDirection) ?? "bottom";
|
|
5459
|
-
db.schematic_net_label.insert({
|
|
5460
|
-
text: this.props.schDisplayLabel,
|
|
5461
|
-
source_net_id: net.source_net_id,
|
|
5462
|
-
anchor_position: anchorPos,
|
|
5463
|
-
center: computeSchematicNetLabelCenter({
|
|
5464
|
-
anchor_position: anchorPos,
|
|
5465
|
-
anchor_side: side2,
|
|
5466
|
-
text: this.props.schDisplayLabel
|
|
5467
|
-
}),
|
|
5468
|
-
anchor_side: side2
|
|
5469
|
-
});
|
|
5470
|
-
return;
|
|
5471
|
-
}
|
|
5472
|
-
const side = getEnteringEdgeFromDirection(port.facingDirection) ?? "bottom";
|
|
5473
|
-
const netLabel = db.schematic_net_label.insert({
|
|
5474
|
-
text: net._parsedProps.name,
|
|
5475
|
-
source_net_id: net.source_net_id,
|
|
5476
|
-
anchor_position: anchorPos,
|
|
5477
|
-
center: computeSchematicNetLabelCenter({
|
|
5478
|
-
anchor_position: anchorPos,
|
|
5479
|
-
anchor_side: side,
|
|
5480
|
-
text: net._parsedProps.name
|
|
5481
|
-
}),
|
|
5482
|
-
anchor_side: side
|
|
5483
|
-
});
|
|
5484
|
-
return;
|
|
5485
|
-
}
|
|
5486
|
-
if (this.props.schDisplayLabel) {
|
|
5487
|
-
if ("from" in this.props && "to" in this.props || "path" in this.props) {
|
|
5488
|
-
this._doInitialSchematicTraceRenderWithDisplayLabel();
|
|
5489
|
-
return;
|
|
5490
|
-
}
|
|
5491
|
-
}
|
|
5492
|
-
if (portsWithPosition.length < 2) {
|
|
5493
|
-
return;
|
|
5494
|
-
}
|
|
5495
|
-
connection.pointsToConnect = portsWithPosition.map(({ position }) => ({
|
|
5496
|
-
...position,
|
|
5497
|
-
layer: "top"
|
|
5498
|
-
}));
|
|
5499
|
-
const bounds = computeObstacleBounds(obstacles);
|
|
5500
|
-
const BOUNDS_MARGIN = 2;
|
|
5501
|
-
const simpleRouteJsonInput = {
|
|
5502
|
-
minTraceWidth: 0.1,
|
|
5503
|
-
obstacles,
|
|
5504
|
-
connections: [connection],
|
|
5505
|
-
bounds: {
|
|
5506
|
-
minX: bounds.minX - BOUNDS_MARGIN,
|
|
5507
|
-
maxX: bounds.maxX + BOUNDS_MARGIN,
|
|
5508
|
-
minY: bounds.minY - BOUNDS_MARGIN,
|
|
5509
|
-
maxY: bounds.maxY + BOUNDS_MARGIN
|
|
5510
|
-
},
|
|
5511
|
-
layerCount: 1
|
|
5512
|
-
};
|
|
5513
|
-
let Autorouter = MultilayerIjump;
|
|
5514
|
-
let skipOtherTraceInteraction = false;
|
|
5515
|
-
if (this.getSubcircuit().props._schDirectLineRoutingEnabled) {
|
|
5516
|
-
Autorouter = DirectLineRouter;
|
|
5517
|
-
skipOtherTraceInteraction = true;
|
|
5518
|
-
}
|
|
5519
|
-
const autorouter = new Autorouter({
|
|
5520
|
-
input: simpleRouteJsonInput,
|
|
5521
|
-
MAX_ITERATIONS: 100,
|
|
5522
|
-
OBSTACLE_MARGIN: 0.1,
|
|
5523
|
-
isRemovePathLoopsEnabled: true,
|
|
5524
|
-
isShortenPathWithShortcutsEnabled: true,
|
|
5525
|
-
marginsWithCosts: [
|
|
5526
|
-
{
|
|
5527
|
-
margin: 1,
|
|
5528
|
-
enterCost: 0,
|
|
5529
|
-
travelCostFactor: 1
|
|
5530
|
-
},
|
|
5531
|
-
{
|
|
5532
|
-
margin: 0.3,
|
|
5533
|
-
enterCost: 0,
|
|
5534
|
-
travelCostFactor: 1
|
|
5535
|
-
},
|
|
5536
|
-
{
|
|
5537
|
-
margin: 0.2,
|
|
5538
|
-
enterCost: 0,
|
|
5539
|
-
travelCostFactor: 2
|
|
5540
|
-
},
|
|
5541
|
-
{
|
|
5542
|
-
margin: 0.1,
|
|
5543
|
-
enterCost: 0,
|
|
5544
|
-
travelCostFactor: 3
|
|
5545
|
-
}
|
|
5546
|
-
]
|
|
5547
|
-
});
|
|
5548
|
-
let results = autorouter.solveAndMapToTraces();
|
|
5549
|
-
if (results.length === 0) {
|
|
5550
|
-
if (this._isSymbolToChipConnection() || this._isSymbolToSymbolConnection() || this._isChipToChipConnection()) {
|
|
5551
|
-
this._doInitialSchematicTraceRenderWithDisplayLabel();
|
|
5552
|
-
return;
|
|
5553
|
-
}
|
|
5554
|
-
const directLineRouter = new DirectLineRouter({
|
|
5555
|
-
input: simpleRouteJsonInput
|
|
5556
|
-
});
|
|
5557
|
-
results = directLineRouter.solveAndMapToTraces();
|
|
5558
|
-
skipOtherTraceInteraction = true;
|
|
5559
|
-
}
|
|
5560
|
-
const [{ route }] = results;
|
|
5561
|
-
let edges = [];
|
|
5562
|
-
for (let i = 0; i < route.length - 1; i++) {
|
|
5563
|
-
edges.push({
|
|
5564
|
-
from: route[i],
|
|
5565
|
-
to: route[i + 1]
|
|
5566
|
-
});
|
|
5567
|
-
}
|
|
5568
|
-
const source_trace_id = this.source_trace_id;
|
|
5569
|
-
let junctions = [];
|
|
5570
|
-
if (!skipOtherTraceInteraction) {
|
|
5571
|
-
pushEdgesOfSchematicTraceToPreventOverlap({ edges, db, source_trace_id });
|
|
5572
|
-
const otherEdges = getOtherSchematicTraces({
|
|
5573
|
-
db,
|
|
5574
|
-
source_trace_id,
|
|
5575
|
-
differentNetOnly: true
|
|
5576
|
-
}).flatMap((t) => t.edges);
|
|
5577
|
-
edges = createSchematicTraceCrossingSegments({ edges, otherEdges });
|
|
5578
|
-
junctions = createSchematicTraceJunctions({
|
|
5579
|
-
edges,
|
|
5580
|
-
db,
|
|
5581
|
-
source_trace_id: this.source_trace_id
|
|
5582
|
-
});
|
|
5583
|
-
}
|
|
5584
|
-
const lastEdge = edges[edges.length - 1];
|
|
5585
|
-
const lastEdgePort = portsWithPosition[portsWithPosition.length - 1];
|
|
5586
|
-
const lastDominantDirection = getDominantDirection(lastEdge);
|
|
5587
|
-
edges.push(
|
|
5588
|
-
...getStubEdges({ lastEdge, lastEdgePort, lastDominantDirection })
|
|
5589
|
-
);
|
|
5590
|
-
const firstEdge = edges[0];
|
|
5591
|
-
const firstEdgePort = portsWithPosition[0];
|
|
5592
|
-
const firstDominantDirection = getDominantDirection(firstEdge);
|
|
5593
|
-
edges.unshift(
|
|
5594
|
-
...getStubEdges({
|
|
5595
|
-
firstEdge,
|
|
5596
|
-
firstEdgePort,
|
|
5597
|
-
firstDominantDirection
|
|
5598
|
-
})
|
|
5599
|
-
);
|
|
5600
|
-
if (!this.source_trace_id) {
|
|
5601
|
-
throw new Error("Missing source_trace_id for schematic trace insertion.");
|
|
5602
|
-
}
|
|
5603
|
-
if (this.getSubcircuit()._parsedProps.schTraceAutoLabelEnabled && countComplexElements(junctions, edges) >= 5 && (this._isSymbolToChipConnection() || this._isSymbolToSymbolConnection() || this._isChipToChipConnection())) {
|
|
5604
|
-
this._doInitialSchematicTraceRenderWithDisplayLabel();
|
|
5605
|
-
return;
|
|
5606
|
-
}
|
|
5607
|
-
const trace = db.schematic_trace.insert({
|
|
5608
|
-
source_trace_id: this.source_trace_id,
|
|
5609
|
-
edges,
|
|
5610
|
-
junctions
|
|
5611
|
-
});
|
|
5612
|
-
this.schematic_trace_id = trace.schematic_trace_id;
|
|
5613
|
-
if (board?._connectedSchematicPortPairs)
|
|
5614
|
-
board._connectedSchematicPortPairs.add(portPairKey);
|
|
5637
|
+
Trace_doInitialSchematicTraceRender(this);
|
|
5615
5638
|
}
|
|
5616
5639
|
};
|
|
5617
5640
|
|
|
@@ -6456,7 +6479,7 @@ var NormalComponent = class extends PrimitiveComponent2 {
|
|
|
6456
6479
|
const targets = Array.isArray(target) ? target : [target];
|
|
6457
6480
|
for (const targetPath of targets) {
|
|
6458
6481
|
this.add(
|
|
6459
|
-
new
|
|
6482
|
+
new Trace3({
|
|
6460
6483
|
from: `${this.getSubcircuitSelector()} > port.${pinName}`,
|
|
6461
6484
|
to: targetPath
|
|
6462
6485
|
})
|
|
@@ -6638,7 +6661,7 @@ var CapacityMeshAutorouter = class {
|
|
|
6638
6661
|
|
|
6639
6662
|
// lib/components/primitive-components/Group/Group.ts
|
|
6640
6663
|
import "circuit-json";
|
|
6641
|
-
import
|
|
6664
|
+
import Debug6 from "debug";
|
|
6642
6665
|
import "zod";
|
|
6643
6666
|
|
|
6644
6667
|
// lib/components/primitive-components/TraceHint.ts
|
|
@@ -6887,7 +6910,7 @@ var applyEditEvents = ({
|
|
|
6887
6910
|
// lib/utils/autorouting/getSimpleRouteJsonFromCircuitJson.ts
|
|
6888
6911
|
import { su as su4 } from "@tscircuit/circuit-json-util";
|
|
6889
6912
|
import {
|
|
6890
|
-
getFullConnectivityMapFromCircuitJson as
|
|
6913
|
+
getFullConnectivityMapFromCircuitJson as getFullConnectivityMapFromCircuitJson3
|
|
6891
6914
|
} from "circuit-json-to-connectivity-map";
|
|
6892
6915
|
|
|
6893
6916
|
// lib/utils/autorouting/getAncestorSubcircuitIds.ts
|
|
@@ -6938,7 +6961,7 @@ var getSimpleRouteJsonFromCircuitJson = ({
|
|
|
6938
6961
|
);
|
|
6939
6962
|
const board = db.pcb_board.list()[0];
|
|
6940
6963
|
db = su4(subcircuitElements);
|
|
6941
|
-
const connMap =
|
|
6964
|
+
const connMap = getFullConnectivityMapFromCircuitJson3(subcircuitElements);
|
|
6942
6965
|
const obstacles = getObstaclesFromCircuitJson(
|
|
6943
6966
|
[
|
|
6944
6967
|
...db.pcb_component.list(),
|
|
@@ -7287,64 +7310,60 @@ import {
|
|
|
7287
7310
|
// lib/components/primitive-components/Group/Group_doInitialSchematicLayoutMatchAdapt.ts
|
|
7288
7311
|
import "@tscircuit/circuit-json-util";
|
|
7289
7312
|
import "circuit-json-to-connectivity-map";
|
|
7290
|
-
import
|
|
7291
|
-
import { convertCircuitJsonToBpc } from "circuit-json-to-bpc";
|
|
7313
|
+
import { corpusNoNetLabel } from "@tscircuit/schematic-corpus";
|
|
7292
7314
|
import {
|
|
7293
|
-
|
|
7315
|
+
convertCircuitJsonToBpc
|
|
7316
|
+
} from "circuit-json-to-bpc";
|
|
7317
|
+
import {
|
|
7318
|
+
layoutSchematicGraph,
|
|
7319
|
+
getGraphicsForBpcGraph
|
|
7294
7320
|
} from "bpc-graph";
|
|
7321
|
+
import "graphics-debug";
|
|
7322
|
+
import "circuit-to-svg";
|
|
7323
|
+
import Debug5 from "debug";
|
|
7324
|
+
var debug4 = Debug5("Group_doInitialSchematicLayoutMatchAdapt");
|
|
7295
7325
|
function Group_doInitialSchematicLayoutMatchAdapt(group) {
|
|
7296
7326
|
const { db } = group.root;
|
|
7297
7327
|
const subtreeCircuitJson = structuredClone(db.toArray());
|
|
7298
|
-
const
|
|
7299
|
-
|
|
7300
|
-
)
|
|
7301
|
-
|
|
7302
|
-
|
|
7303
|
-
|
|
7304
|
-
|
|
7305
|
-
|
|
7306
|
-
};
|
|
7307
|
-
const generatedNetLabels = /* @__PURE__ */ new Map();
|
|
7308
|
-
for (const sp of subtreeCircuitJson.filter(
|
|
7309
|
-
(e) => e.type === "schematic_port"
|
|
7310
|
-
)) {
|
|
7311
|
-
const key = `${sp.center.x},${sp.center.y}`;
|
|
7312
|
-
if (existingLabels.has(key)) continue;
|
|
7313
|
-
const srcPort = db.source_port.get(sp.source_port_id);
|
|
7314
|
-
const srcNet = db.source_net.getWhere({
|
|
7315
|
-
subcircuit_connectivity_map_key: srcPort?.subcircuit_connectivity_map_key
|
|
7316
|
-
});
|
|
7317
|
-
if (!srcNet) {
|
|
7318
|
-
console.error(`No source net found for port: ${sp.source_port_id}`);
|
|
7319
|
-
continue;
|
|
7320
|
-
}
|
|
7321
|
-
const srcTrace = db.source_trace.getWhere({
|
|
7322
|
-
subcircuit_connectivity_map_key: srcPort?.subcircuit_connectivity_map_key
|
|
7323
|
-
});
|
|
7324
|
-
const schematic_net_label_id = `netlabel_for_${sp.schematic_port_id}`;
|
|
7325
|
-
const source_net = db.source_net.get(srcNet.source_net_id);
|
|
7326
|
-
const schematic_net_label = {
|
|
7327
|
-
type: "schematic_net_label",
|
|
7328
|
-
schematic_net_label_id,
|
|
7329
|
-
text: source_net.name,
|
|
7330
|
-
source_net_id: srcNet.source_net_id,
|
|
7331
|
-
source_trace_id: srcTrace?.source_trace_id,
|
|
7332
|
-
anchor_position: { ...sp.center },
|
|
7333
|
-
center: { ...sp.center },
|
|
7334
|
-
anchor_side: oppositeSideFromFacing[sp.facing_direction] ?? "right"
|
|
7335
|
-
};
|
|
7336
|
-
generatedNetLabels.set(schematic_net_label_id, {
|
|
7337
|
-
schematic_net_label,
|
|
7338
|
-
schematic_port: sp
|
|
7339
|
-
});
|
|
7340
|
-
subtreeCircuitJson.push(schematic_net_label);
|
|
7328
|
+
const bpcGraphBeforeGeneratedNetLabels = convertCircuitJsonToBpc(subtreeCircuitJson);
|
|
7329
|
+
console.log("Writing bpcGraphBeforeGeneratedNetLabels.svg");
|
|
7330
|
+
if (debug4.enabled) {
|
|
7331
|
+
global.debugGraphics?.push(
|
|
7332
|
+
getGraphicsForBpcGraph(bpcGraphBeforeGeneratedNetLabels, {
|
|
7333
|
+
title: "floatingBpcGraph"
|
|
7334
|
+
})
|
|
7335
|
+
);
|
|
7341
7336
|
}
|
|
7342
|
-
const targetBpcGraph = convertCircuitJsonToBpc(
|
|
7337
|
+
const targetBpcGraph = convertCircuitJsonToBpc(
|
|
7338
|
+
subtreeCircuitJson
|
|
7339
|
+
// .concat(implicitNetLabels),
|
|
7340
|
+
);
|
|
7343
7341
|
const laidOutBpcGraph = layoutSchematicGraph(targetBpcGraph, {
|
|
7344
7342
|
singletonKeys: ["vcc/2", "gnd/2"],
|
|
7345
7343
|
centerPinColors: ["netlabel_center", "component_center"],
|
|
7346
|
-
|
|
7344
|
+
floatingBoxIdsWithMutablePinOffsets: new Set(
|
|
7345
|
+
targetBpcGraph.boxes.filter((box) => {
|
|
7346
|
+
const boxPins = targetBpcGraph.pins.filter(
|
|
7347
|
+
(p) => p.boxId === box.boxId
|
|
7348
|
+
);
|
|
7349
|
+
const nonCenterBoxPins = boxPins.filter(
|
|
7350
|
+
(bp) => !bp.color.includes("center")
|
|
7351
|
+
);
|
|
7352
|
+
if (nonCenterBoxPins.length <= 2) {
|
|
7353
|
+
return true;
|
|
7354
|
+
}
|
|
7355
|
+
return false;
|
|
7356
|
+
}).map((b) => b.boxId)
|
|
7357
|
+
),
|
|
7358
|
+
corpus: corpusNoNetLabel
|
|
7347
7359
|
});
|
|
7360
|
+
if (debug4.enabled) {
|
|
7361
|
+
global.debugGraphics?.push(
|
|
7362
|
+
getGraphicsForBpcGraph(laidOutBpcGraph, {
|
|
7363
|
+
title: "laidOutBpcGraph"
|
|
7364
|
+
})
|
|
7365
|
+
);
|
|
7366
|
+
}
|
|
7348
7367
|
const groupOffset = group._getGlobalSchematicPositionBeforeLayout();
|
|
7349
7368
|
for (const box of laidOutBpcGraph.boxes) {
|
|
7350
7369
|
if (!box.center) continue;
|
|
@@ -7394,36 +7413,6 @@ function Group_doInitialSchematicLayoutMatchAdapt(group) {
|
|
|
7394
7413
|
};
|
|
7395
7414
|
continue;
|
|
7396
7415
|
}
|
|
7397
|
-
if (generatedNetLabels.has(box.boxId)) {
|
|
7398
|
-
const { schematic_net_label: generatedNetLabel, schematic_port } = generatedNetLabels.get(box.boxId);
|
|
7399
|
-
const pins = laidOutBpcGraph.pins.filter((p) => p.boxId === box.boxId);
|
|
7400
|
-
const center = pins.find((p) => p.color === "netlabel_center");
|
|
7401
|
-
const anchor = pins.find((p) => p.color !== "netlabel_center");
|
|
7402
|
-
const color = anchor.color;
|
|
7403
|
-
const symbolName = color === "vcc" ? "vcc" : color === "gnd" ? "gnd" : void 0;
|
|
7404
|
-
const anchorSide = color === "vcc" ? "bottom" : color === "gnd" ? "top" : oppositeSideFromFacing[schematic_port.facing_direction] ?? "right";
|
|
7405
|
-
const source_net = db.source_net.get(generatedNetLabel.source_net_id);
|
|
7406
|
-
const schematic_net_label2 = {
|
|
7407
|
-
type: "schematic_net_label",
|
|
7408
|
-
schematic_net_label_id: `netlabel_for_${box.boxId}`,
|
|
7409
|
-
text: source_net.name,
|
|
7410
|
-
// no text; just a placeholder box for Match-Adapt
|
|
7411
|
-
anchor_position: {
|
|
7412
|
-
x: box.center.x + groupOffset.x + center.offset.x,
|
|
7413
|
-
y: box.center.y + groupOffset.y + center.offset.y
|
|
7414
|
-
},
|
|
7415
|
-
center: {
|
|
7416
|
-
x: box.center.x + groupOffset.x + center.offset.x,
|
|
7417
|
-
y: box.center.y + groupOffset.y + center.offset.y
|
|
7418
|
-
},
|
|
7419
|
-
anchor_side: anchorSide,
|
|
7420
|
-
symbol_name: symbolName,
|
|
7421
|
-
source_net_id: generatedNetLabel.source_net_id,
|
|
7422
|
-
source_trace_id: generatedNetLabel.source_trace_id
|
|
7423
|
-
};
|
|
7424
|
-
db.schematic_net_label.insert(schematic_net_label2);
|
|
7425
|
-
continue;
|
|
7426
|
-
}
|
|
7427
7416
|
console.error(
|
|
7428
7417
|
`No schematic element found for box: ${box.boxId}. This is a bug in the matchAdapt binding with @tscircuit/core`
|
|
7429
7418
|
);
|
|
@@ -7924,20 +7913,20 @@ var Group = class extends NormalComponent {
|
|
|
7924
7913
|
return false;
|
|
7925
7914
|
}
|
|
7926
7915
|
_hasTracesToRoute() {
|
|
7927
|
-
const
|
|
7916
|
+
const debug5 = Debug6("tscircuit:core:_hasTracesToRoute");
|
|
7928
7917
|
const traces = this.selectAll("trace");
|
|
7929
|
-
|
|
7918
|
+
debug5(`[${this.getString()}] has ${traces.length} traces to route`);
|
|
7930
7919
|
return traces.length > 0;
|
|
7931
7920
|
}
|
|
7932
7921
|
async _runEffectMakeHttpAutoroutingRequest() {
|
|
7933
7922
|
const { db } = this.root;
|
|
7934
|
-
const
|
|
7923
|
+
const debug5 = Debug6("tscircuit:core:_runEffectMakeHttpAutoroutingRequest");
|
|
7935
7924
|
const props = this._parsedProps;
|
|
7936
7925
|
const autorouterConfig = this._getAutorouterConfig();
|
|
7937
7926
|
const serverUrl = autorouterConfig.serverUrl;
|
|
7938
7927
|
const serverMode = autorouterConfig.serverMode;
|
|
7939
7928
|
const fetchWithDebug = (url, options) => {
|
|
7940
|
-
|
|
7929
|
+
debug5("fetching", url);
|
|
7941
7930
|
if (options.headers) {
|
|
7942
7931
|
options.headers["Tscircuit-Core-Version"] = this.root?.getCoreVersion();
|
|
7943
7932
|
}
|
|
@@ -8053,8 +8042,8 @@ var Group = class extends NormalComponent {
|
|
|
8053
8042
|
async _runLocalAutorouting() {
|
|
8054
8043
|
const { db } = this.root;
|
|
8055
8044
|
const props = this._parsedProps;
|
|
8056
|
-
const
|
|
8057
|
-
|
|
8045
|
+
const debug5 = Debug6("tscircuit:core:_runLocalAutorouting");
|
|
8046
|
+
debug5(`[${this.getString()}] starting local autorouting`);
|
|
8058
8047
|
const autorouterConfig = this._getAutorouterConfig();
|
|
8059
8048
|
const { simpleRouteJson } = getSimpleRouteJsonFromCircuitJson({
|
|
8060
8049
|
db,
|
|
@@ -8079,11 +8068,11 @@ var Group = class extends NormalComponent {
|
|
|
8079
8068
|
const routingPromise = new Promise(
|
|
8080
8069
|
(resolve, reject) => {
|
|
8081
8070
|
autorouter.on("complete", (event) => {
|
|
8082
|
-
|
|
8071
|
+
debug5(`[${this.getString()}] local autorouting complete`);
|
|
8083
8072
|
resolve(event.traces);
|
|
8084
8073
|
});
|
|
8085
8074
|
autorouter.on("error", (event) => {
|
|
8086
|
-
|
|
8075
|
+
debug5(
|
|
8087
8076
|
`[${this.getString()}] local autorouting error: ${event.error.message}`
|
|
8088
8077
|
);
|
|
8089
8078
|
reject(event.error);
|
|
@@ -8140,30 +8129,30 @@ var Group = class extends NormalComponent {
|
|
|
8140
8129
|
}
|
|
8141
8130
|
}
|
|
8142
8131
|
doInitialPcbTraceRender() {
|
|
8143
|
-
const
|
|
8132
|
+
const debug5 = Debug6("tscircuit:core:doInitialPcbTraceRender");
|
|
8144
8133
|
if (!this.isSubcircuit) return;
|
|
8145
8134
|
if (this.root?.pcbDisabled) return;
|
|
8146
8135
|
if (this.getInheritedProperty("routingDisabled")) return;
|
|
8147
8136
|
if (this._shouldUseTraceByTraceRouting()) return;
|
|
8148
8137
|
if (!this._areChildSubcircuitsRouted()) {
|
|
8149
|
-
|
|
8138
|
+
debug5(
|
|
8150
8139
|
`[${this.getString()}] child subcircuits are not routed, skipping async autorouting until subcircuits routed`
|
|
8151
8140
|
);
|
|
8152
8141
|
return;
|
|
8153
8142
|
}
|
|
8154
|
-
|
|
8143
|
+
debug5(
|
|
8155
8144
|
`[${this.getString()}] no child subcircuits to wait for, initiating async routing`
|
|
8156
8145
|
);
|
|
8157
8146
|
if (!this._hasTracesToRoute()) return;
|
|
8158
8147
|
this._startAsyncAutorouting();
|
|
8159
8148
|
}
|
|
8160
8149
|
updatePcbTraceRender() {
|
|
8161
|
-
const
|
|
8162
|
-
|
|
8150
|
+
const debug5 = Debug6("tscircuit:core:updatePcbTraceRender");
|
|
8151
|
+
debug5(`[${this.getString()}] updating...`);
|
|
8163
8152
|
if (!this.isSubcircuit) return;
|
|
8164
8153
|
if (this._shouldRouteAsync() && this._hasTracesToRoute() && !this._hasStartedAsyncAutorouting) {
|
|
8165
8154
|
if (this._areChildSubcircuitsRouted()) {
|
|
8166
|
-
|
|
8155
|
+
debug5(
|
|
8167
8156
|
`[${this.getString()}] child subcircuits are now routed, starting async autorouting`
|
|
8168
8157
|
);
|
|
8169
8158
|
this._startAsyncAutorouting();
|
|
@@ -8174,14 +8163,14 @@ var Group = class extends NormalComponent {
|
|
|
8174
8163
|
if (this._shouldUseTraceByTraceRouting()) return;
|
|
8175
8164
|
const { db } = this.root;
|
|
8176
8165
|
if (this._asyncAutoroutingResult.output_simple_route_json) {
|
|
8177
|
-
|
|
8166
|
+
debug5(
|
|
8178
8167
|
`[${this.getString()}] updating PCB traces from simple route json (${this._asyncAutoroutingResult.output_simple_route_json.traces?.length} traces)`
|
|
8179
8168
|
);
|
|
8180
8169
|
this._updatePcbTraceRenderFromSimpleRouteJson();
|
|
8181
8170
|
return;
|
|
8182
8171
|
}
|
|
8183
8172
|
if (this._asyncAutoroutingResult.output_pcb_traces) {
|
|
8184
|
-
|
|
8173
|
+
debug5(
|
|
8185
8174
|
`[${this.getString()}] updating PCB traces from ${this._asyncAutoroutingResult.output_pcb_traces.length} traces`
|
|
8186
8175
|
);
|
|
8187
8176
|
this._updatePcbTraceRenderFromPcbTraces();
|
|
@@ -8653,13 +8642,13 @@ var Capacitor = class extends NormalComponent {
|
|
|
8653
8642
|
doInitialCreateTracesFromProps() {
|
|
8654
8643
|
if (this.props.decouplingFor && this.props.decouplingTo) {
|
|
8655
8644
|
this.add(
|
|
8656
|
-
new
|
|
8645
|
+
new Trace3({
|
|
8657
8646
|
from: `${this.getSubcircuitSelector()} > port.1`,
|
|
8658
8647
|
to: this.props.decouplingFor
|
|
8659
8648
|
})
|
|
8660
8649
|
);
|
|
8661
8650
|
this.add(
|
|
8662
|
-
new
|
|
8651
|
+
new Trace3({
|
|
8663
8652
|
from: `${this.getSubcircuitSelector()} > port.2`,
|
|
8664
8653
|
to: this.props.decouplingTo
|
|
8665
8654
|
})
|
|
@@ -8735,7 +8724,7 @@ var Chip = class extends NormalComponent {
|
|
|
8735
8724
|
if (props.externallyConnectedPins) {
|
|
8736
8725
|
for (const [pin1, pin2] of props.externallyConnectedPins) {
|
|
8737
8726
|
this.add(
|
|
8738
|
-
new
|
|
8727
|
+
new Trace3({
|
|
8739
8728
|
from: `${this.getSubcircuitSelector()} > port.${pin1}`,
|
|
8740
8729
|
to: `${this.getSubcircuitSelector()} > port.${pin2}`
|
|
8741
8730
|
})
|
|
@@ -9192,13 +9181,13 @@ var Resistor = class extends NormalComponent {
|
|
|
9192
9181
|
doInitialCreateTracesFromProps() {
|
|
9193
9182
|
if (this.props.pullupFor && this.props.pullupTo) {
|
|
9194
9183
|
this.add(
|
|
9195
|
-
new
|
|
9184
|
+
new Trace3({
|
|
9196
9185
|
from: `${this.getSubcircuitSelector()} > port.1`,
|
|
9197
9186
|
to: this.props.pullupFor
|
|
9198
9187
|
})
|
|
9199
9188
|
);
|
|
9200
9189
|
this.add(
|
|
9201
|
-
new
|
|
9190
|
+
new Trace3({
|
|
9202
9191
|
from: `${this.getSubcircuitSelector()} > port.2`,
|
|
9203
9192
|
to: this.props.pullupTo
|
|
9204
9193
|
})
|
|
@@ -9206,13 +9195,13 @@ var Resistor = class extends NormalComponent {
|
|
|
9206
9195
|
}
|
|
9207
9196
|
if (this.props.pulldownFor && this.props.pulldownTo) {
|
|
9208
9197
|
this.add(
|
|
9209
|
-
new
|
|
9198
|
+
new Trace3({
|
|
9210
9199
|
from: `${this.getSubcircuitSelector()} > port.1`,
|
|
9211
9200
|
to: this.props.pulldownFor
|
|
9212
9201
|
})
|
|
9213
9202
|
);
|
|
9214
9203
|
this.add(
|
|
9215
|
-
new
|
|
9204
|
+
new Trace3({
|
|
9216
9205
|
from: `${this.getSubcircuitSelector()} > port.2`,
|
|
9217
9206
|
to: this.props.pulldownTo
|
|
9218
9207
|
})
|
|
@@ -9611,7 +9600,7 @@ var NetLabel = class extends PrimitiveComponent2 {
|
|
|
9611
9600
|
if (!connectsTo) return;
|
|
9612
9601
|
for (const connection of connectsTo) {
|
|
9613
9602
|
this.add(
|
|
9614
|
-
new
|
|
9603
|
+
new Trace3({
|
|
9615
9604
|
from: connection,
|
|
9616
9605
|
to: `net.${this._getNetName()}`
|
|
9617
9606
|
})
|
|
@@ -10725,7 +10714,7 @@ import { identity as identity5 } from "transformation-matrix";
|
|
|
10725
10714
|
var package_default = {
|
|
10726
10715
|
name: "@tscircuit/core",
|
|
10727
10716
|
type: "module",
|
|
10728
|
-
version: "0.0.
|
|
10717
|
+
version: "0.0.551",
|
|
10729
10718
|
types: "dist/index.d.ts",
|
|
10730
10719
|
main: "dist/index.js",
|
|
10731
10720
|
module: "dist/index.js",
|
|
@@ -10759,7 +10748,7 @@ var package_default = {
|
|
|
10759
10748
|
"@tscircuit/math-utils": "^0.0.18",
|
|
10760
10749
|
"@tscircuit/props": "^0.0.251",
|
|
10761
10750
|
"@tscircuit/schematic-autolayout": "^0.0.6",
|
|
10762
|
-
"@tscircuit/schematic-corpus": "^0.0.
|
|
10751
|
+
"@tscircuit/schematic-corpus": "^0.0.52",
|
|
10763
10752
|
"@tscircuit/schematic-match-adapt": "^0.0.16",
|
|
10764
10753
|
"@tscircuit/simple-3d-svg": "^0.0.6",
|
|
10765
10754
|
"@types/bun": "^1.2.16",
|
|
@@ -10767,18 +10756,18 @@ var package_default = {
|
|
|
10767
10756
|
"@types/react": "^19.0.1",
|
|
10768
10757
|
"@types/react-dom": "^19.0.2",
|
|
10769
10758
|
"@types/react-reconciler": "^0.28.9",
|
|
10770
|
-
"bpc-graph": "^0.0.
|
|
10759
|
+
"bpc-graph": "^0.0.53",
|
|
10771
10760
|
"bun-match-svg": "0.0.12",
|
|
10772
10761
|
"calculate-elbow": "^0.0.5",
|
|
10773
10762
|
"chokidar-cli": "^3.0.0",
|
|
10774
10763
|
"circuit-json": "^0.0.215",
|
|
10775
|
-
"circuit-json-to-bpc": "^0.0.
|
|
10764
|
+
"circuit-json-to-bpc": "^0.0.13",
|
|
10776
10765
|
"circuit-json-to-connectivity-map": "^0.0.22",
|
|
10777
10766
|
"circuit-json-to-simple-3d": "^0.0.2",
|
|
10778
10767
|
"circuit-to-svg": "^0.0.162",
|
|
10779
10768
|
concurrently: "^9.1.2",
|
|
10780
10769
|
debug: "^4.3.6",
|
|
10781
|
-
"graphics-debug": "^0.0.
|
|
10770
|
+
"graphics-debug": "^0.0.60",
|
|
10782
10771
|
howfat: "^0.3.8",
|
|
10783
10772
|
"live-server": "^1.2.2",
|
|
10784
10773
|
"looks-same": "^9.0.1",
|
|
@@ -11258,7 +11247,7 @@ export {
|
|
|
11258
11247
|
Subcircuit,
|
|
11259
11248
|
Switch,
|
|
11260
11249
|
TestPoint,
|
|
11261
|
-
|
|
11250
|
+
Trace3 as Trace,
|
|
11262
11251
|
TraceHint,
|
|
11263
11252
|
Transistor,
|
|
11264
11253
|
Via,
|