crossrefitem: fix terminal name sorting for power contacts

The previous sort used QString::toInt() to order terminal names,
which returns 0 for any string containing a non-numeric prefix
(e.g. "R1", "R2", "L1", "L2"...). This caused undefined sort order
and incorrect pole pairing in the Xref contact mirror.

Example: a 4-pole NC power contact with terminals R1..R8 was
displaying R1/R3, R5/R7, R2/R4, R6/R8 instead of the correct
R1/R2, R3/R4, R5/R6, R7/R8.

Fix: extract the trailing numeric part of each terminal name and
compare prefixes separately. If both names share the same prefix
and both have a trailing number, sort numerically on that number;
otherwise fall back to full string comparison.

This covers all naming conventions: "1"/"2"/"3", "R1"/"R2"/"R3",
"L1"/"L2"/"L3", etc.

Applied in both drawContact() and setUpCrossBoundingRect().
This commit is contained in:
Laurent Trinques
2026-05-23 15:50:11 +02:00
parent d949e6eb8c
commit 7d718bb9a0
+24 -2
View File
@@ -560,7 +560,16 @@ void CrossRefItem::setUpCrossBoundingRect(QPainter &painter)
if (is_power) { if (is_power) {
std::sort(tnames.begin(), tnames.end(), std::sort(tnames.begin(), tnames.end(),
[](const QString &a, const QString &b){ [](const QString &a, const QString &b){
return a.toInt() < b.toInt(); int i_a = a.size();
while (i_a > 0 && a[i_a-1].isDigit()) --i_a;
int i_b = b.size();
while (i_b > 0 && b[i_b-1].isDigit()) --i_b;
bool a_ok = false, b_ok = false;
int ai = a.mid(i_a).toInt(&a_ok);
int bi = b.mid(i_b).toInt(&b_ok);
if (a_ok && b_ok && a.left(i_a) == b.left(i_b))
return ai < bi;
return a < b;
}); });
} }
} }
@@ -741,9 +750,22 @@ QRectF CrossRefItem::drawContact(QPainter &painter, int flags, Element *elmt, in
} }
if (is_power_ctc) { if (is_power_ctc) {
// Sort terminals alphanumerically so names like "R1","R2"... or "1","2"...
// are ordered correctly. Extract trailing digits for numeric comparison;
// fall back to full string comparison when no digits are found.
std::sort(terminal_names.begin(), terminal_names.end(), std::sort(terminal_names.begin(), terminal_names.end(),
[](const QString &a, const QString &b){ [](const QString &a, const QString &b){
return a.toInt() < b.toInt(); // Extract trailing numeric part
int i_a = a.size();
while (i_a > 0 && a[i_a-1].isDigit()) --i_a;
int i_b = b.size();
while (i_b > 0 && b[i_b-1].isDigit()) --i_b;
bool a_ok = false, b_ok = false;
int ai = a.mid(i_a).toInt(&a_ok);
int bi = b.mid(i_b).toInt(&b_ok);
if (a_ok && b_ok && a.left(i_a) == b.left(i_b))
return ai < bi;
return a < b;
}); });
// Pick the pair for this pole: pole 0 → [0,1], pole 1 → [2,3], etc. // Pick the pair for this pole: pole 0 → [0,1], pole 1 → [2,3], etc.
int idx = pole_index * 2; int idx = pole_index * 2;