@tscircuit/schematic-trace-solver 0.0.21 → 0.0.22
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/.github/workflows/bun-pver-release.yml +3 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +177 -89
- package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver/SchematicTraceSingleLineSolver.ts +3 -1
- package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver/generateElbowVariants.ts +234 -87
- package/package.json +1 -1
- package/site/SchematicTraceSingleLineSolver/SchematicTraceSingleLineSolver01.page.tsx +894 -0
- package/site/examples/example09.page.tsx +417 -0
- package/tests/functions/generateElbowVariants.test.ts +1 -1
- package/tests/solvers/SchematicTraceSingleLineSolver/SchematicTraceSingleLineSolver_repro02.test.ts +904 -0
package/dist/index.d.ts
CHANGED
|
@@ -161,6 +161,7 @@ declare class SchematicTraceSingleLineSolver extends BaseSolver {
|
|
|
161
161
|
chipMap: Record<string, InputChip>;
|
|
162
162
|
movableSegments: Array<MovableSegment>;
|
|
163
163
|
baseElbow: Point[];
|
|
164
|
+
allCandidatePaths: Array<Point[]>;
|
|
164
165
|
queuedCandidatePaths: Array<Point[]>;
|
|
165
166
|
chipObstacleSpatialIndex: ChipObstacleSpatialIndex;
|
|
166
167
|
solvedTracePath: {
|
package/dist/index.js
CHANGED
|
@@ -6520,81 +6520,167 @@ var dir = (facingDirection) => {
|
|
|
6520
6520
|
};
|
|
6521
6521
|
|
|
6522
6522
|
// lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver/generateElbowVariants.ts
|
|
6523
|
-
var
|
|
6524
|
-
|
|
6525
|
-
|
|
6526
|
-
|
|
6527
|
-
const
|
|
6528
|
-
|
|
6529
|
-
|
|
6530
|
-
|
|
6531
|
-
|
|
6532
|
-
|
|
6533
|
-
|
|
6534
|
-
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
|
|
6523
|
+
var EPS = 1e-6;
|
|
6524
|
+
var MIN_LEN = 1e-6;
|
|
6525
|
+
var isAxisAligned = (a, b) => Math.abs(a.x - b.x) < EPS || Math.abs(a.y - b.y) < EPS;
|
|
6526
|
+
var orientationOf = (a, b) => {
|
|
6527
|
+
const dx = Math.abs(a.x - b.x);
|
|
6528
|
+
const dy = Math.abs(a.y - b.y);
|
|
6529
|
+
if (dx < EPS && dy >= EPS) return "vertical";
|
|
6530
|
+
if (dy < EPS && dx >= EPS) return "horizontal";
|
|
6531
|
+
throw new Error("Non-orthogonal or degenerate segment detected.");
|
|
6532
|
+
};
|
|
6533
|
+
var assertOrthogonalPolyline = (pts) => {
|
|
6534
|
+
if (pts.length < 2) {
|
|
6535
|
+
throw new Error("Polyline must have at least two points.");
|
|
6536
|
+
}
|
|
6537
|
+
for (let i = 0; i < pts.length - 1; i++) {
|
|
6538
|
+
const a = pts[i];
|
|
6539
|
+
const b = pts[i + 1];
|
|
6540
|
+
if (!isAxisAligned(a, b)) {
|
|
6541
|
+
throw new Error("Polyline contains a non-orthogonal segment.");
|
|
6542
|
+
}
|
|
6543
|
+
const manhattan = Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
|
|
6544
|
+
if (manhattan < MIN_LEN) {
|
|
6545
|
+
throw new Error("Polyline contains a near-zero length segment.");
|
|
6538
6546
|
}
|
|
6539
|
-
movableSegments.push({ start, end, freedom, dir: dir(freedom) });
|
|
6540
6547
|
}
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
|
|
6545
|
-
|
|
6546
|
-
|
|
6547
|
-
|
|
6548
|
-
|
|
6548
|
+
};
|
|
6549
|
+
var uniqSortedWithTol = (vals, tol = EPS) => {
|
|
6550
|
+
const sorted = vals.slice().sort((a, b) => a - b);
|
|
6551
|
+
const out = [];
|
|
6552
|
+
for (const v of sorted) {
|
|
6553
|
+
if (out.length === 0 || Math.abs(v - out[out.length - 1]) > tol) out.push(v);
|
|
6554
|
+
}
|
|
6555
|
+
return out;
|
|
6556
|
+
};
|
|
6557
|
+
var keyForPolyline = (pts, decimals = 9) => pts.map((p) => `${p.x.toFixed(decimals)},${p.y.toFixed(decimals)}`).join("|");
|
|
6558
|
+
var preprocessElbow = (pts, tol = MIN_LEN) => {
|
|
6559
|
+
if (pts.length === 0) return [];
|
|
6560
|
+
const out = [{ ...pts[0] }];
|
|
6561
|
+
for (let i = 1; i < pts.length; i++) {
|
|
6562
|
+
const p = pts[i];
|
|
6563
|
+
const last = out[out.length - 1];
|
|
6564
|
+
const manhattan = Math.abs(p.x - last.x) + Math.abs(p.y - last.y);
|
|
6565
|
+
if (manhattan > tol) out.push({ ...p });
|
|
6566
|
+
}
|
|
6567
|
+
return out;
|
|
6568
|
+
};
|
|
6569
|
+
var collectAxisCandidates = (axis, guidelines, currentCoord) => {
|
|
6570
|
+
const positions = [];
|
|
6571
|
+
for (const g of guidelines) {
|
|
6572
|
+
if (axis === "x") {
|
|
6573
|
+
if (g.orientation === "vertical" && typeof g.x === "number") {
|
|
6574
|
+
positions.push(g.x);
|
|
6549
6575
|
}
|
|
6550
|
-
relevantPositions.push(segment.start.x);
|
|
6551
6576
|
} else {
|
|
6552
|
-
|
|
6553
|
-
|
|
6554
|
-
relevantPositions.push(guideline.y);
|
|
6555
|
-
}
|
|
6577
|
+
if (g.orientation === "horizontal" && typeof g.y === "number") {
|
|
6578
|
+
positions.push(g.y);
|
|
6556
6579
|
}
|
|
6557
|
-
relevantPositions.push(segment.start.y);
|
|
6558
6580
|
}
|
|
6559
|
-
segmentGuidelineOptions.push(
|
|
6560
|
-
[...new Set(relevantPositions)].sort((a, b) => a - b)
|
|
6561
|
-
);
|
|
6562
6581
|
}
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
|
|
6570
|
-
|
|
6571
|
-
|
|
6582
|
+
positions.push(currentCoord);
|
|
6583
|
+
return uniqSortedWithTol(positions);
|
|
6584
|
+
};
|
|
6585
|
+
var computeFreedom = (prev, start, end) => {
|
|
6586
|
+
const orient = orientationOf(start, end);
|
|
6587
|
+
if (orient === "horizontal") {
|
|
6588
|
+
const facing = prev.y <= start.y ? "y+" : "y-";
|
|
6589
|
+
return { axis: "y", facing };
|
|
6590
|
+
} else {
|
|
6591
|
+
const facing = prev.x <= start.x ? "x+" : "x-";
|
|
6592
|
+
return { axis: "x", facing };
|
|
6593
|
+
}
|
|
6594
|
+
};
|
|
6595
|
+
var cartesian = (arrays) => arrays.length === 0 ? [[]] : arrays.reduce(
|
|
6596
|
+
(acc, curr) => acc.flatMap((a) => curr.map((c) => [...a, c])),
|
|
6597
|
+
[[]]
|
|
6598
|
+
);
|
|
6599
|
+
var generateElbowVariants = ({
|
|
6600
|
+
baseElbow,
|
|
6601
|
+
guidelines
|
|
6602
|
+
}) => {
|
|
6603
|
+
const elbow = preprocessElbow(baseElbow);
|
|
6604
|
+
assertOrthogonalPolyline(elbow);
|
|
6605
|
+
const nPts = elbow.length;
|
|
6606
|
+
const nSegs = nPts - 1;
|
|
6607
|
+
if (nSegs < 5) {
|
|
6608
|
+
return {
|
|
6609
|
+
elbowVariants: [elbow.map((p) => ({ ...p }))],
|
|
6610
|
+
movableSegments: []
|
|
6611
|
+
};
|
|
6612
|
+
}
|
|
6613
|
+
const firstMovableIndex = 2;
|
|
6614
|
+
const lastMovableIndex = nPts - 4;
|
|
6615
|
+
const movableSegments = [];
|
|
6616
|
+
const movableIdx = [];
|
|
6617
|
+
const axes = [];
|
|
6618
|
+
const optionsPerSegment = [];
|
|
6619
|
+
for (let i = firstMovableIndex; i <= lastMovableIndex; i++) {
|
|
6620
|
+
const prev = elbow[i - 1];
|
|
6621
|
+
const start = elbow[i];
|
|
6622
|
+
const end = elbow[i + 1];
|
|
6623
|
+
const next2 = elbow[i + 2];
|
|
6624
|
+
const { axis, facing } = computeFreedom(prev, start, end);
|
|
6625
|
+
movableSegments.push({
|
|
6626
|
+
start: { ...start },
|
|
6627
|
+
end: { ...end },
|
|
6628
|
+
freedom: facing,
|
|
6629
|
+
dir: dir(facing)
|
|
6630
|
+
});
|
|
6631
|
+
movableIdx.push(i);
|
|
6632
|
+
axes.push(axis);
|
|
6633
|
+
const currentCoord = axis === "x" ? start.x : start.y;
|
|
6634
|
+
const rawCandidates = collectAxisCandidates(axis, guidelines, currentCoord);
|
|
6635
|
+
const filtered = rawCandidates.filter((pos) => {
|
|
6636
|
+
if (axis === "y") {
|
|
6637
|
+
const lenPrev = Math.abs(prev.y - pos);
|
|
6638
|
+
const lenNext = Math.abs(next2.y - pos);
|
|
6639
|
+
return lenPrev > MIN_LEN && lenNext > MIN_LEN;
|
|
6640
|
+
} else {
|
|
6641
|
+
const lenPrev = Math.abs(prev.x - pos);
|
|
6642
|
+
const lenNext = Math.abs(next2.x - pos);
|
|
6643
|
+
return lenPrev > MIN_LEN && lenNext > MIN_LEN;
|
|
6572
6644
|
}
|
|
6573
|
-
}
|
|
6574
|
-
|
|
6575
|
-
}
|
|
6576
|
-
const
|
|
6645
|
+
});
|
|
6646
|
+
optionsPerSegment.push(filtered);
|
|
6647
|
+
}
|
|
6648
|
+
const combos = cartesian(optionsPerSegment);
|
|
6649
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6577
6650
|
const elbowVariants = [];
|
|
6578
|
-
|
|
6579
|
-
const
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6651
|
+
{
|
|
6652
|
+
const key = keyForPolyline(elbow);
|
|
6653
|
+
seen.add(key);
|
|
6654
|
+
elbowVariants.push(elbow.map((p) => ({ ...p })));
|
|
6655
|
+
}
|
|
6656
|
+
for (const combo of combos) {
|
|
6657
|
+
if (combo.length === 0) continue;
|
|
6658
|
+
const variant = elbow.map((p) => ({ ...p }));
|
|
6659
|
+
for (let k = 0; k < movableIdx.length; k++) {
|
|
6660
|
+
const segIndex = movableIdx[k];
|
|
6661
|
+
const axis = axes[k];
|
|
6662
|
+
const newPos = combo[k];
|
|
6663
|
+
if (typeof newPos !== "number" || Number.isNaN(newPos)) continue;
|
|
6664
|
+
if (axis === "y") {
|
|
6665
|
+
variant[segIndex] = { ...variant[segIndex], y: newPos };
|
|
6666
|
+
variant[segIndex + 1] = { ...variant[segIndex + 1], y: newPos };
|
|
6587
6667
|
} else {
|
|
6588
|
-
variant[
|
|
6589
|
-
variant[
|
|
6668
|
+
variant[segIndex] = { ...variant[segIndex], x: newPos };
|
|
6669
|
+
variant[segIndex + 1] = { ...variant[segIndex + 1], x: newPos };
|
|
6590
6670
|
}
|
|
6591
6671
|
}
|
|
6592
|
-
|
|
6672
|
+
try {
|
|
6673
|
+
assertOrthogonalPolyline(variant);
|
|
6674
|
+
} catch {
|
|
6675
|
+
continue;
|
|
6676
|
+
}
|
|
6677
|
+
const key = keyForPolyline(variant);
|
|
6678
|
+
if (!seen.has(key)) {
|
|
6679
|
+
seen.add(key);
|
|
6680
|
+
elbowVariants.push(variant);
|
|
6681
|
+
}
|
|
6593
6682
|
}
|
|
6594
|
-
return {
|
|
6595
|
-
elbowVariants,
|
|
6596
|
-
movableSegments
|
|
6597
|
-
};
|
|
6683
|
+
return { elbowVariants, movableSegments };
|
|
6598
6684
|
};
|
|
6599
6685
|
|
|
6600
6686
|
// lib/solvers/GuidelinesSolver/visualizeGuidelines.ts
|
|
@@ -6642,6 +6728,7 @@ var SchematicTraceSingleLineSolver = class extends BaseSolver {
|
|
|
6642
6728
|
chipMap;
|
|
6643
6729
|
movableSegments;
|
|
6644
6730
|
baseElbow;
|
|
6731
|
+
allCandidatePaths;
|
|
6645
6732
|
queuedCandidatePaths;
|
|
6646
6733
|
chipObstacleSpatialIndex;
|
|
6647
6734
|
solvedTracePath = null;
|
|
@@ -6691,7 +6778,8 @@ var SchematicTraceSingleLineSolver = class extends BaseSolver {
|
|
|
6691
6778
|
}
|
|
6692
6779
|
return len;
|
|
6693
6780
|
};
|
|
6694
|
-
this.
|
|
6781
|
+
this.allCandidatePaths = [this.baseElbow, ...elbowVariants];
|
|
6782
|
+
this.queuedCandidatePaths = [...this.allCandidatePaths].sort(
|
|
6695
6783
|
(a, b) => getPathLength(a) - getPathLength(b)
|
|
6696
6784
|
);
|
|
6697
6785
|
}
|
|
@@ -6728,12 +6816,12 @@ var SchematicTraceSingleLineSolver = class extends BaseSolver {
|
|
|
6728
6816
|
const bounds = getInputChipBounds(this.chipMap[startPin.chipId]);
|
|
6729
6817
|
const dx = end.x - start.x;
|
|
6730
6818
|
const dy = end.y - start.y;
|
|
6731
|
-
const
|
|
6819
|
+
const EPS2 = 1e-9;
|
|
6732
6820
|
const onLeft = Math.abs(start.x - bounds.minX) < 1e-9;
|
|
6733
6821
|
const onRight = Math.abs(start.x - bounds.maxX) < 1e-9;
|
|
6734
6822
|
const onBottom = Math.abs(start.y - bounds.minY) < 1e-9;
|
|
6735
6823
|
const onTop = Math.abs(start.y - bounds.maxY) < 1e-9;
|
|
6736
|
-
const entersInterior = onLeft && dx >
|
|
6824
|
+
const entersInterior = onLeft && dx > EPS2 || onRight && dx < -EPS2 || onBottom && dy > EPS2 || onTop && dy < -EPS2;
|
|
6737
6825
|
if (entersInterior) return;
|
|
6738
6826
|
if (!excludeChipIds.includes(startPin.chipId)) {
|
|
6739
6827
|
excludeChipIds.push(startPin.chipId);
|
|
@@ -6748,12 +6836,12 @@ var SchematicTraceSingleLineSolver = class extends BaseSolver {
|
|
|
6748
6836
|
const bounds = getInputChipBounds(this.chipMap[endPin.chipId]);
|
|
6749
6837
|
const dx = start.x - end.x;
|
|
6750
6838
|
const dy = start.y - end.y;
|
|
6751
|
-
const
|
|
6839
|
+
const EPS2 = 1e-9;
|
|
6752
6840
|
const onLeft = Math.abs(end.x - bounds.minX) < 1e-9;
|
|
6753
6841
|
const onRight = Math.abs(end.x - bounds.maxX) < 1e-9;
|
|
6754
6842
|
const onBottom = Math.abs(end.y - bounds.minY) < 1e-9;
|
|
6755
6843
|
const onTop = Math.abs(end.y - bounds.maxY) < 1e-9;
|
|
6756
|
-
const entersInterior = onLeft && dx >
|
|
6844
|
+
const entersInterior = onLeft && dx > EPS2 || onRight && dx < -EPS2 || onBottom && dy > EPS2 || onTop && dy < -EPS2;
|
|
6757
6845
|
if (entersInterior) return;
|
|
6758
6846
|
if (!excludeChipIds.includes(endPin.chipId)) {
|
|
6759
6847
|
excludeChipIds.push(endPin.chipId);
|
|
@@ -6956,13 +7044,13 @@ var TraceOverlapIssueSolver = class extends BaseSolver {
|
|
|
6956
7044
|
}
|
|
6957
7045
|
}
|
|
6958
7046
|
_step() {
|
|
6959
|
-
const
|
|
7047
|
+
const EPS2 = 1e-6;
|
|
6960
7048
|
const offsets = this.overlappingTraceSegments.map((_, idx) => {
|
|
6961
7049
|
const n = Math.floor(idx / 2) + 1;
|
|
6962
7050
|
const signed = idx % 2 === 0 ? -n : n;
|
|
6963
7051
|
return signed * this.SHIFT_DISTANCE;
|
|
6964
7052
|
});
|
|
6965
|
-
const eq = (a, b) => Math.abs(a - b) <
|
|
7053
|
+
const eq = (a, b) => Math.abs(a - b) < EPS2;
|
|
6966
7054
|
const samePoint = (p, q) => !!p && !!q && eq(p.x, q.x) && eq(p.y, q.y);
|
|
6967
7055
|
this.overlappingTraceSegments.forEach((group, gidx) => {
|
|
6968
7056
|
const offset = offsets[gidx];
|
|
@@ -6985,8 +7073,8 @@ var TraceOverlapIssueSolver = class extends BaseSolver {
|
|
|
6985
7073
|
if (si === 0 || si === pts.length - 2) continue;
|
|
6986
7074
|
const start = pts[si];
|
|
6987
7075
|
const end = pts[si + 1];
|
|
6988
|
-
const isVertical = Math.abs(start.x - end.x) <
|
|
6989
|
-
const isHorizontal = Math.abs(start.y - end.y) <
|
|
7076
|
+
const isVertical = Math.abs(start.x - end.x) < EPS2;
|
|
7077
|
+
const isHorizontal = Math.abs(start.y - end.y) < EPS2;
|
|
6990
7078
|
if (!isVertical && !isHorizontal) continue;
|
|
6991
7079
|
if (isVertical) {
|
|
6992
7080
|
if (!appliedX.has(si)) {
|
|
@@ -7095,7 +7183,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
7095
7183
|
return islands;
|
|
7096
7184
|
}
|
|
7097
7185
|
findNextOverlapIssue() {
|
|
7098
|
-
const
|
|
7186
|
+
const EPS2 = 1e-6;
|
|
7099
7187
|
const netIds = Object.keys(this.traceNetIslands);
|
|
7100
7188
|
for (let i = 0; i < netIds.length; i++) {
|
|
7101
7189
|
for (let j = i + 1; j < netIds.length; j++) {
|
|
@@ -7113,7 +7201,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
7113
7201
|
const minB = Math.min(b1, b2);
|
|
7114
7202
|
const maxB = Math.max(b1, b2);
|
|
7115
7203
|
const overlap = Math.min(maxA, maxB) - Math.max(minA, minB);
|
|
7116
|
-
return overlap >
|
|
7204
|
+
return overlap > EPS2;
|
|
7117
7205
|
};
|
|
7118
7206
|
for (let pa = 0; pa < pathsA.length; pa++) {
|
|
7119
7207
|
const pathA = pathsA[pa];
|
|
@@ -7121,8 +7209,8 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
7121
7209
|
for (let sa = 0; sa < ptsA.length - 1; sa++) {
|
|
7122
7210
|
const a1 = ptsA[sa];
|
|
7123
7211
|
const a2 = ptsA[sa + 1];
|
|
7124
|
-
const aVert = Math.abs(a1.x - a2.x) <
|
|
7125
|
-
const aHorz = Math.abs(a1.y - a2.y) <
|
|
7212
|
+
const aVert = Math.abs(a1.x - a2.x) < EPS2;
|
|
7213
|
+
const aHorz = Math.abs(a1.y - a2.y) < EPS2;
|
|
7126
7214
|
if (!aVert && !aHorz) continue;
|
|
7127
7215
|
for (let pb = 0; pb < pathsB.length; pb++) {
|
|
7128
7216
|
const pathB = pathsB[pb];
|
|
@@ -7130,11 +7218,11 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
7130
7218
|
for (let sb = 0; sb < ptsB.length - 1; sb++) {
|
|
7131
7219
|
const b1 = ptsB[sb];
|
|
7132
7220
|
const b2 = ptsB[sb + 1];
|
|
7133
|
-
const bVert = Math.abs(b1.x - b2.x) <
|
|
7134
|
-
const bHorz = Math.abs(b1.y - b2.y) <
|
|
7221
|
+
const bVert = Math.abs(b1.x - b2.x) < EPS2;
|
|
7222
|
+
const bHorz = Math.abs(b1.y - b2.y) < EPS2;
|
|
7135
7223
|
if (!bVert && !bHorz) continue;
|
|
7136
7224
|
if (aVert && bVert) {
|
|
7137
|
-
if (Math.abs(a1.x - b1.x) <
|
|
7225
|
+
if (Math.abs(a1.x - b1.x) < EPS2) {
|
|
7138
7226
|
if (overlaps1D(a1.y, a2.y, b1.y, b2.y)) {
|
|
7139
7227
|
const keyA = `${pa}:${sa}`;
|
|
7140
7228
|
const keyB = `${pb}:${sb}`;
|
|
@@ -7155,7 +7243,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
7155
7243
|
}
|
|
7156
7244
|
}
|
|
7157
7245
|
} else if (aHorz && bHorz) {
|
|
7158
|
-
if (Math.abs(a1.y - b1.y) <
|
|
7246
|
+
if (Math.abs(a1.y - b1.y) < EPS2) {
|
|
7159
7247
|
if (overlaps1D(a1.x, a2.x, b1.x, b2.x)) {
|
|
7160
7248
|
const keyA = `${pa}:${sa}`;
|
|
7161
7249
|
const keyB = `${pb}:${sb}`;
|
|
@@ -7270,24 +7358,24 @@ function getRectBounds(center, w, h) {
|
|
|
7270
7358
|
}
|
|
7271
7359
|
|
|
7272
7360
|
// lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/collisions.ts
|
|
7273
|
-
function segmentIntersectsRect(p1, p2, rect,
|
|
7274
|
-
const isVert = Math.abs(p1.x - p2.x) <
|
|
7275
|
-
const isHorz = Math.abs(p1.y - p2.y) <
|
|
7361
|
+
function segmentIntersectsRect(p1, p2, rect, EPS2 = 1e-9) {
|
|
7362
|
+
const isVert = Math.abs(p1.x - p2.x) < EPS2;
|
|
7363
|
+
const isHorz = Math.abs(p1.y - p2.y) < EPS2;
|
|
7276
7364
|
if (!isVert && !isHorz) return false;
|
|
7277
7365
|
if (isVert) {
|
|
7278
7366
|
const x = p1.x;
|
|
7279
|
-
if (x < rect.minX -
|
|
7367
|
+
if (x < rect.minX - EPS2 || x > rect.maxX + EPS2) return false;
|
|
7280
7368
|
const segMinY = Math.min(p1.y, p2.y);
|
|
7281
7369
|
const segMaxY = Math.max(p1.y, p2.y);
|
|
7282
7370
|
const overlap = Math.min(segMaxY, rect.maxY) - Math.max(segMinY, rect.minY);
|
|
7283
|
-
return overlap >
|
|
7371
|
+
return overlap > EPS2;
|
|
7284
7372
|
} else {
|
|
7285
7373
|
const y = p1.y;
|
|
7286
|
-
if (y < rect.minY -
|
|
7374
|
+
if (y < rect.minY - EPS2 || y > rect.maxY + EPS2) return false;
|
|
7287
7375
|
const segMinX = Math.min(p1.x, p2.x);
|
|
7288
7376
|
const segMaxX = Math.max(p1.x, p2.x);
|
|
7289
7377
|
const overlap = Math.min(segMaxX, rect.maxX) - Math.max(segMinX, rect.minX);
|
|
7290
|
-
return overlap >
|
|
7378
|
+
return overlap > EPS2;
|
|
7291
7379
|
}
|
|
7292
7380
|
}
|
|
7293
7381
|
function rectIntersectsAnyTrace(bounds, inputTraceMap, hostPathId, hostSegIndex) {
|
|
@@ -7612,14 +7700,14 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
|
|
|
7612
7700
|
};
|
|
7613
7701
|
let bestCandidate = null;
|
|
7614
7702
|
let bestScore = -Infinity;
|
|
7615
|
-
const
|
|
7703
|
+
const EPS2 = 1e-6;
|
|
7616
7704
|
for (const curr of tracesToScan) {
|
|
7617
7705
|
const pts = curr.tracePath.slice();
|
|
7618
7706
|
for (let si = 0; si < pts.length - 1; si++) {
|
|
7619
7707
|
const a = pts[si];
|
|
7620
7708
|
const b = pts[si + 1];
|
|
7621
|
-
const isH = Math.abs(a.y - b.y) <
|
|
7622
|
-
const isV = Math.abs(a.x - b.x) <
|
|
7709
|
+
const isH = Math.abs(a.y - b.y) < EPS2;
|
|
7710
|
+
const isV = Math.abs(a.x - b.x) < EPS2;
|
|
7623
7711
|
if (!isH && !isV) continue;
|
|
7624
7712
|
const segmentAllowed = isH ? ["y+", "y-"] : ["x+", "x-"];
|
|
7625
7713
|
const candidateOrients = orientations.filter(
|
|
@@ -24,6 +24,7 @@ export class SchematicTraceSingleLineSolver extends BaseSolver {
|
|
|
24
24
|
movableSegments: Array<MovableSegment>
|
|
25
25
|
baseElbow: Point[]
|
|
26
26
|
|
|
27
|
+
allCandidatePaths: Array<Point[]>
|
|
27
28
|
queuedCandidatePaths: Array<Point[]>
|
|
28
29
|
|
|
29
30
|
chipObstacleSpatialIndex: ChipObstacleSpatialIndex
|
|
@@ -91,7 +92,8 @@ export class SchematicTraceSingleLineSolver extends BaseSolver {
|
|
|
91
92
|
return len
|
|
92
93
|
}
|
|
93
94
|
|
|
94
|
-
this.
|
|
95
|
+
this.allCandidatePaths = [this.baseElbow, ...elbowVariants]
|
|
96
|
+
this.queuedCandidatePaths = [...this.allCandidatePaths].sort(
|
|
95
97
|
(a, b) => getPathLength(a) - getPathLength(b),
|
|
96
98
|
)
|
|
97
99
|
}
|