@tscircuit/schematic-trace-solver 0.0.80 → 0.0.82
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 +10 -2
- package/dist/index.js +132 -10
- package/lib/solvers/AvailableNetOrientationSolver/AvailableNetOrientationSolver.ts +184 -10
- package/lib/solvers/AvailableNetOrientationSolver/types.ts +6 -1
- package/package.json +1 -1
- package/tests/examples/__snapshots__/example46.snap.svg +4 -4
- package/tests/repros/__snapshots__/bugreport-001-gnd-overlap.snap.svg +219 -0
- package/tests/repros/assets/bugreport-001-gnd-overlap.input.json +163 -0
- package/tests/repros/bugreport-001-gnd-overlap.test.ts +16 -0
- package/tests/repros/rotated-components-rail-label.test.ts +68 -0
package/dist/index.d.ts
CHANGED
|
@@ -694,8 +694,8 @@ type CandidateLabel = {
|
|
|
694
694
|
width: number;
|
|
695
695
|
height: number;
|
|
696
696
|
};
|
|
697
|
-
type CandidateStatus$2 = "valid" | "chip-collision" | "text-collision" | "trace-collision" | "netlabel-collision";
|
|
698
|
-
type CandidatePhase = "rotate" | "shift" | "lateral-shift";
|
|
697
|
+
type CandidateStatus$2 = "valid" | "chip-collision" | "text-collision" | "trace-collision" | "trace-clearance-violation" | "netlabel-collision";
|
|
698
|
+
type CandidatePhase = "rotate" | "trace-anchor" | "shift" | "lateral-shift";
|
|
699
699
|
type EvaluatedCandidate = CandidateLabel & {
|
|
700
700
|
status: CandidateStatus$2;
|
|
701
701
|
selected: boolean;
|
|
@@ -733,6 +733,8 @@ declare class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
733
733
|
private setCurrentLabel;
|
|
734
734
|
private findCorrectedCandidate;
|
|
735
735
|
private findValidRotatedCandidate;
|
|
736
|
+
private findValidTraceAnchorCandidate;
|
|
737
|
+
private getTraceAnchorCandidatePoints;
|
|
736
738
|
private getAvailableOrientations;
|
|
737
739
|
private findValidShiftedCandidate;
|
|
738
740
|
/**
|
|
@@ -757,7 +759,13 @@ declare class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
757
759
|
private getNetLabelWidth;
|
|
758
760
|
private getNetLabelHeight;
|
|
759
761
|
private getCandidateStatus;
|
|
762
|
+
private isAcceptableTraceAnchorChipCollision;
|
|
760
763
|
private getBoundsStatus;
|
|
764
|
+
private isTraceTooCloseToLabel;
|
|
765
|
+
private getLabelTraceClearanceBounds;
|
|
766
|
+
private shouldCheckTraceClearanceForLabel;
|
|
767
|
+
private hasRoutedLabelOnSameNet;
|
|
768
|
+
private isPortOnlyLabel;
|
|
761
769
|
private intersectsAnyOtherNetLabel;
|
|
762
770
|
private sharesChipBoundary;
|
|
763
771
|
private getChipSideForPoint;
|
package/dist/index.js
CHANGED
|
@@ -6167,6 +6167,7 @@ var ensureGraphicsArrays = (graphics) => {
|
|
|
6167
6167
|
};
|
|
6168
6168
|
|
|
6169
6169
|
// lib/solvers/AvailableNetOrientationSolver/AvailableNetOrientationSolver.ts
|
|
6170
|
+
var LABEL_TRACE_CLEARANCE = 0.1;
|
|
6170
6171
|
var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
6171
6172
|
inputProblem;
|
|
6172
6173
|
traces;
|
|
@@ -6245,6 +6246,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6245
6246
|
this.addConnectorTrace(label, candidate, labelIndex);
|
|
6246
6247
|
}
|
|
6247
6248
|
addConnectorTrace(label, candidate, labelIndex) {
|
|
6249
|
+
if (candidate.phase === "trace-anchor") return;
|
|
6248
6250
|
const tracePath = this.getCandidateConnectorTrace(label, candidate);
|
|
6249
6251
|
if (tracePath.length < 2) return;
|
|
6250
6252
|
const mspPairId = `available-net-orientation-${labelIndex}-${label.netId ?? label.globalConnNetId}`;
|
|
@@ -6279,6 +6281,12 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6279
6281
|
orientations
|
|
6280
6282
|
);
|
|
6281
6283
|
if (rotatedCandidate) return rotatedCandidate;
|
|
6284
|
+
const traceAnchorCandidate = this.findValidTraceAnchorCandidate(
|
|
6285
|
+
label,
|
|
6286
|
+
orientations[0],
|
|
6287
|
+
labelIndex
|
|
6288
|
+
);
|
|
6289
|
+
if (traceAnchorCandidate) return traceAnchorCandidate;
|
|
6282
6290
|
const shiftedCandidate = this.findValidShiftedCandidate(
|
|
6283
6291
|
label,
|
|
6284
6292
|
orientations[0],
|
|
@@ -6312,6 +6320,46 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6312
6320
|
}
|
|
6313
6321
|
return null;
|
|
6314
6322
|
}
|
|
6323
|
+
findValidTraceAnchorCandidate(label, orientation, labelIndex) {
|
|
6324
|
+
const direction = dir(orientation);
|
|
6325
|
+
const candidatePoints = this.getTraceAnchorCandidatePoints(label).sort(
|
|
6326
|
+
(a, b) => {
|
|
6327
|
+
const aAlongDirection = a.x * direction.x + a.y * direction.y;
|
|
6328
|
+
const bAlongDirection = b.x * direction.x + b.y * direction.y;
|
|
6329
|
+
return bAlongDirection - aAlongDirection;
|
|
6330
|
+
}
|
|
6331
|
+
);
|
|
6332
|
+
for (const anchorPoint of candidatePoints) {
|
|
6333
|
+
const candidate = this.createCandidate(label, anchorPoint, orientation);
|
|
6334
|
+
const result = this.evaluateCandidate(
|
|
6335
|
+
candidate,
|
|
6336
|
+
label,
|
|
6337
|
+
labelIndex,
|
|
6338
|
+
"trace-anchor"
|
|
6339
|
+
);
|
|
6340
|
+
this.currentCandidateResults.push(result);
|
|
6341
|
+
if (result.status === "valid") {
|
|
6342
|
+
result.selected = true;
|
|
6343
|
+
return result;
|
|
6344
|
+
}
|
|
6345
|
+
}
|
|
6346
|
+
return null;
|
|
6347
|
+
}
|
|
6348
|
+
getTraceAnchorCandidatePoints(label) {
|
|
6349
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6350
|
+
const points = [];
|
|
6351
|
+
for (const traceId of label.mspConnectionPairIds ?? []) {
|
|
6352
|
+
const trace = this.traceMap[traceId];
|
|
6353
|
+
if (!trace) continue;
|
|
6354
|
+
for (const point of trace.tracePath) {
|
|
6355
|
+
const key = `${point.x.toFixed(9)},${point.y.toFixed(9)}`;
|
|
6356
|
+
if (seen.has(key)) continue;
|
|
6357
|
+
seen.add(key);
|
|
6358
|
+
points.push(point);
|
|
6359
|
+
}
|
|
6360
|
+
}
|
|
6361
|
+
return points;
|
|
6362
|
+
}
|
|
6315
6363
|
getAvailableOrientations(label) {
|
|
6316
6364
|
const effectiveNetId = label.netId ?? label.globalConnNetId;
|
|
6317
6365
|
return this.inputProblem.availableNetLabelOrientations[effectiveNetId] ?? [];
|
|
@@ -6580,11 +6628,28 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6580
6628
|
}
|
|
6581
6629
|
getCandidateStatus(params) {
|
|
6582
6630
|
const { candidate, label, labelIndex, phase } = params;
|
|
6583
|
-
const
|
|
6584
|
-
|
|
6585
|
-
|
|
6631
|
+
const bounds = getRectBounds(
|
|
6632
|
+
candidate.center,
|
|
6633
|
+
candidate.width,
|
|
6634
|
+
candidate.height
|
|
6586
6635
|
);
|
|
6587
|
-
|
|
6636
|
+
const boundsStatus = this.getBoundsStatus({
|
|
6637
|
+
bounds,
|
|
6638
|
+
labelIndex,
|
|
6639
|
+
label
|
|
6640
|
+
});
|
|
6641
|
+
if (boundsStatus !== "valid") {
|
|
6642
|
+
if (phase !== "trace-anchor" || boundsStatus !== "chip-collision" || !this.isAcceptableTraceAnchorChipCollision(candidate, label, bounds)) {
|
|
6643
|
+
return boundsStatus;
|
|
6644
|
+
}
|
|
6645
|
+
const nonChipBoundsStatus = this.getBoundsStatus({
|
|
6646
|
+
bounds,
|
|
6647
|
+
labelIndex,
|
|
6648
|
+
label,
|
|
6649
|
+
ignoreChipCollisions: true
|
|
6650
|
+
});
|
|
6651
|
+
if (nonChipBoundsStatus !== "valid") return nonChipBoundsStatus;
|
|
6652
|
+
}
|
|
6588
6653
|
const connectorTrace = this.getCandidateConnectorTrace(label, {
|
|
6589
6654
|
anchorPoint: candidate.anchorPoint,
|
|
6590
6655
|
orientation: candidate.orientation,
|
|
@@ -6607,24 +6672,81 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6607
6672
|
}
|
|
6608
6673
|
return "valid";
|
|
6609
6674
|
}
|
|
6610
|
-
|
|
6611
|
-
|
|
6612
|
-
|
|
6675
|
+
isAcceptableTraceAnchorChipCollision(candidate, label, bounds) {
|
|
6676
|
+
const collidingChips = this.chipObstacleSpatialIndex.getChipsInBounds(bounds);
|
|
6677
|
+
if (collidingChips.length === 0) return false;
|
|
6678
|
+
const labelChipIds = new Set(
|
|
6679
|
+
label.pinIds.map((pinId) => this.pinMap[pinId]?.chipId).filter((chipId) => Boolean(chipId))
|
|
6680
|
+
);
|
|
6681
|
+
return collidingChips.every((chip) => {
|
|
6682
|
+
if (!labelChipIds.has(chip.chipId)) return false;
|
|
6683
|
+
const { anchorPoint, orientation } = candidate;
|
|
6684
|
+
const chipBounds = chip.bounds;
|
|
6685
|
+
if (isYOrientation(orientation)) {
|
|
6686
|
+
return anchorPoint.x < chipBounds.minX - EPS8 || anchorPoint.x > chipBounds.maxX + EPS8;
|
|
6687
|
+
}
|
|
6688
|
+
return anchorPoint.y < chipBounds.minY - EPS8 || anchorPoint.y > chipBounds.maxY + EPS8;
|
|
6689
|
+
});
|
|
6690
|
+
}
|
|
6691
|
+
getBoundsStatus(candidateBoundsCheck) {
|
|
6692
|
+
const { bounds, labelIndex, label, ignoreChipCollisions } = candidateBoundsCheck;
|
|
6693
|
+
if (!ignoreChipCollisions) {
|
|
6694
|
+
if (this.chipObstacleSpatialIndex.getChipsInBounds(bounds).length > 0) {
|
|
6695
|
+
return "chip-collision";
|
|
6696
|
+
}
|
|
6697
|
+
if (this.sharesChipBoundary(bounds)) {
|
|
6698
|
+
return "chip-collision";
|
|
6699
|
+
}
|
|
6613
6700
|
}
|
|
6614
6701
|
if (rectIntersectsAnyTextBox(bounds, this.inputProblem)) {
|
|
6615
6702
|
return "text-collision";
|
|
6616
6703
|
}
|
|
6617
|
-
if (this.sharesChipBoundary(bounds)) {
|
|
6618
|
-
return "chip-collision";
|
|
6619
|
-
}
|
|
6620
6704
|
if (traceCrossesBoundsInterior(bounds, this.traceMap)) {
|
|
6621
6705
|
return "trace-collision";
|
|
6622
6706
|
}
|
|
6707
|
+
if (this.isTraceTooCloseToLabel(bounds, label)) {
|
|
6708
|
+
return "trace-clearance-violation";
|
|
6709
|
+
}
|
|
6623
6710
|
if (this.intersectsAnyOtherNetLabel(bounds, labelIndex)) {
|
|
6624
6711
|
return "netlabel-collision";
|
|
6625
6712
|
}
|
|
6626
6713
|
return "valid";
|
|
6627
6714
|
}
|
|
6715
|
+
isTraceTooCloseToLabel(bounds, label) {
|
|
6716
|
+
if (!this.shouldCheckTraceClearanceForLabel(label)) return false;
|
|
6717
|
+
const clearanceBounds = this.getLabelTraceClearanceBounds(bounds);
|
|
6718
|
+
for (const trace of Object.values(this.traceMap)) {
|
|
6719
|
+
if (trace.globalConnNetId === label.globalConnNetId) continue;
|
|
6720
|
+
if (tracePathIntersectsBounds(trace.tracePath, clearanceBounds)) {
|
|
6721
|
+
return true;
|
|
6722
|
+
}
|
|
6723
|
+
}
|
|
6724
|
+
return false;
|
|
6725
|
+
}
|
|
6726
|
+
getLabelTraceClearanceBounds(bounds) {
|
|
6727
|
+
return {
|
|
6728
|
+
minX: bounds.minX - LABEL_TRACE_CLEARANCE,
|
|
6729
|
+
minY: bounds.minY - LABEL_TRACE_CLEARANCE,
|
|
6730
|
+
maxX: bounds.maxX + LABEL_TRACE_CLEARANCE,
|
|
6731
|
+
maxY: bounds.maxY + LABEL_TRACE_CLEARANCE
|
|
6732
|
+
};
|
|
6733
|
+
}
|
|
6734
|
+
shouldCheckTraceClearanceForLabel(label) {
|
|
6735
|
+
if (!this.isPortOnlyLabel(label)) return false;
|
|
6736
|
+
if (!this.hasRoutedLabelOnSameNet(label)) return false;
|
|
6737
|
+
const orientations = this.getAvailableOrientations(label);
|
|
6738
|
+
return orientations.length === 1;
|
|
6739
|
+
}
|
|
6740
|
+
hasRoutedLabelOnSameNet(label) {
|
|
6741
|
+
for (const otherLabel of this.outputNetLabelPlacements) {
|
|
6742
|
+
if (otherLabel.globalConnNetId !== label.globalConnNetId) continue;
|
|
6743
|
+
if (otherLabel.mspConnectionPairIds.length > 0) return true;
|
|
6744
|
+
}
|
|
6745
|
+
return false;
|
|
6746
|
+
}
|
|
6747
|
+
isPortOnlyLabel(label) {
|
|
6748
|
+
return label.mspConnectionPairIds.length === 0;
|
|
6749
|
+
}
|
|
6628
6750
|
intersectsAnyOtherNetLabel(bounds, labelIndex) {
|
|
6629
6751
|
for (let i = 0; i < this.outputNetLabelPlacements.length; i++) {
|
|
6630
6752
|
if (i === labelIndex) continue;
|
|
@@ -38,6 +38,8 @@ import type {
|
|
|
38
38
|
import { visualizeAvailableNetOrientationSolver } from "./visualize"
|
|
39
39
|
import { rectIntersectsAnyTextBox } from "lib/utils/textBoxBounds"
|
|
40
40
|
|
|
41
|
+
const LABEL_TRACE_CLEARANCE = 0.1
|
|
42
|
+
|
|
41
43
|
export class AvailableNetOrientationSolver extends BaseSolver {
|
|
42
44
|
inputProblem: InputProblem
|
|
43
45
|
traces: SolvedTracePath[]
|
|
@@ -144,6 +146,8 @@ export class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
144
146
|
candidate: EvaluatedCandidate,
|
|
145
147
|
labelIndex: number,
|
|
146
148
|
) {
|
|
149
|
+
if (candidate.phase === "trace-anchor") return
|
|
150
|
+
|
|
147
151
|
const tracePath = this.getCandidateConnectorTrace(label, candidate)
|
|
148
152
|
if (tracePath.length < 2) return
|
|
149
153
|
|
|
@@ -185,6 +189,13 @@ export class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
185
189
|
)
|
|
186
190
|
if (rotatedCandidate) return rotatedCandidate
|
|
187
191
|
|
|
192
|
+
const traceAnchorCandidate = this.findValidTraceAnchorCandidate(
|
|
193
|
+
label,
|
|
194
|
+
orientations[0]!,
|
|
195
|
+
labelIndex,
|
|
196
|
+
)
|
|
197
|
+
if (traceAnchorCandidate) return traceAnchorCandidate
|
|
198
|
+
|
|
188
199
|
const shiftedCandidate = this.findValidShiftedCandidate(
|
|
189
200
|
label,
|
|
190
201
|
orientations[0]!,
|
|
@@ -226,6 +237,57 @@ export class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
226
237
|
return null
|
|
227
238
|
}
|
|
228
239
|
|
|
240
|
+
private findValidTraceAnchorCandidate(
|
|
241
|
+
label: NetLabelPlacement,
|
|
242
|
+
orientation: FacingDirection,
|
|
243
|
+
labelIndex: number,
|
|
244
|
+
) {
|
|
245
|
+
const direction = dir(orientation)
|
|
246
|
+
const candidatePoints = this.getTraceAnchorCandidatePoints(label).sort(
|
|
247
|
+
(a, b) => {
|
|
248
|
+
const aAlongDirection = a.x * direction.x + a.y * direction.y
|
|
249
|
+
const bAlongDirection = b.x * direction.x + b.y * direction.y
|
|
250
|
+
return bAlongDirection - aAlongDirection
|
|
251
|
+
},
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
for (const anchorPoint of candidatePoints) {
|
|
255
|
+
const candidate = this.createCandidate(label, anchorPoint, orientation)
|
|
256
|
+
const result = this.evaluateCandidate(
|
|
257
|
+
candidate,
|
|
258
|
+
label,
|
|
259
|
+
labelIndex,
|
|
260
|
+
"trace-anchor",
|
|
261
|
+
)
|
|
262
|
+
this.currentCandidateResults.push(result)
|
|
263
|
+
|
|
264
|
+
if (result.status === "valid") {
|
|
265
|
+
result.selected = true
|
|
266
|
+
return result
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return null
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
private getTraceAnchorCandidatePoints(label: NetLabelPlacement) {
|
|
274
|
+
const seen = new Set<string>()
|
|
275
|
+
const points: Point[] = []
|
|
276
|
+
|
|
277
|
+
for (const traceId of label.mspConnectionPairIds ?? []) {
|
|
278
|
+
const trace = this.traceMap[traceId]
|
|
279
|
+
if (!trace) continue
|
|
280
|
+
for (const point of trace.tracePath) {
|
|
281
|
+
const key = `${point.x.toFixed(9)},${point.y.toFixed(9)}`
|
|
282
|
+
if (seen.has(key)) continue
|
|
283
|
+
seen.add(key)
|
|
284
|
+
points.push(point)
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return points
|
|
289
|
+
}
|
|
290
|
+
|
|
229
291
|
private getAvailableOrientations(label: NetLabelPlacement) {
|
|
230
292
|
const effectiveNetId = label.netId ?? label.globalConnNetId
|
|
231
293
|
return this.inputProblem.availableNetLabelOrientations[effectiveNetId] ?? []
|
|
@@ -606,11 +668,33 @@ export class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
606
668
|
phase: CandidatePhase
|
|
607
669
|
}) {
|
|
608
670
|
const { candidate, label, labelIndex, phase } = params
|
|
609
|
-
const
|
|
610
|
-
|
|
611
|
-
|
|
671
|
+
const bounds = getRectBounds(
|
|
672
|
+
candidate.center,
|
|
673
|
+
candidate.width,
|
|
674
|
+
candidate.height,
|
|
612
675
|
)
|
|
613
|
-
|
|
676
|
+
const boundsStatus = this.getBoundsStatus({
|
|
677
|
+
bounds,
|
|
678
|
+
labelIndex,
|
|
679
|
+
label,
|
|
680
|
+
})
|
|
681
|
+
if (boundsStatus !== "valid") {
|
|
682
|
+
if (
|
|
683
|
+
phase !== "trace-anchor" ||
|
|
684
|
+
boundsStatus !== "chip-collision" ||
|
|
685
|
+
!this.isAcceptableTraceAnchorChipCollision(candidate, label, bounds)
|
|
686
|
+
) {
|
|
687
|
+
return boundsStatus
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
const nonChipBoundsStatus = this.getBoundsStatus({
|
|
691
|
+
bounds,
|
|
692
|
+
labelIndex,
|
|
693
|
+
label,
|
|
694
|
+
ignoreChipCollisions: true,
|
|
695
|
+
})
|
|
696
|
+
if (nonChipBoundsStatus !== "valid") return nonChipBoundsStatus
|
|
697
|
+
}
|
|
614
698
|
|
|
615
699
|
const connectorTrace = this.getCandidateConnectorTrace(label, {
|
|
616
700
|
anchorPoint: candidate.anchorPoint,
|
|
@@ -640,25 +724,115 @@ export class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
640
724
|
return "valid"
|
|
641
725
|
}
|
|
642
726
|
|
|
643
|
-
private
|
|
644
|
-
|
|
645
|
-
|
|
727
|
+
private isAcceptableTraceAnchorChipCollision(
|
|
728
|
+
candidate: CandidateLabel,
|
|
729
|
+
label: NetLabelPlacement,
|
|
730
|
+
bounds: Bounds,
|
|
731
|
+
) {
|
|
732
|
+
const collidingChips =
|
|
733
|
+
this.chipObstacleSpatialIndex.getChipsInBounds(bounds)
|
|
734
|
+
if (collidingChips.length === 0) return false
|
|
735
|
+
|
|
736
|
+
const labelChipIds = new Set(
|
|
737
|
+
label.pinIds
|
|
738
|
+
.map((pinId) => this.pinMap[pinId]?.chipId)
|
|
739
|
+
.filter((chipId): chipId is string => Boolean(chipId)),
|
|
740
|
+
)
|
|
741
|
+
|
|
742
|
+
return collidingChips.every((chip) => {
|
|
743
|
+
if (!labelChipIds.has(chip.chipId)) return false
|
|
744
|
+
|
|
745
|
+
const { anchorPoint, orientation } = candidate
|
|
746
|
+
const chipBounds = chip.bounds
|
|
747
|
+
if (isYOrientation(orientation)) {
|
|
748
|
+
return (
|
|
749
|
+
anchorPoint.x < chipBounds.minX - EPS ||
|
|
750
|
+
anchorPoint.x > chipBounds.maxX + EPS
|
|
751
|
+
)
|
|
752
|
+
}
|
|
753
|
+
return (
|
|
754
|
+
anchorPoint.y < chipBounds.minY - EPS ||
|
|
755
|
+
anchorPoint.y > chipBounds.maxY + EPS
|
|
756
|
+
)
|
|
757
|
+
})
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
private getBoundsStatus(candidateBoundsCheck: {
|
|
761
|
+
bounds: Bounds
|
|
762
|
+
labelIndex: number
|
|
763
|
+
label: NetLabelPlacement
|
|
764
|
+
ignoreChipCollisions?: boolean
|
|
765
|
+
}): CandidateStatus {
|
|
766
|
+
const { bounds, labelIndex, label, ignoreChipCollisions } =
|
|
767
|
+
candidateBoundsCheck
|
|
768
|
+
|
|
769
|
+
if (!ignoreChipCollisions) {
|
|
770
|
+
if (this.chipObstacleSpatialIndex.getChipsInBounds(bounds).length > 0) {
|
|
771
|
+
return "chip-collision"
|
|
772
|
+
}
|
|
773
|
+
if (this.sharesChipBoundary(bounds)) {
|
|
774
|
+
return "chip-collision"
|
|
775
|
+
}
|
|
646
776
|
}
|
|
647
777
|
if (rectIntersectsAnyTextBox(bounds, this.inputProblem)) {
|
|
648
778
|
return "text-collision"
|
|
649
779
|
}
|
|
650
|
-
if (this.sharesChipBoundary(bounds)) {
|
|
651
|
-
return "chip-collision"
|
|
652
|
-
}
|
|
653
780
|
if (traceCrossesBoundsInterior(bounds, this.traceMap)) {
|
|
654
781
|
return "trace-collision"
|
|
655
782
|
}
|
|
783
|
+
if (this.isTraceTooCloseToLabel(bounds, label)) {
|
|
784
|
+
return "trace-clearance-violation"
|
|
785
|
+
}
|
|
656
786
|
if (this.intersectsAnyOtherNetLabel(bounds, labelIndex)) {
|
|
657
787
|
return "netlabel-collision"
|
|
658
788
|
}
|
|
659
789
|
return "valid"
|
|
660
790
|
}
|
|
661
791
|
|
|
792
|
+
private isTraceTooCloseToLabel(bounds: Bounds, label: NetLabelPlacement) {
|
|
793
|
+
if (!this.shouldCheckTraceClearanceForLabel(label)) return false
|
|
794
|
+
|
|
795
|
+
const clearanceBounds = this.getLabelTraceClearanceBounds(bounds)
|
|
796
|
+
for (const trace of Object.values(this.traceMap)) {
|
|
797
|
+
if (trace.globalConnNetId === label.globalConnNetId) continue
|
|
798
|
+
if (tracePathIntersectsBounds(trace.tracePath, clearanceBounds)) {
|
|
799
|
+
return true
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
return false
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
private getLabelTraceClearanceBounds(bounds: Bounds): Bounds {
|
|
807
|
+
return {
|
|
808
|
+
minX: bounds.minX - LABEL_TRACE_CLEARANCE,
|
|
809
|
+
minY: bounds.minY - LABEL_TRACE_CLEARANCE,
|
|
810
|
+
maxX: bounds.maxX + LABEL_TRACE_CLEARANCE,
|
|
811
|
+
maxY: bounds.maxY + LABEL_TRACE_CLEARANCE,
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
private shouldCheckTraceClearanceForLabel(label: NetLabelPlacement) {
|
|
816
|
+
if (!this.isPortOnlyLabel(label)) return false
|
|
817
|
+
if (!this.hasRoutedLabelOnSameNet(label)) return false
|
|
818
|
+
|
|
819
|
+
const orientations = this.getAvailableOrientations(label)
|
|
820
|
+
return orientations.length === 1
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
private hasRoutedLabelOnSameNet(label: NetLabelPlacement) {
|
|
824
|
+
for (const otherLabel of this.outputNetLabelPlacements) {
|
|
825
|
+
if (otherLabel.globalConnNetId !== label.globalConnNetId) continue
|
|
826
|
+
if (otherLabel.mspConnectionPairIds.length > 0) return true
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
return false
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
private isPortOnlyLabel(label: NetLabelPlacement) {
|
|
833
|
+
return label.mspConnectionPairIds.length === 0
|
|
834
|
+
}
|
|
835
|
+
|
|
662
836
|
private intersectsAnyOtherNetLabel(bounds: Bounds, labelIndex: number) {
|
|
663
837
|
for (let i = 0; i < this.outputNetLabelPlacements.length; i++) {
|
|
664
838
|
if (i === labelIndex) continue
|
|
@@ -32,9 +32,14 @@ export type CandidateStatus =
|
|
|
32
32
|
| "chip-collision"
|
|
33
33
|
| "text-collision"
|
|
34
34
|
| "trace-collision"
|
|
35
|
+
| "trace-clearance-violation"
|
|
35
36
|
| "netlabel-collision"
|
|
36
37
|
|
|
37
|
-
export type CandidatePhase =
|
|
38
|
+
export type CandidatePhase =
|
|
39
|
+
| "rotate"
|
|
40
|
+
| "trace-anchor"
|
|
41
|
+
| "shift"
|
|
42
|
+
| "lateral-shift"
|
|
38
43
|
|
|
39
44
|
export type EvaluatedCandidate = CandidateLabel & {
|
|
40
45
|
status: CandidateStatus
|
package/package.json
CHANGED
|
@@ -86,7 +86,7 @@ orientation: x-" data-x="-1.485" data-y="-0.2" cx="256.11911623439005" cy="288.2
|
|
|
86
86
|
</g>
|
|
87
87
|
<g>
|
|
88
88
|
<circle data-type="point" data-label="anchorPoint
|
|
89
|
-
orientation: y-" data-x="-1.3860000000000001" data-y="-0.
|
|
89
|
+
orientation: y-" data-x="-1.3860000000000001" data-y="-0.601" cx="261.4447646493756" cy="309.8328530259365" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
|
|
90
90
|
</g>
|
|
91
91
|
<g>
|
|
92
92
|
<circle data-type="point" data-label="anchorPoint
|
|
@@ -218,10 +218,10 @@ orientation: x-" data-x="2.6749999999999994" data-y="-2.7362499999999996" cx="47
|
|
|
218
218
|
<polyline data-points="-1.2850000000000001,0.20000000000000018 -1.866,0.20000000000000018 -1.866,-4.440892098500626e-16 -2.87,-4.440892098500626e-16 -2.87,0.19999999999999973" data-type="line" data-label="" points="266.8780019212296,266.74351585014404 235.62343900096062,266.74351585014404 235.62343900096062,277.5024015369836 181.61383285302594,277.5024015369836 181.61383285302594,266.74351585014404" fill="none" stroke="purple" stroke-width="1" />
|
|
219
219
|
</g>
|
|
220
220
|
<g>
|
|
221
|
-
<polyline data-points="-1.2850000000000001,-0.2 -1.485,-0.2 -1.485,-0.
|
|
221
|
+
<polyline data-points="-1.2850000000000001,-0.2 -1.485,-0.2 -1.485,-0.5 -2.166,-0.5 -2.166,0.5 -1.485,0.5 -1.485,0.2 -1.2850000000000001,0.2" data-type="line" data-label="" points="266.8780019212296,288.26128722382316 256.11911623439005,288.26128722382316 256.11911623439005,304.39961575408256 219.48511047070127,304.39961575408256 219.48511047070127,250.60518731988466 256.11911623439005,250.60518731988466 256.11911623439005,266.74351585014404 266.8780019212296,266.74351585014404" fill="none" stroke="purple" stroke-width="1" />
|
|
222
222
|
</g>
|
|
223
223
|
<g>
|
|
224
|
-
<polyline data-points="-1.2850000000000001,0 -1.3860000000000001,0 -1.3860000000000001,-0.
|
|
224
|
+
<polyline data-points="-1.2850000000000001,0 -1.3860000000000001,0 -1.3860000000000001,-0.601" data-type="line" data-label="" points="266.8780019212296,277.5024015369836 261.4447646493756,277.5024015369836 261.4447646493756,309.8328530259365" fill="none" stroke="purple" stroke-width="1" />
|
|
225
225
|
</g>
|
|
226
226
|
<g>
|
|
227
227
|
<rect data-type="rect" data-label="schematic_component_0" data-x="-2.71" data-y="0.7199999999999998" x="167.08933717579254" y="210.79731027857824" width="46.26320845341016" height="55.9462055715658" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.018589285714285714" />
|
|
@@ -257,7 +257,7 @@ globalConnNetId: connectivity_net1" data-x="-1.725" data-y="-0.2" x="230.2977905
|
|
|
257
257
|
</g>
|
|
258
258
|
<g>
|
|
259
259
|
<rect data-type="rect" data-label="netId: GND
|
|
260
|
-
globalConnNetId: connectivity_net2" data-x="-1.3860000000000001" data-y="-0.
|
|
260
|
+
globalConnNetId: connectivity_net2" data-x="-1.3860000000000001" data-y="-0.841" x="256.0653218059558" y="309.8328530259365" width="10.758885686839562" height="25.821325648414984" fill="#00000066" stroke="#000000" stroke-width="0.018589285714285714" />
|
|
261
261
|
</g>
|
|
262
262
|
<g>
|
|
263
263
|
<rect data-type="rect" data-label="netId: GND
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
<svg width="640" height="640" viewBox="0 0 640 640" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<rect width="100%" height="100%" fill="white" />
|
|
3
|
+
<g>
|
|
4
|
+
<circle data-type="point" data-label="BT1.1
|
|
5
|
+
x+" data-x="-2.6" data-y="2.2" cx="84.13793103448276" cy="230.89655172413794" r="3" fill="hsl(114, 100%, 50%, 0.8)" />
|
|
6
|
+
</g>
|
|
7
|
+
<g>
|
|
8
|
+
<circle data-type="point" data-label="BT1.2
|
|
9
|
+
x+" data-x="-2.6" data-y="1.8" cx="84.13793103448276" cy="252.9655172413793" r="3" fill="hsl(115, 100%, 50%, 0.8)" />
|
|
10
|
+
</g>
|
|
11
|
+
<g>
|
|
12
|
+
<circle data-type="point" data-label="SW1.1
|
|
13
|
+
x-" data-x="-0.5" data-y="2" cx="200" cy="241.93103448275863" r="3" fill="hsl(104, 100%, 50%, 0.8)" />
|
|
14
|
+
</g>
|
|
15
|
+
<g>
|
|
16
|
+
<circle data-type="point" data-label="SW1.2
|
|
17
|
+
x+" data-x="0.5" data-y="2" cx="255.17241379310343" cy="241.93103448275863" r="3" fill="hsl(105, 100%, 50%, 0.8)" />
|
|
18
|
+
</g>
|
|
19
|
+
<g>
|
|
20
|
+
<circle data-type="point" data-label="R1.1
|
|
21
|
+
x-" data-x="2.45" data-y="1" cx="362.7586206896552" cy="297.1034482758621" r="3" fill="hsl(226, 100%, 50%, 0.8)" />
|
|
22
|
+
</g>
|
|
23
|
+
<g>
|
|
24
|
+
<circle data-type="point" data-label="R1.2
|
|
25
|
+
x+" data-x="3.55" data-y="1" cx="423.44827586206895" cy="297.1034482758621" r="3" fill="hsl(227, 100%, 50%, 0.8)" />
|
|
26
|
+
</g>
|
|
27
|
+
<g>
|
|
28
|
+
<circle data-type="point" data-label="R2.1
|
|
29
|
+
x-" data-x="2.45" data-y="-1" cx="362.7586206896552" cy="407.44827586206895" r="3" fill="hsl(107, 100%, 50%, 0.8)" />
|
|
30
|
+
</g>
|
|
31
|
+
<g>
|
|
32
|
+
<circle data-type="point" data-label="R2.2
|
|
33
|
+
x+" data-x="3.55" data-y="-1" cx="423.44827586206895" cy="407.44827586206895" r="3" fill="hsl(108, 100%, 50%, 0.8)" />
|
|
34
|
+
</g>
|
|
35
|
+
<g>
|
|
36
|
+
<circle data-type="point" data-label="D1.1
|
|
37
|
+
x-" data-x="5.45" data-y="1" cx="528.2758620689655" cy="297.1034482758621" r="3" fill="hsl(32, 100%, 50%, 0.8)" />
|
|
38
|
+
</g>
|
|
39
|
+
<g>
|
|
40
|
+
<circle data-type="point" data-label="D1.2
|
|
41
|
+
x+" data-x="6.55" data-y="1" cx="588.9655172413793" cy="297.1034482758621" r="3" fill="hsl(33, 100%, 50%, 0.8)" />
|
|
42
|
+
</g>
|
|
43
|
+
<g>
|
|
44
|
+
<circle data-type="point" data-label="D2.1
|
|
45
|
+
x-" data-x="5.45" data-y="-1" cx="528.2758620689655" cy="407.44827586206895" r="3" fill="hsl(273, 100%, 50%, 0.8)" />
|
|
46
|
+
</g>
|
|
47
|
+
<g>
|
|
48
|
+
<circle data-type="point" data-label="D2.2
|
|
49
|
+
x+" data-x="6.55" data-y="-1" cx="588.9655172413793" cy="407.44827586206895" r="3" fill="hsl(274, 100%, 50%, 0.8)" />
|
|
50
|
+
</g>
|
|
51
|
+
<g>
|
|
52
|
+
<circle data-type="point" data-label="anchorPoint
|
|
53
|
+
orientation: y+" data-x="-2.075" data-y="2.2" cx="113.10344827586206" cy="230.89655172413794" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
|
|
54
|
+
</g>
|
|
55
|
+
<g>
|
|
56
|
+
<circle data-type="point" data-label="anchorPoint
|
|
57
|
+
orientation: y-" data-x="-2.499" data-y="1.5990000000000002" cx="89.7103448275862" cy="264.0551724137931" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
|
|
58
|
+
</g>
|
|
59
|
+
<g>
|
|
60
|
+
<circle data-type="point" data-label="anchorPoint
|
|
61
|
+
orientation: y-" data-x="6.65" data-y="-1" cx="594.4827586206897" cy="407.44827586206895" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
|
|
62
|
+
</g>
|
|
63
|
+
<g>
|
|
64
|
+
<circle data-type="point" data-label="anchorPoint
|
|
65
|
+
orientation: y-" data-x="2.25" data-y="-1" cx="351.7241379310345" cy="407.44827586206895" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
|
|
66
|
+
</g>
|
|
67
|
+
<g>
|
|
68
|
+
<circle data-type="point" data-label="anchorPoint
|
|
69
|
+
orientation: y+" data-x="4.5" data-y="1" cx="475.8620689655172" cy="297.1034482758621" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
|
|
70
|
+
</g>
|
|
71
|
+
<g>
|
|
72
|
+
<circle data-type="point" data-label="anchorPoint
|
|
73
|
+
orientation: y+" data-x="4.5" data-y="-1" cx="475.8620689655172" cy="407.44827586206895" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
|
|
74
|
+
</g>
|
|
75
|
+
<g>
|
|
76
|
+
<polyline data-points="-2.6,2.2 -0.5,2" data-type="line" data-label="" points="84.13793103448276,230.89655172413794 200,241.93103448275863" fill="none" stroke="hsl(0, 100%, 50%, 0.8)" stroke-width="1" />
|
|
77
|
+
</g>
|
|
78
|
+
<g>
|
|
79
|
+
<polyline data-points="0.5,2 2.45,1" data-type="line" data-label="" points="255.17241379310343,241.93103448275863 362.7586206896552,297.1034482758621" fill="none" stroke="hsl(304, 100%, 50%, 0.8)" stroke-width="1" />
|
|
80
|
+
</g>
|
|
81
|
+
<g>
|
|
82
|
+
<polyline data-points="0.5,2 2.45,-1" data-type="line" data-label="" points="255.17241379310343,241.93103448275863 362.7586206896552,407.44827586206895" fill="none" stroke="hsl(304, 100%, 50%, 0.8)" stroke-width="1" />
|
|
83
|
+
</g>
|
|
84
|
+
<g>
|
|
85
|
+
<polyline data-points="3.55,1 5.45,1" data-type="line" data-label="" points="423.44827586206895,297.1034482758621 528.2758620689655,297.1034482758621" fill="none" stroke="hsl(312, 100%, 50%, 0.8)" stroke-width="1" />
|
|
86
|
+
</g>
|
|
87
|
+
<g>
|
|
88
|
+
<polyline data-points="3.55,-1 5.45,-1" data-type="line" data-label="" points="423.44827586206895,407.44827586206895 528.2758620689655,407.44827586206895" fill="none" stroke="hsl(320, 100%, 50%, 0.8)" stroke-width="1" />
|
|
89
|
+
</g>
|
|
90
|
+
<g>
|
|
91
|
+
<polyline data-points="-2.6,1.8 6.55,1" data-type="line" data-label="" points="84.13793103448276,252.9655172413793 588.9655172413793,297.1034482758621" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
92
|
+
</g>
|
|
93
|
+
<g>
|
|
94
|
+
<polyline data-points="-2.6,1.8 6.55,-1" data-type="line" data-label="" points="84.13793103448276,252.9655172413793 588.9655172413793,407.44827586206895" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
95
|
+
</g>
|
|
96
|
+
<g>
|
|
97
|
+
<polyline data-points="6.55,1 6.55,-1" data-type="line" data-label="" points="588.9655172413793,297.1034482758621 588.9655172413793,407.44827586206895" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
98
|
+
</g>
|
|
99
|
+
<g>
|
|
100
|
+
<polyline data-points="-2.6,2.2 -1.55,2.2 -1.55,2 -0.5,2" data-type="line" data-label="" points="84.13793103448276,230.89655172413794 142.06896551724137,230.89655172413794 142.06896551724137,241.93103448275863 200,241.93103448275863" fill="none" stroke="purple" stroke-width="1" />
|
|
101
|
+
</g>
|
|
102
|
+
<g>
|
|
103
|
+
<polyline data-points="2.45,-1 2.25,-1 2.25,1 2.45,1" data-type="line" data-label="" points="362.7586206896552,407.44827586206895 351.7241379310345,407.44827586206895 351.7241379310345,297.1034482758621 362.7586206896552,297.1034482758621" fill="none" stroke="purple" stroke-width="1" />
|
|
104
|
+
</g>
|
|
105
|
+
<g>
|
|
106
|
+
<polyline data-points="0.5,2 1.475,2 1.475,1 2.45,1" data-type="line" data-label="" points="255.17241379310343,241.93103448275863 308.9655172413793,241.93103448275863 308.9655172413793,297.1034482758621 362.7586206896552,297.1034482758621" fill="none" stroke="purple" stroke-width="1" />
|
|
107
|
+
</g>
|
|
108
|
+
<g>
|
|
109
|
+
<polyline data-points="3.55,1 5.45,1" data-type="line" data-label="" points="423.44827586206895,297.1034482758621 528.2758620689655,297.1034482758621" fill="none" stroke="purple" stroke-width="1" />
|
|
110
|
+
</g>
|
|
111
|
+
<g>
|
|
112
|
+
<polyline data-points="3.55,-1 5.45,-1" data-type="line" data-label="" points="423.44827586206895,407.44827586206895 528.2758620689655,407.44827586206895" fill="none" stroke="purple" stroke-width="1" />
|
|
113
|
+
</g>
|
|
114
|
+
<g>
|
|
115
|
+
<polyline data-points="6.55,-1 6.75,-1 6.75,1 6.55,1" data-type="line" data-label="" points="588.9655172413793,407.44827586206895 600,407.44827586206895 600,297.1034482758621 588.9655172413793,297.1034482758621" fill="none" stroke="purple" stroke-width="1" />
|
|
116
|
+
</g>
|
|
117
|
+
<g>
|
|
118
|
+
<polyline data-points="-2.6,1.8 -2.499,1.8 -2.499,1.5990000000000002" data-type="line" data-label="" points="84.13793103448276,252.9655172413793 89.7103448275862,252.9655172413793 89.7103448275862,264.0551724137931" fill="none" stroke="purple" stroke-width="1" />
|
|
119
|
+
</g>
|
|
120
|
+
<g>
|
|
121
|
+
<rect data-type="rect" data-label="BT1" data-x="-3" data-y="2" x="40" y="219.86206896551727" width="44.13793103448276" height="44.13793103448273" fill="hsl(199, 100%, 50%, 0.8)" stroke="black" stroke-width="0.018125000000000002" />
|
|
122
|
+
</g>
|
|
123
|
+
<g>
|
|
124
|
+
<rect data-type="rect" data-label="SW1" data-x="0" data-y="2" x="200" y="219.86206896551727" width="55.17241379310343" height="44.13793103448273" fill="hsl(69, 100%, 50%, 0.8)" stroke="black" stroke-width="0.018125000000000002" />
|
|
125
|
+
</g>
|
|
126
|
+
<g>
|
|
127
|
+
<rect data-type="rect" data-label="R1" data-x="3" data-y="1" x="362.7586206896552" y="286.3748772413793" width="60.68965517241378" height="21.45714206896554" fill="hsl(71, 100%, 50%, 0.8)" stroke="black" stroke-width="0.018125000000000002" />
|
|
128
|
+
</g>
|
|
129
|
+
<g>
|
|
130
|
+
<rect data-type="rect" data-label="R2" data-x="3" data-y="-1" x="362.7586206896552" y="396.7197048275862" width="60.68965517241378" height="21.45714206896554" fill="hsl(72, 100%, 50%, 0.8)" stroke="black" stroke-width="0.018125000000000002" />
|
|
131
|
+
</g>
|
|
132
|
+
<g>
|
|
133
|
+
<rect data-type="rect" data-label="D1" data-x="6" data-y="1" x="528.2758620689655" y="286.3748772413793" width="60.689655172413836" height="21.45714206896554" fill="hsl(357, 100%, 50%, 0.8)" stroke="black" stroke-width="0.018125000000000002" />
|
|
134
|
+
</g>
|
|
135
|
+
<g>
|
|
136
|
+
<rect data-type="rect" data-label="D2" data-x="6" data-y="-1" x="528.2758620689655" y="396.7197048275862" width="60.689655172413836" height="21.45714206896554" fill="hsl(358, 100%, 50%, 0.8)" stroke="black" stroke-width="0.018125000000000002" />
|
|
137
|
+
</g>
|
|
138
|
+
<g>
|
|
139
|
+
<rect data-type="rect" data-label="netId: BT1.plus to SW1.in
|
|
140
|
+
globalConnNetId: connectivity_net0" data-x="-2.075" data-y="2.4250000000000003" x="107.5862068965517" y="206.06896551724137" width="11.034482758620712" height="24.82758620689657" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.018125000000000002" />
|
|
141
|
+
</g>
|
|
142
|
+
<g>
|
|
143
|
+
<rect data-type="rect" data-label="netId: GND
|
|
144
|
+
globalConnNetId: connectivity_net4" data-x="-2.499" data-y="1.3590000000000002" x="84.19310344827585" y="264.0551724137931" width="11.034482758620697" height="26.48275862068965" fill="#00000066" stroke="#000000" stroke-width="0.018125000000000002" />
|
|
145
|
+
</g>
|
|
146
|
+
<g>
|
|
147
|
+
<rect data-type="rect" data-label="netId: GND
|
|
148
|
+
globalConnNetId: connectivity_net4" data-x="6.65" data-y="-1.24" x="588.9655172413793" y="407.44827586206895" width="11.034482758620697" height="26.48275862068965" fill="#00000066" stroke="#000000" stroke-width="0.018125000000000002" />
|
|
149
|
+
</g>
|
|
150
|
+
<g>
|
|
151
|
+
<rect data-type="rect" data-label="netId: SW1.out to R2.left
|
|
152
|
+
globalConnNetId: connectivity_net1" data-x="2.25" data-y="-1.225" x="346.2068965517241" y="407.44827586206895" width="11.034482758620697" height="24.82758620689657" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.018125000000000002" />
|
|
153
|
+
</g>
|
|
154
|
+
<g>
|
|
155
|
+
<rect data-type="rect" data-label="netId: R1.right to D1.a
|
|
156
|
+
globalConnNetId: connectivity_net2" data-x="4.5" data-y="1.225" x="470.34482758620686" y="272.2758620689655" width="11.034482758620697" height="24.82758620689657" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.018125000000000002" />
|
|
157
|
+
</g>
|
|
158
|
+
<g>
|
|
159
|
+
<rect data-type="rect" data-label="netId: R2.right to D2.a
|
|
160
|
+
globalConnNetId: connectivity_net3" data-x="4.5" data-y="-0.775" x="470.34482758620686" y="382.62068965517244" width="11.034482758620697" height="24.827586206896513" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.018125000000000002" />
|
|
161
|
+
</g>
|
|
162
|
+
<g id="crosshair" style="display: none">
|
|
163
|
+
<line id="crosshair-h" y1="0" y2="640" stroke="#666" stroke-width="0.5" />
|
|
164
|
+
<line id="crosshair-v" x1="0" x2="640" stroke="#666" stroke-width="0.5" /><text id="coordinates" font-family="monospace" font-size="12" fill="#666"></text>
|
|
165
|
+
</g>
|
|
166
|
+
<script>
|
|
167
|
+
<![CDATA[
|
|
168
|
+
document.currentScript.parentElement.addEventListener('mousemove', (e) => {
|
|
169
|
+
const svg = e.currentTarget;
|
|
170
|
+
const rect = svg.getBoundingClientRect();
|
|
171
|
+
const x = e.clientX - rect.left;
|
|
172
|
+
const y = e.clientY - rect.top;
|
|
173
|
+
const crosshair = svg.getElementById('crosshair');
|
|
174
|
+
const h = svg.getElementById('crosshair-h');
|
|
175
|
+
const v = svg.getElementById('crosshair-v');
|
|
176
|
+
const coords = svg.getElementById('coordinates');
|
|
177
|
+
|
|
178
|
+
crosshair.style.display = 'block';
|
|
179
|
+
h.setAttribute('x1', '0');
|
|
180
|
+
h.setAttribute('x2', '640');
|
|
181
|
+
h.setAttribute('y1', y);
|
|
182
|
+
h.setAttribute('y2', y);
|
|
183
|
+
v.setAttribute('x1', x);
|
|
184
|
+
v.setAttribute('x2', x);
|
|
185
|
+
v.setAttribute('y1', '0');
|
|
186
|
+
v.setAttribute('y2', '640');
|
|
187
|
+
|
|
188
|
+
// Calculate real coordinates using inverse transformation
|
|
189
|
+
const matrix = {
|
|
190
|
+
"a": 55.172413793103445,
|
|
191
|
+
"c": 0,
|
|
192
|
+
"e": 227.58620689655172,
|
|
193
|
+
"b": 0,
|
|
194
|
+
"d": -55.172413793103445,
|
|
195
|
+
"f": 352.2758620689655
|
|
196
|
+
};
|
|
197
|
+
// Manually invert and apply the affine transform
|
|
198
|
+
// Since we only use translate and scale, we can directly compute:
|
|
199
|
+
// x' = (x - tx) / sx
|
|
200
|
+
// y' = (y - ty) / sy
|
|
201
|
+
const sx = matrix.a;
|
|
202
|
+
const sy = matrix.d;
|
|
203
|
+
const tx = matrix.e;
|
|
204
|
+
const ty = matrix.f;
|
|
205
|
+
const realPoint = {
|
|
206
|
+
x: (x - tx) / sx,
|
|
207
|
+
y: (y - ty) / sy // Flip y back since we used negative scale
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
coords.textContent = `(${realPoint.x.toFixed(2)}, ${realPoint.y.toFixed(2)})`;
|
|
211
|
+
coords.setAttribute('x', (x + 5).toString());
|
|
212
|
+
coords.setAttribute('y', (y - 5).toString());
|
|
213
|
+
});
|
|
214
|
+
document.currentScript.parentElement.addEventListener('mouseleave', () => {
|
|
215
|
+
document.currentScript.parentElement.getElementById('crosshair').style.display = 'none';
|
|
216
|
+
});
|
|
217
|
+
]]>
|
|
218
|
+
</script>
|
|
219
|
+
</svg>
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
{
|
|
2
|
+
"chips": [
|
|
3
|
+
{
|
|
4
|
+
"chipId": "BT1",
|
|
5
|
+
"center": {
|
|
6
|
+
"x": -3,
|
|
7
|
+
"y": 2
|
|
8
|
+
},
|
|
9
|
+
"width": 0.8,
|
|
10
|
+
"height": 0.8,
|
|
11
|
+
"pins": [
|
|
12
|
+
{
|
|
13
|
+
"pinId": "BT1.1",
|
|
14
|
+
"x": -2.6,
|
|
15
|
+
"y": 2.2
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"pinId": "BT1.2",
|
|
19
|
+
"x": -2.6,
|
|
20
|
+
"y": 1.8
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"chipId": "SW1",
|
|
26
|
+
"center": {
|
|
27
|
+
"x": 0,
|
|
28
|
+
"y": 2
|
|
29
|
+
},
|
|
30
|
+
"width": 1,
|
|
31
|
+
"height": 0.8,
|
|
32
|
+
"pins": [
|
|
33
|
+
{
|
|
34
|
+
"pinId": "SW1.1",
|
|
35
|
+
"x": -0.5,
|
|
36
|
+
"y": 2
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"pinId": "SW1.2",
|
|
40
|
+
"x": 0.5,
|
|
41
|
+
"y": 2
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"chipId": "R1",
|
|
47
|
+
"center": {
|
|
48
|
+
"x": 3,
|
|
49
|
+
"y": 1
|
|
50
|
+
},
|
|
51
|
+
"width": 1.06,
|
|
52
|
+
"height": 0.3889107,
|
|
53
|
+
"pins": [
|
|
54
|
+
{
|
|
55
|
+
"pinId": "R1.1",
|
|
56
|
+
"x": 2.45,
|
|
57
|
+
"y": 1
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"pinId": "R1.2",
|
|
61
|
+
"x": 3.55,
|
|
62
|
+
"y": 1
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"chipId": "R2",
|
|
68
|
+
"center": {
|
|
69
|
+
"x": 3,
|
|
70
|
+
"y": -1
|
|
71
|
+
},
|
|
72
|
+
"width": 1.06,
|
|
73
|
+
"height": 0.3889107,
|
|
74
|
+
"pins": [
|
|
75
|
+
{
|
|
76
|
+
"pinId": "R2.1",
|
|
77
|
+
"x": 2.45,
|
|
78
|
+
"y": -1
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"pinId": "R2.2",
|
|
82
|
+
"x": 3.55,
|
|
83
|
+
"y": -1
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"chipId": "D1",
|
|
89
|
+
"center": {
|
|
90
|
+
"x": 6,
|
|
91
|
+
"y": 1
|
|
92
|
+
},
|
|
93
|
+
"width": 1.06,
|
|
94
|
+
"height": 0.3889107,
|
|
95
|
+
"pins": [
|
|
96
|
+
{
|
|
97
|
+
"pinId": "D1.1",
|
|
98
|
+
"x": 5.45,
|
|
99
|
+
"y": 1
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"pinId": "D1.2",
|
|
103
|
+
"x": 6.55,
|
|
104
|
+
"y": 1
|
|
105
|
+
}
|
|
106
|
+
]
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"chipId": "D2",
|
|
110
|
+
"center": {
|
|
111
|
+
"x": 6,
|
|
112
|
+
"y": -1
|
|
113
|
+
},
|
|
114
|
+
"width": 1.06,
|
|
115
|
+
"height": 0.3889107,
|
|
116
|
+
"pins": [
|
|
117
|
+
{
|
|
118
|
+
"pinId": "D2.1",
|
|
119
|
+
"x": 5.45,
|
|
120
|
+
"y": -1
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"pinId": "D2.2",
|
|
124
|
+
"x": 6.55,
|
|
125
|
+
"y": -1
|
|
126
|
+
}
|
|
127
|
+
]
|
|
128
|
+
}
|
|
129
|
+
],
|
|
130
|
+
"directConnections": [
|
|
131
|
+
{
|
|
132
|
+
"pinIds": ["BT1.1", "SW1.1"],
|
|
133
|
+
"netId": "BT1.plus to SW1.in"
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"pinIds": ["SW1.2", "R1.1"],
|
|
137
|
+
"netId": "SW1.out to R1.left"
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"pinIds": ["SW1.2", "R2.1"],
|
|
141
|
+
"netId": "SW1.out to R2.left"
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"pinIds": ["R1.2", "D1.1"],
|
|
145
|
+
"netId": "R1.right to D1.a"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"pinIds": ["R2.2", "D2.1"],
|
|
149
|
+
"netId": "R2.right to D2.a"
|
|
150
|
+
}
|
|
151
|
+
],
|
|
152
|
+
"netConnections": [
|
|
153
|
+
{
|
|
154
|
+
"netId": "GND",
|
|
155
|
+
"pinIds": ["BT1.2", "D1.2", "D2.2"],
|
|
156
|
+
"netLabelWidth": 0.48
|
|
157
|
+
}
|
|
158
|
+
],
|
|
159
|
+
"availableNetLabelOrientations": {
|
|
160
|
+
"GND": ["y-"]
|
|
161
|
+
},
|
|
162
|
+
"maxMspPairDistance": 8
|
|
163
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import { SchematicTracePipelineSolver } from "lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver"
|
|
3
|
+
import inputProblem from "./assets/bugreport-001-gnd-overlap.input.json"
|
|
4
|
+
import "tests/fixtures/matcher"
|
|
5
|
+
|
|
6
|
+
test("bugreport-001-gnd-overlap", () => {
|
|
7
|
+
const solver = new SchematicTracePipelineSolver(inputProblem as any)
|
|
8
|
+
solver.solve()
|
|
9
|
+
|
|
10
|
+
expect(
|
|
11
|
+
solver.netLabelPlacementSolver!.netLabelPlacements.some(
|
|
12
|
+
(placement) => placement.netId === "GND",
|
|
13
|
+
),
|
|
14
|
+
).toBe(true)
|
|
15
|
+
expect(solver).toMatchSolverSnapshot(import.meta.path)
|
|
16
|
+
})
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import { SchematicTracePipelineSolver } from "lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver"
|
|
3
|
+
import type { InputProblem } from "lib/types/InputProblem"
|
|
4
|
+
|
|
5
|
+
const inputProblem: InputProblem = {
|
|
6
|
+
chips: [
|
|
7
|
+
{
|
|
8
|
+
chipId: "D1",
|
|
9
|
+
center: { x: 7.9, y: 0 },
|
|
10
|
+
width: 0.7400000000000002,
|
|
11
|
+
height: 1.04,
|
|
12
|
+
pins: [
|
|
13
|
+
{ pinId: "D1.1", x: 8, y: -0.52 },
|
|
14
|
+
{ pinId: "D1.2", x: 8, y: 0.52 },
|
|
15
|
+
],
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
chipId: "D2",
|
|
19
|
+
center: { x: 10, y: 0.07 },
|
|
20
|
+
width: 1.0399999999999991,
|
|
21
|
+
height: 0.68,
|
|
22
|
+
pins: [
|
|
23
|
+
{ pinId: "D2.1", x: 9.48, y: 0 },
|
|
24
|
+
{ pinId: "D2.2", x: 10.52, y: 0 },
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
directConnections: [],
|
|
29
|
+
netConnections: [
|
|
30
|
+
{
|
|
31
|
+
netId: "VCC",
|
|
32
|
+
pinIds: ["D1.1", "D2.1"],
|
|
33
|
+
netLabelWidth: 0.48,
|
|
34
|
+
netLabelHeight: 0.42,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
netId: "GND",
|
|
38
|
+
pinIds: ["D1.2", "D2.2"],
|
|
39
|
+
netLabelWidth: 0.48,
|
|
40
|
+
netLabelHeight: 0.42,
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
textBoxes: [],
|
|
44
|
+
availableNetLabelOrientations: {
|
|
45
|
+
GND: ["y-"],
|
|
46
|
+
VCC: ["y+"],
|
|
47
|
+
},
|
|
48
|
+
maxMspPairDistance: 0.1,
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
test("rotated component rail label stays on the existing trace", () => {
|
|
52
|
+
const solver = new SchematicTracePipelineSolver(inputProblem)
|
|
53
|
+
solver.solve()
|
|
54
|
+
|
|
55
|
+
const traces = solver.netLabelTraceCollisionSolver!.getOutput().traces
|
|
56
|
+
const labels =
|
|
57
|
+
solver.netLabelNetLabelCollisionSolver!.getOutput().netLabelPlacements
|
|
58
|
+
const gndLabel = labels.find((label) => label.netId === "GND")
|
|
59
|
+
|
|
60
|
+
expect(
|
|
61
|
+
traces.some((trace) =>
|
|
62
|
+
trace.mspPairId.startsWith("available-net-orientation"),
|
|
63
|
+
),
|
|
64
|
+
).toBe(false)
|
|
65
|
+
expect(gndLabel?.orientation).toBe("y-")
|
|
66
|
+
expect(gndLabel?.anchorPoint.x).toBeCloseTo(10.72)
|
|
67
|
+
expect(gndLabel?.anchorPoint.y).toBeCloseTo(0)
|
|
68
|
+
})
|