@tscircuit/core 0.0.549 → 0.0.551
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 +1241 -1209
- package/package.json +1 -1
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,135 +4370,1129 @@ 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
|
-
};
|
|
4788
|
-
}
|
|
4789
|
-
_getTracePortOrNetSelectorListFromProps() {
|
|
4790
|
-
if ("from" in this.props && "to" in this.props) {
|
|
4791
|
-
return [
|
|
4792
|
-
typeof this.props.from === "string" ? this.props.from : this.props.from.getPortSelector(),
|
|
4793
|
-
typeof this.props.to === "string" ? this.props.to : this.props.to.getPortSelector()
|
|
4794
|
-
];
|
|
4795
|
-
}
|
|
4796
|
-
if ("path" in this.props) {
|
|
4797
|
-
return this.props.path.map(
|
|
4798
|
-
(p) => typeof p === "string" ? p : p.getPortSelector()
|
|
4799
|
-
);
|
|
4800
|
-
}
|
|
4801
|
-
return [];
|
|
4802
|
-
}
|
|
4803
|
-
getTracePortPathSelectors() {
|
|
4804
|
-
return this._getTracePortOrNetSelectorListFromProps().filter(
|
|
4805
|
-
(selector) => !selector.includes("net.")
|
|
4806
|
-
);
|
|
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;
|
|
4807
4389
|
}
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
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
|
|
4811
4396
|
);
|
|
4812
|
-
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
const { _parsedProps: props, parent } = this;
|
|
4816
|
-
if (!parent) throw new Error("Trace has no parent");
|
|
4817
|
-
const portSelectors = this.getTracePortPathSelectors();
|
|
4818
|
-
const portsWithSelectors = portSelectors.map((selector) => ({
|
|
4819
|
-
selector,
|
|
4820
|
-
port: this.getSubcircuit().selectOne(selector, { type: "port" }) ?? null
|
|
4821
|
-
}));
|
|
4822
|
-
for (const { selector, port } of portsWithSelectors) {
|
|
4823
|
-
if (!port) {
|
|
4824
|
-
let parentSelector;
|
|
4825
|
-
let portToken;
|
|
4826
|
-
const dotIndex = selector.lastIndexOf(".");
|
|
4827
|
-
if (dotIndex !== -1 && dotIndex > selector.lastIndexOf(" ")) {
|
|
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
|
-
}
|
|
4397
|
+
const isSameNet = otherSourceTrace?.subcircuit_connectivity_map_key === mySourceTrace.subcircuit_connectivity_map_key;
|
|
4398
|
+
if (differentNetOnly && isSameNet) {
|
|
4399
|
+
continue;
|
|
4870
4400
|
}
|
|
4871
|
-
if (
|
|
4872
|
-
|
|
4401
|
+
if (sameNetOnly && !isSameNet) {
|
|
4402
|
+
continue;
|
|
4873
4403
|
}
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
if (
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
|
|
4404
|
+
traces.push(otherSchematicTrace);
|
|
4405
|
+
}
|
|
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
|
+
);
|
|
4421
|
+
}
|
|
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
|
+
);
|
|
5468
|
+
}
|
|
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);
|
|
5483
|
+
}
|
|
5484
|
+
_resolveNet(selector) {
|
|
5485
|
+
const direct = this.getSubcircuit().selectOne(selector, {
|
|
5486
|
+
type: "net"
|
|
5487
|
+
});
|
|
5488
|
+
if (direct) return direct;
|
|
5489
|
+
const match = selector.match(/^net\.(.+)$/);
|
|
5490
|
+
const netName = match ? match[1] : null;
|
|
5491
|
+
if (!netName) return null;
|
|
5492
|
+
const allDescendants = this.root._getBoard().getDescendants();
|
|
5493
|
+
return allDescendants.find(
|
|
5494
|
+
(d) => d.componentName === "Net" && d._parsedProps.name === netName
|
|
5495
|
+
) || null;
|
|
4892
5496
|
}
|
|
4893
5497
|
_findConnectedNets() {
|
|
4894
5498
|
const netsWithSelectors = this.getTracePathNetSelectors().map(
|
|
@@ -4944,416 +5548,63 @@ var Trace2 = class extends PrimitiveComponent2 {
|
|
|
4944
5548
|
const { allPortsFound, ports } = this._findConnectedPorts();
|
|
4945
5549
|
if (!allPortsFound || !ports) return null;
|
|
4946
5550
|
const sortedPorts = [...ports].sort(
|
|
4947
|
-
(a, b) => (a.pcb_port_id || "").localeCompare(b.pcb_port_id || "")
|
|
4948
|
-
);
|
|
4949
|
-
const allIds = sortedPorts.map((p) => p.pcb_port_id);
|
|
4950
|
-
return allIds.join(",");
|
|
4951
|
-
}
|
|
4952
|
-
doInitialSourceTraceRender() {
|
|
4953
|
-
const { db } = this.root;
|
|
4954
|
-
const { _parsedProps: props, parent } = this;
|
|
4955
|
-
if (!parent) {
|
|
4956
|
-
this.renderError("Trace has no parent");
|
|
4957
|
-
return;
|
|
4958
|
-
}
|
|
4959
|
-
const { allPortsFound, portsWithSelectors: ports } = this._findConnectedPorts();
|
|
4960
|
-
if (!allPortsFound) return;
|
|
4961
|
-
this._traceConnectionHash = this._computeTraceConnectionHash();
|
|
4962
|
-
const existingTraces = db.source_trace.list();
|
|
4963
|
-
const existingTrace = existingTraces.find(
|
|
4964
|
-
(t) => t.subcircuit_connectivity_map_key === this.subcircuit_connectivity_map_key && t.connected_source_port_ids.sort().join(",") === this._traceConnectionHash
|
|
4965
|
-
);
|
|
4966
|
-
if (existingTrace) {
|
|
4967
|
-
this.source_trace_id = existingTrace.source_trace_id;
|
|
4968
|
-
return;
|
|
4969
|
-
}
|
|
4970
|
-
const nets = this._findConnectedNets().nets;
|
|
4971
|
-
const displayName = getTraceDisplayName({ ports, nets });
|
|
4972
|
-
const trace = db.source_trace.insert({
|
|
4973
|
-
connected_source_port_ids: ports.map((p) => p.port.source_port_id),
|
|
4974
|
-
connected_source_net_ids: nets.map((n) => n.source_net_id),
|
|
4975
|
-
subcircuit_id: this.getSubcircuit()?.subcircuit_id,
|
|
4976
|
-
max_length: getMaxLengthFromConnectedCapacitors(
|
|
4977
|
-
ports.map((p) => p.port),
|
|
4978
|
-
{ db }
|
|
4979
|
-
) ?? props.maxLength,
|
|
4980
|
-
display_name: displayName,
|
|
4981
|
-
min_trace_thickness: props.thickness
|
|
4982
|
-
});
|
|
4983
|
-
this.source_trace_id = trace.source_trace_id;
|
|
4984
|
-
}
|
|
4985
|
-
_insertErrorIfTraceIsOutsideBoard(mergedRoute, ports) {
|
|
4986
|
-
const { db } = this.root;
|
|
4987
|
-
const isOutsideBoard = isRouteOutsideBoard(mergedRoute, { db });
|
|
4988
|
-
if (isOutsideBoard) {
|
|
4989
|
-
db.pcb_trace_error.insert({
|
|
4990
|
-
error_type: "pcb_trace_error",
|
|
4991
|
-
source_trace_id: this.source_trace_id,
|
|
4992
|
-
message: `Trace ${this.getString()} routed outside the board boundaries.`,
|
|
4993
|
-
pcb_trace_id: this.pcb_trace_id,
|
|
4994
|
-
pcb_component_ids: [],
|
|
4995
|
-
pcb_port_ids: ports.map((p) => p.pcb_port_id)
|
|
4996
|
-
});
|
|
4997
|
-
}
|
|
4998
|
-
}
|
|
4999
|
-
doInitialPcbTraceRender() {
|
|
5000
|
-
if (this.root?.pcbDisabled) return;
|
|
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
|
-
)
|
|
5551
|
+
(a, b) => (a.pcb_port_id || "").localeCompare(b.pcb_port_id || "")
|
|
5088
5552
|
);
|
|
5089
|
-
|
|
5553
|
+
const allIds = sortedPorts.map((p) => p.pcb_port_id);
|
|
5554
|
+
return allIds.join(",");
|
|
5555
|
+
}
|
|
5556
|
+
doInitialSourceTraceRender() {
|
|
5557
|
+
const { db } = this.root;
|
|
5558
|
+
const { _parsedProps: props, parent } = this;
|
|
5559
|
+
if (!parent) {
|
|
5560
|
+
this.renderError("Trace has no parent");
|
|
5090
5561
|
return;
|
|
5091
5562
|
}
|
|
5092
|
-
|
|
5093
|
-
if (
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
} else {
|
|
5099
|
-
orderedRouteObjectives = [
|
|
5100
|
-
portToObjective(ports[0]),
|
|
5101
|
-
...pcbRouteHints,
|
|
5102
|
-
portToObjective(ports[1])
|
|
5103
|
-
];
|
|
5104
|
-
}
|
|
5105
|
-
const candidateLayerCombinations = findPossibleTraceLayerCombinations(
|
|
5106
|
-
orderedRouteObjectives
|
|
5563
|
+
const { allPortsFound, portsWithSelectors: ports } = this._findConnectedPorts();
|
|
5564
|
+
if (!allPortsFound) return;
|
|
5565
|
+
this._traceConnectionHash = this._computeTraceConnectionHash();
|
|
5566
|
+
const existingTraces = db.source_trace.list();
|
|
5567
|
+
const existingTrace = existingTraces.find(
|
|
5568
|
+
(t) => t.subcircuit_connectivity_map_key === this.subcircuit_connectivity_map_key && t.connected_source_port_ids.sort().join(",") === this._traceConnectionHash
|
|
5107
5569
|
);
|
|
5108
|
-
if (
|
|
5109
|
-
this.
|
|
5110
|
-
`Could not find a common layer (using hints) for trace ${this.getString()}`
|
|
5111
|
-
);
|
|
5570
|
+
if (existingTrace) {
|
|
5571
|
+
this.source_trace_id = existingTrace.source_trace_id;
|
|
5112
5572
|
return;
|
|
5113
5573
|
}
|
|
5114
|
-
const
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
() =>
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
|
|
5123
|
-
|
|
5574
|
+
const nets = this._findConnectedNets().nets;
|
|
5575
|
+
const displayName = getTraceDisplayName({ ports, nets });
|
|
5576
|
+
const trace = db.source_trace.insert({
|
|
5577
|
+
connected_source_port_ids: ports.map((p) => p.port.source_port_id),
|
|
5578
|
+
connected_source_net_ids: nets.map((n) => n.source_net_id),
|
|
5579
|
+
subcircuit_id: this.getSubcircuit()?.subcircuit_id,
|
|
5580
|
+
max_length: getMaxLengthFromConnectedCapacitors(
|
|
5581
|
+
ports.map((p) => p.port),
|
|
5582
|
+
{ db }
|
|
5583
|
+
) ?? props.maxLength,
|
|
5584
|
+
display_name: displayName,
|
|
5585
|
+
min_trace_thickness: props.thickness
|
|
5586
|
+
});
|
|
5587
|
+
this.source_trace_id = trace.source_trace_id;
|
|
5588
|
+
}
|
|
5589
|
+
_insertErrorIfTraceIsOutsideBoard(mergedRoute, ports) {
|
|
5590
|
+
const { db } = this.root;
|
|
5591
|
+
const isOutsideBoard = isRouteOutsideBoard(mergedRoute, { db });
|
|
5592
|
+
if (isOutsideBoard) {
|
|
5593
|
+
db.pcb_trace_error.insert({
|
|
5124
5594
|
error_type: "pcb_trace_error",
|
|
5125
|
-
pcb_trace_error_id: this.pcb_trace_id,
|
|
5126
|
-
message: `Error getting obstacles for autorouting: ${errGettingObstacles.message}`,
|
|
5127
5595
|
source_trace_id: this.source_trace_id,
|
|
5128
|
-
|
|
5129
|
-
pcb_port_ids: ports.map((p) => p.pcb_port_id),
|
|
5596
|
+
message: `Trace ${this.getString()} routed outside the board boundaries.`,
|
|
5130
5597
|
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
|
-
}
|
|
5598
|
+
pcb_component_ids: [],
|
|
5599
|
+
pcb_port_ids: ports.map((p) => p.pcb_port_id)
|
|
5196
5600
|
});
|
|
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
5601
|
}
|
|
5270
|
-
|
|
5602
|
+
}
|
|
5603
|
+
doInitialPcbTraceRender() {
|
|
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
|
})
|
|
@@ -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(),
|
|
@@ -7725,6 +7748,53 @@ function Group_doInitialPcbLayoutGrid(group) {
|
|
|
7725
7748
|
}
|
|
7726
7749
|
}
|
|
7727
7750
|
|
|
7751
|
+
// lib/utils/autorouting/getPresetAutoroutingConfig.ts
|
|
7752
|
+
function getPresetAutoroutingConfig(autorouterConfig) {
|
|
7753
|
+
const defaults = {
|
|
7754
|
+
serverUrl: "https://registry-api.tscircuit.com",
|
|
7755
|
+
serverMode: "job",
|
|
7756
|
+
serverCacheEnabled: true
|
|
7757
|
+
};
|
|
7758
|
+
if (typeof autorouterConfig === "object" && !autorouterConfig.preset) {
|
|
7759
|
+
return {
|
|
7760
|
+
local: !(autorouterConfig.serverUrl || autorouterConfig.serverMode || autorouterConfig.serverCacheEnabled),
|
|
7761
|
+
...defaults,
|
|
7762
|
+
...autorouterConfig
|
|
7763
|
+
};
|
|
7764
|
+
}
|
|
7765
|
+
const preset = typeof autorouterConfig === "object" ? autorouterConfig.preset : autorouterConfig;
|
|
7766
|
+
switch (preset) {
|
|
7767
|
+
case "auto-local":
|
|
7768
|
+
return {
|
|
7769
|
+
local: true,
|
|
7770
|
+
groupMode: "subcircuit"
|
|
7771
|
+
};
|
|
7772
|
+
case "sequential-trace":
|
|
7773
|
+
return {
|
|
7774
|
+
local: true,
|
|
7775
|
+
groupMode: "sequential-trace"
|
|
7776
|
+
};
|
|
7777
|
+
case "subcircuit":
|
|
7778
|
+
return {
|
|
7779
|
+
local: true,
|
|
7780
|
+
groupMode: "subcircuit"
|
|
7781
|
+
};
|
|
7782
|
+
case "auto-cloud":
|
|
7783
|
+
return {
|
|
7784
|
+
local: false,
|
|
7785
|
+
groupMode: "subcircuit",
|
|
7786
|
+
serverUrl: defaults.serverUrl,
|
|
7787
|
+
serverMode: defaults.serverMode,
|
|
7788
|
+
serverCacheEnabled: true
|
|
7789
|
+
};
|
|
7790
|
+
default:
|
|
7791
|
+
return {
|
|
7792
|
+
local: true,
|
|
7793
|
+
groupMode: "subcircuit"
|
|
7794
|
+
};
|
|
7795
|
+
}
|
|
7796
|
+
}
|
|
7797
|
+
|
|
7728
7798
|
// lib/components/primitive-components/Group/Group.ts
|
|
7729
7799
|
var Group = class extends NormalComponent {
|
|
7730
7800
|
pcb_group_id = null;
|
|
@@ -8327,46 +8397,8 @@ var Group = class extends NormalComponent {
|
|
|
8327
8397
|
};
|
|
8328
8398
|
}
|
|
8329
8399
|
_getAutorouterConfig() {
|
|
8330
|
-
const
|
|
8331
|
-
|
|
8332
|
-
serverMode: "job",
|
|
8333
|
-
serverCacheEnabled: true
|
|
8334
|
-
};
|
|
8335
|
-
const autorouter = this._parsedProps.autorouter || this._parsedProps.autorouter?.preset || this.getInheritedProperty("autorouter");
|
|
8336
|
-
if (typeof autorouter === "object") {
|
|
8337
|
-
return {
|
|
8338
|
-
local: !(autorouter.serverUrl || autorouter.serverMode || autorouter.serverCacheEnabled),
|
|
8339
|
-
...defaults,
|
|
8340
|
-
...autorouter
|
|
8341
|
-
};
|
|
8342
|
-
}
|
|
8343
|
-
if (autorouter === "auto-local")
|
|
8344
|
-
return {
|
|
8345
|
-
local: true,
|
|
8346
|
-
groupMode: "subcircuit"
|
|
8347
|
-
};
|
|
8348
|
-
if (autorouter === "sequential-trace")
|
|
8349
|
-
return {
|
|
8350
|
-
local: true,
|
|
8351
|
-
groupMode: "sequential-trace"
|
|
8352
|
-
};
|
|
8353
|
-
if (autorouter === "subcircuit")
|
|
8354
|
-
return {
|
|
8355
|
-
local: true,
|
|
8356
|
-
groupMode: "subcircuit"
|
|
8357
|
-
};
|
|
8358
|
-
if (autorouter === "auto-cloud")
|
|
8359
|
-
return {
|
|
8360
|
-
local: false,
|
|
8361
|
-
groupMode: "subcircuit",
|
|
8362
|
-
serverUrl: defaults.serverUrl,
|
|
8363
|
-
serverMode: defaults.serverMode,
|
|
8364
|
-
serverCacheEnabled: true
|
|
8365
|
-
};
|
|
8366
|
-
return {
|
|
8367
|
-
local: true,
|
|
8368
|
-
groupMode: "subcircuit"
|
|
8369
|
-
};
|
|
8400
|
+
const autorouter = this._parsedProps.autorouter || this.getInheritedProperty("autorouter");
|
|
8401
|
+
return getPresetAutoroutingConfig(autorouter);
|
|
8370
8402
|
}
|
|
8371
8403
|
/**
|
|
8372
8404
|
* Trace-by-trace autorouting is where each trace routes itself in a well-known
|
|
@@ -8644,13 +8676,13 @@ var Capacitor = class extends NormalComponent {
|
|
|
8644
8676
|
doInitialCreateTracesFromProps() {
|
|
8645
8677
|
if (this.props.decouplingFor && this.props.decouplingTo) {
|
|
8646
8678
|
this.add(
|
|
8647
|
-
new
|
|
8679
|
+
new Trace3({
|
|
8648
8680
|
from: `${this.getSubcircuitSelector()} > port.1`,
|
|
8649
8681
|
to: this.props.decouplingFor
|
|
8650
8682
|
})
|
|
8651
8683
|
);
|
|
8652
8684
|
this.add(
|
|
8653
|
-
new
|
|
8685
|
+
new Trace3({
|
|
8654
8686
|
from: `${this.getSubcircuitSelector()} > port.2`,
|
|
8655
8687
|
to: this.props.decouplingTo
|
|
8656
8688
|
})
|
|
@@ -8726,7 +8758,7 @@ var Chip = class extends NormalComponent {
|
|
|
8726
8758
|
if (props.externallyConnectedPins) {
|
|
8727
8759
|
for (const [pin1, pin2] of props.externallyConnectedPins) {
|
|
8728
8760
|
this.add(
|
|
8729
|
-
new
|
|
8761
|
+
new Trace3({
|
|
8730
8762
|
from: `${this.getSubcircuitSelector()} > port.${pin1}`,
|
|
8731
8763
|
to: `${this.getSubcircuitSelector()} > port.${pin2}`
|
|
8732
8764
|
})
|
|
@@ -9183,13 +9215,13 @@ var Resistor = class extends NormalComponent {
|
|
|
9183
9215
|
doInitialCreateTracesFromProps() {
|
|
9184
9216
|
if (this.props.pullupFor && this.props.pullupTo) {
|
|
9185
9217
|
this.add(
|
|
9186
|
-
new
|
|
9218
|
+
new Trace3({
|
|
9187
9219
|
from: `${this.getSubcircuitSelector()} > port.1`,
|
|
9188
9220
|
to: this.props.pullupFor
|
|
9189
9221
|
})
|
|
9190
9222
|
);
|
|
9191
9223
|
this.add(
|
|
9192
|
-
new
|
|
9224
|
+
new Trace3({
|
|
9193
9225
|
from: `${this.getSubcircuitSelector()} > port.2`,
|
|
9194
9226
|
to: this.props.pullupTo
|
|
9195
9227
|
})
|
|
@@ -9197,13 +9229,13 @@ var Resistor = class extends NormalComponent {
|
|
|
9197
9229
|
}
|
|
9198
9230
|
if (this.props.pulldownFor && this.props.pulldownTo) {
|
|
9199
9231
|
this.add(
|
|
9200
|
-
new
|
|
9232
|
+
new Trace3({
|
|
9201
9233
|
from: `${this.getSubcircuitSelector()} > port.1`,
|
|
9202
9234
|
to: this.props.pulldownFor
|
|
9203
9235
|
})
|
|
9204
9236
|
);
|
|
9205
9237
|
this.add(
|
|
9206
|
-
new
|
|
9238
|
+
new Trace3({
|
|
9207
9239
|
from: `${this.getSubcircuitSelector()} > port.2`,
|
|
9208
9240
|
to: this.props.pulldownTo
|
|
9209
9241
|
})
|
|
@@ -9602,7 +9634,7 @@ var NetLabel = class extends PrimitiveComponent2 {
|
|
|
9602
9634
|
if (!connectsTo) return;
|
|
9603
9635
|
for (const connection of connectsTo) {
|
|
9604
9636
|
this.add(
|
|
9605
|
-
new
|
|
9637
|
+
new Trace3({
|
|
9606
9638
|
from: connection,
|
|
9607
9639
|
to: `net.${this._getNetName()}`
|
|
9608
9640
|
})
|
|
@@ -10716,7 +10748,7 @@ import { identity as identity5 } from "transformation-matrix";
|
|
|
10716
10748
|
var package_default = {
|
|
10717
10749
|
name: "@tscircuit/core",
|
|
10718
10750
|
type: "module",
|
|
10719
|
-
version: "0.0.
|
|
10751
|
+
version: "0.0.550",
|
|
10720
10752
|
types: "dist/index.d.ts",
|
|
10721
10753
|
main: "dist/index.js",
|
|
10722
10754
|
module: "dist/index.js",
|
|
@@ -11249,7 +11281,7 @@ export {
|
|
|
11249
11281
|
Subcircuit,
|
|
11250
11282
|
Switch,
|
|
11251
11283
|
TestPoint,
|
|
11252
|
-
|
|
11284
|
+
Trace3 as Trace,
|
|
11253
11285
|
TraceHint,
|
|
11254
11286
|
Transistor,
|
|
11255
11287
|
Via,
|