diff --git a/lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver.ts b/lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver.ts
index 48b46c9..8fa458b 100644
--- a/lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver.ts
+++ b/lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver.ts
@@ -74,7 +74,20 @@ export class MspConnectionPairSolver extends BaseSolver {
}
}
- this.queuedDcNetIds = Object.keys(netConnMap.netMap)
+ // Only queue nets that have direct connections (traces).
+ // Nets connected solely via netConnections (net labels) should not
+ // produce MSP pairs – they receive net labels instead of traces.
+ const directNetIds = new Set(Object.keys(directConnMap.netMap))
+ this.queuedDcNetIds = Object.keys(netConnMap.netMap).filter((netId) => {
+ // A net qualifies for tracing if at least one of its pins appears
+ // in the direct-connection map under the same global net.
+ const allIds = netConnMap.getIdsConnectedToNet(netId) as string[]
+ const pins = allIds.filter((id) => !!this.pinMap[id])
+ return pins.some((pinId) => {
+ const dcNet = directConnMap.getNetConnectedToId(pinId)
+ return dcNet != null && directNetIds.has(dcNet)
+ })
+ })
}
override getConstructorParams(): ConstructorParameters<
diff --git a/tests/examples/__snapshots__/example01.snap.svg b/tests/examples/__snapshots__/example01.snap.svg
index 293bf05..8f364a3 100644
--- a/tests/examples/__snapshots__/example01.snap.svg
+++ b/tests/examples/__snapshots__/example01.snap.svg
@@ -49,6 +49,9 @@ y-" data-x="-4" data-y="-0.5" cx="67.72277227722776" cy="356.03960396039605" r="
+
+
+
@@ -73,9 +76,6 @@ y-" data-x="-4" data-y="-0.5" cx="67.72277227722776" cy="356.03960396039605" r="
-
-
-
@@ -94,6 +94,9 @@ y-" data-x="-4" data-y="-0.5" cx="67.72277227722776" cy="356.03960396039605" r="
+
+
+
diff --git a/tests/examples/__snapshots__/example12.snap.svg b/tests/examples/__snapshots__/example12.snap.svg
index 164322e..f167fd7 100644
--- a/tests/examples/__snapshots__/example12.snap.svg
+++ b/tests/examples/__snapshots__/example12.snap.svg
@@ -2,88 +2,88 @@
+x+" data-x="1.1" data-y="0.2" cx="301.57112526539277" cy="201.4336522292994" r="3" fill="hsl(218, 100%, 50%, 0.8)" />
+x+" data-x="1.1" data-y="0" cx="301.57112526539277" cy="225.21284543524422" r="3" fill="hsl(219, 100%, 50%, 0.8)" />
+x+" data-x="1.1" data-y="-0.2" cx="301.57112526539277" cy="248.99203864118903" r="3" fill="hsl(220, 100%, 50%, 0.8)" />
+x-" data-x="0.5499999999999996" data-y="-1.7944553499999996" cx="236.17834394904452" cy="438.5663477707006" r="3" fill="hsl(226, 100%, 50%, 0.8)" />
+x+" data-x="1.6499999999999997" data-y="-1.7944553499999996" cx="366.9639065817409" cy="438.5663477707006" r="3" fill="hsl(227, 100%, 50%, 0.8)" />
+x-" data-x="2.3099999999999996" data-y="0.01999999999999985" cx="445.4352441613587" cy="222.83492611464976" r="3" fill="hsl(121, 100%, 50%, 0.8)" />
+x+" data-x="3.41" data-y="0.01999999999999985" cx="576.2208067940551" cy="222.83492611464976" r="3" fill="hsl(122, 100%, 50%, 0.8)" />
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -113,12 +113,12 @@ x+" data-x="3.41" data-y="0.01999999999999985" cx="549.090909090909" cy="227.750
// Calculate real coordinates using inverse transformation
const matrix = {
- "a": 112.88046764765167,
+ "a": 118.89596602972397,
"c": 0,
- "e": 164.16851441241687,
+ "e": 170.78556263269638,
"b": 0,
- "d": -112.88046764765167,
- "f": 230.00856722434997
+ "d": -118.89596602972397,
+ "f": 225.21284543524422
};
// Manually invert and apply the affine transform
// Since we only use translate and scale, we can directly compute:
diff --git a/tests/examples/__snapshots__/example13.snap.svg b/tests/examples/__snapshots__/example13.snap.svg
index 08e47d6..a5d7fd4 100644
--- a/tests/examples/__snapshots__/example13.snap.svg
+++ b/tests/examples/__snapshots__/example13.snap.svg
@@ -77,10 +77,13 @@ x-" data-x="3.435" data-y="3" cx="513.5461404526988" cy="157.49274521183986" r="
x+" data-x="4.5649999999999995" data-y="3" cx="586.9994196169471" cy="157.49274521183986" r="3" fill="hsl(58, 100%, 50%, 0.8)" />
-
+
-
+
+
+
+
@@ -197,23 +200,20 @@ x+" data-x="4.5649999999999995" data-y="3" cx="586.9994196169471" cy="157.492745
-
+
-
+
-
+
-
-
-
@@ -236,10 +236,13 @@ x+" data-x="4.5649999999999995" data-y="3" cx="586.9994196169471" cy="157.492745
-
+
+
+
+
-
+
diff --git a/tests/examples/__snapshots__/example15.snap.svg b/tests/examples/__snapshots__/example15.snap.svg
index fa7b2fb..8bf97bb 100644
--- a/tests/examples/__snapshots__/example15.snap.svg
+++ b/tests/examples/__snapshots__/example15.snap.svg
@@ -335,13 +335,25 @@ y-" data-x="-2.025" data-y="-2.7" cx="318.5204755614267" cy="526.0237780713342"
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -812,28 +824,16 @@ y-" data-x="-2.025" data-y="-2.7" cx="318.5204755614267" cy="526.0237780713342"
-
-
-
-
-
-
-
+
-
+
-
+
-
-
-
-
-
-
-
+
@@ -890,13 +890,25 @@ y-" data-x="-2.025" data-y="-2.7" cx="318.5204755614267" cy="526.0237780713342"
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
diff --git a/tests/examples/__snapshots__/example16.snap.svg b/tests/examples/__snapshots__/example16.snap.svg
index 24745c4..c9921b4 100644
--- a/tests/examples/__snapshots__/example16.snap.svg
+++ b/tests/examples/__snapshots__/example16.snap.svg
@@ -2,92 +2,95 @@
+x+" data-x="1.2000000000000002" data-y="-0.30000000000000004" cx="308.80000000000007" cy="440.68" r="3" fill="hsl(319, 100%, 50%, 0.8)" />
+x-" data-x="-1.2000000000000002" data-y="-0.30000000000000004" cx="40" cy="440.68" r="3" fill="hsl(320, 100%, 50%, 0.8)" />
+x+" data-x="1.2000000000000002" data-y="0.09999999999999998" cx="308.80000000000007" cy="395.88" r="3" fill="hsl(321, 100%, 50%, 0.8)" />
+x-" data-x="-1.2000000000000002" data-y="0.30000000000000004" cx="40" cy="373.47999999999996" r="3" fill="hsl(322, 100%, 50%, 0.8)" />
+x-" data-x="-1.2000000000000002" data-y="0.10000000000000003" cx="40" cy="395.88" r="3" fill="hsl(323, 100%, 50%, 0.8)" />
+x-" data-x="-1.2000000000000002" data-y="-0.09999999999999998" cx="40" cy="418.28" r="3" fill="hsl(324, 100%, 50%, 0.8)" />
+x+" data-x="1.2000000000000002" data-y="-0.10000000000000003" cx="308.80000000000007" cy="418.28" r="3" fill="hsl(325, 100%, 50%, 0.8)" />
+x+" data-x="1.2000000000000002" data-y="0.30000000000000004" cx="308.80000000000007" cy="373.47999999999996" r="3" fill="hsl(326, 100%, 50%, 0.8)" />
+x-" data-x="1.6" data-y="2.105" cx="353.6" cy="171.32" r="3" fill="hsl(218, 100%, 50%, 0.8)" />
+x-" data-x="1.6" data-y="1.9049999999999998" cx="353.6" cy="193.72" r="3" fill="hsl(219, 100%, 50%, 0.8)" />
+x-" data-x="1.6" data-y="1.7049999999999998" cx="353.6" cy="216.12" r="3" fill="hsl(220, 100%, 50%, 0.8)" />
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
@@ -122,7 +125,7 @@ x-" data-x="1.6" data-y="1.7049999999999998" cx="353.6" cy="244.12000000000006"
"e": 174.40000000000003,
"b": 0,
"d": -112,
- "f": 435.08000000000004
+ "f": 407.08
};
// Manually invert and apply the affine transform
// Since we only use translate and scale, we can directly compute:
diff --git a/tests/examples/__snapshots__/example21.snap.svg b/tests/examples/__snapshots__/example21.snap.svg
index 5e7e7ce..eed359b 100644
--- a/tests/examples/__snapshots__/example21.snap.svg
+++ b/tests/examples/__snapshots__/example21.snap.svg
@@ -2,209 +2,212 @@
+x-" data-x="-1.4" data-y="-0.6" cx="65.61715719826601" cy="310.3855806525211" r="3" fill="hsl(65, 100%, 50%, 0.8)" />
+x-" data-x="-1.4" data-y="0.6" cx="65.61715719826601" cy="233.7257586128223" r="3" fill="hsl(66, 100%, 50%, 0.8)" />
+x+" data-x="1.4" data-y="0.6" cx="244.49007529089664" cy="233.7257586128223" r="3" fill="hsl(67, 100%, 50%, 0.8)" />
+x+" data-x="1.4" data-y="-0.6" cx="244.49007529089664" cy="310.3855806525211" r="3" fill="hsl(68, 100%, 50%, 0.8)" />
+x-" data-x="3.785" data-y="-0.29999999999999993" cx="396.8514715947981" cy="291.2206251425964" r="3" fill="hsl(175, 100%, 50%, 0.8)" />
+y-" data-x="4.785" data-y="-1.2999999999999998" cx="460.73465662788044" cy="355.10381017567875" r="3" fill="hsl(176, 100%, 50%, 0.8)" />
+x-" data-x="3.785" data-y="-0.4999999999999999" cx="396.8514715947981" cy="303.9972621492129" r="3" fill="hsl(177, 100%, 50%, 0.8)" />
+x+" data-x="5.785" data-y="-0.3999999999999999" cx="524.6178416609628" cy="297.6089436459047" r="3" fill="hsl(179, 100%, 50%, 0.8)" />
+y+" data-x="6.7" data-y="-0.39999999999999925" cx="583.0709559662332" cy="297.6089436459046" r="3" fill="hsl(218, 100%, 50%, 0.8)" />
+y-" data-x="6.7" data-y="-1.4999999999999993" cx="583.0709559662332" cy="367.8804471822952" r="3" fill="hsl(219, 100%, 50%, 0.8)" />
+y+" data-x="2.8699999999999997" data-y="-1.2" cx="338.39835728952767" cy="348.71549167237055" r="3" fill="hsl(337, 100%, 50%, 0.8)" />
+y-" data-x="2.8699999999999997" data-y="-2.3" cx="338.39835728952767" cy="418.98699520876113" r="3" fill="hsl(338, 100%, 50%, 0.8)" />
+y+" data-x="2.9752723250000006" data-y="0.6000000000000003" cx="345.1234887063655" cy="233.72575861282226" r="3" fill="hsl(82, 100%, 50%, 0.8)" />
+y-" data-x="2.9752723250000006" data-y="-0.4999999999999998" cx="345.1234887063655" cy="303.9972621492129" r="3" fill="hsl(83, 100%, 50%, 0.8)" />
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
@@ -239,7 +242,7 @@ y-" data-x="2.9752723250000006" data-y="-0.4999999999999998" cx="345.12348870636
"e": 155.05361624458132,
"b": 0,
"d": -63.88318503308236,
- "f": 265.69929272188
+ "f": 272.0556696326717
};
// Manually invert and apply the affine transform
// Since we only use translate and scale, we can directly compute:
diff --git a/tests/examples/__snapshots__/example22.snap.svg b/tests/examples/__snapshots__/example22.snap.svg
index 7790385..5ef7da2 100644
--- a/tests/examples/__snapshots__/example22.snap.svg
+++ b/tests/examples/__snapshots__/example22.snap.svg
@@ -2,80 +2,80 @@
+x+" data-x="1.2000000000000002" data-y="-0.30000000000000004" cx="308.80000000000007" cy="440.68" r="3" fill="hsl(319, 100%, 50%, 0.8)" />
+x-" data-x="-1.2000000000000002" data-y="-0.30000000000000004" cx="40" cy="440.68" r="3" fill="hsl(320, 100%, 50%, 0.8)" />
+x+" data-x="1.2000000000000002" data-y="0.09999999999999998" cx="308.80000000000007" cy="395.88" r="3" fill="hsl(321, 100%, 50%, 0.8)" />
+x-" data-x="-1.2000000000000002" data-y="0.30000000000000004" cx="40" cy="373.47999999999996" r="3" fill="hsl(322, 100%, 50%, 0.8)" />
+x-" data-x="-1.2000000000000002" data-y="0.10000000000000003" cx="40" cy="395.88" r="3" fill="hsl(323, 100%, 50%, 0.8)" />
+x-" data-x="-1.2000000000000002" data-y="-0.09999999999999998" cx="40" cy="418.28" r="3" fill="hsl(324, 100%, 50%, 0.8)" />
+x+" data-x="1.2000000000000002" data-y="-0.10000000000000003" cx="308.80000000000007" cy="418.28" r="3" fill="hsl(325, 100%, 50%, 0.8)" />
+x+" data-x="1.2000000000000002" data-y="0.30000000000000004" cx="308.80000000000007" cy="373.47999999999996" r="3" fill="hsl(326, 100%, 50%, 0.8)" />
+x-" data-x="1.6" data-y="2.105" cx="353.6" cy="171.32" r="3" fill="hsl(218, 100%, 50%, 0.8)" />
+x-" data-x="1.6" data-y="1.9049999999999998" cx="353.6" cy="193.72" r="3" fill="hsl(219, 100%, 50%, 0.8)" />
+x-" data-x="1.6" data-y="1.7049999999999998" cx="353.6" cy="216.12" r="3" fill="hsl(220, 100%, 50%, 0.8)" />
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -110,7 +110,7 @@ x-" data-x="1.6" data-y="1.7049999999999998" cx="353.6" cy="244.12000000000006"
"e": 174.40000000000003,
"b": 0,
"d": -112,
- "f": 435.08000000000004
+ "f": 407.08
};
// Manually invert and apply the affine transform
// Since we only use translate and scale, we can directly compute:
diff --git a/tests/solvers/MspConnectionPairSolver/MspConnectionPairSolver_repro1.test.ts b/tests/solvers/MspConnectionPairSolver/MspConnectionPairSolver_repro1.test.ts
index ad0356b..b8901e9 100644
--- a/tests/solvers/MspConnectionPairSolver/MspConnectionPairSolver_repro1.test.ts
+++ b/tests/solvers/MspConnectionPairSolver/MspConnectionPairSolver_repro1.test.ts
@@ -10,5 +10,7 @@ test("MspConnectionPairSolver_repro1", () => {
solver.solve()
- expect(solver.mspConnectionPairs.length).toBe(4)
+ // Only directConnections produce MSP pairs (VCC: U1.1↔C1.1, EN: U1.2↔C2.1).
+ // GND is a netConnection and should only receive net labels, not traces.
+ expect(solver.mspConnectionPairs.length).toBe(2)
})
diff --git a/tests/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver_repro61.test.ts b/tests/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver_repro61.test.ts
new file mode 100644
index 0000000..7e937a3
--- /dev/null
+++ b/tests/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver_repro61.test.ts
@@ -0,0 +1,60 @@
+import type { InputProblem } from "lib/types/InputProblem"
+import { test, expect } from "bun:test"
+import { SchematicTracePipelineSolver } from "lib/index"
+
+/**
+ * Repro for issue #79: two capacitors connected only via net labels (VCC, GND).
+ * No direct connections exist, so the solver should NOT produce any traces.
+ * Each pin should only receive a net label, with no trace drawn between them.
+ */
+const inputProblem: InputProblem = {
+ chips: [
+ {
+ chipId: "C1",
+ center: { x: 2, y: 0 },
+ width: 0.5,
+ height: 1,
+ pins: [
+ { pinId: "C1.1", x: 2, y: 0.5 },
+ { pinId: "C1.2", x: 2, y: -0.5 },
+ ],
+ },
+ {
+ chipId: "C2",
+ center: { x: 0, y: 0 },
+ width: 0.5,
+ height: 1,
+ pins: [
+ { pinId: "C2.1", x: 0, y: 0.5 },
+ { pinId: "C2.2", x: 0, y: -0.5 },
+ ],
+ },
+ ],
+ directConnections: [],
+ netConnections: [
+ { netId: "GND", pinIds: ["C1.1", "C2.1"] },
+ { netId: "VCC", pinIds: ["C1.2", "C2.2"] },
+ ],
+ availableNetLabelOrientations: {},
+}
+
+test("repro61: net-label-only connections should not produce traces", () => {
+ const solver = new SchematicTracePipelineSolver(inputProblem)
+ solver.solve()
+
+ expect(solver.solved).toBe(true)
+ expect(solver.failed).toBe(false)
+
+ // No MSP pairs should be created for net-label-only connections
+ const mspPairs = solver.mspConnectionPairSolver!.mspConnectionPairs
+ expect(mspPairs).toHaveLength(0)
+
+ // Net labels should still be placed for each net
+ const labels = solver.netLabelPlacementSolver!.netLabelPlacements
+ expect(labels.length).toBeGreaterThanOrEqual(2)
+
+ // Each net should have labels
+ const netIds = labels.map((l) => l.netId)
+ expect(netIds).toContain("GND")
+ expect(netIds).toContain("VCC")
+})