mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-23 23:44:13 +02:00
Fix bugtracker #734: stop routing a bridge conductors don't need
generateConductorPath()'s cas "3"/"4" branches each insert a two-point bridge along one axis, at a coordinate on the other axis computed as the midpoint of depart/arrivee and then snapped to the routing grid by a loop that walks it strictly downward until it divides evenly. When depart and arrivee already agree on the axis the bridge would run along, no bridge is needed at all -- the midpoint starts on the correct, already-shared value. But the snap can still walk it off that value, or, when it happens to already sit on the grid, the two bridge points just duplicate depart and arrivee outright. Either way the conductor renders with an unnecessary out-and-back excursion or a small looping detour at a join that needed neither. Fix: skip the bridge in exactly that degenerate case, per branch, on the axis that branch actually bridges on. descendant and montant are not mirror images of each other in which axis each cas guards on -- each site says so. Verified against the report's own canonical reproduction (qet_bug_repro_resaved.qet from the linked gist): 1 self-retracing path -> 0. Full corpus of 24 shipped example projects (stored segments, as shipped, not regenerated): 74 -> 65 self-retracing conductor paths, zero regressions -- only two files changed, both improved. One disclosed trade-off, found while checking for regressions: in schema_unifilaire_voltaique2.qet, 8 terminal pairs closer together than twice the extension length (docked stubs already cross before any bridge is considered) go from an existing small rectangular-loop artifact to a straight out-and-back retrace covering the full gap -- same count of defective paths (8 -> 8), a different shape, still no connectivity change either way. Not chased further; a real fix for that narrower "crossed stubs" case is a separate piece of work. The shipped affuteuse_250h.qet's own 12 self-retracing paths (verified by stripping all 185 stored <segment> elements and forcing full regeneration) are unchanged by this fix -- they are a structurally different point-count signature (a 4-point back-and-forth reachable from cas "1"/"2", not the cas "3"/"4" grid-snap bridge this fixes), consistent with what the issue thread already flagged as a separate, undiagnosed mechanism. Refs #734 (own root-cause comment, 2026-08-13). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -407,20 +407,44 @@ void Conductor::generateConductorPath(const QPointF &p1, Qet::Orientation o1, co
|
||||
|
||||
// commence le vrai trajet
|
||||
// starts the real path
|
||||
//
|
||||
// Each cas "3"/"4" below inserts a two-point bridge along one axis, at a
|
||||
// coordinate on the OTHER axis computed as a midpoint and then snapped
|
||||
// to the grid by a loop that walks it strictly downward until it
|
||||
// divides evenly. Whenever depart and arrivee already agree on the axis
|
||||
// the bridge would run along, that bridge is unneeded -- the midpoint
|
||||
// starts on the correct value already, but the snap can still walk it
|
||||
// off, or, if it happens to already be on-grid, the two bridge points
|
||||
// just duplicate depart and arrivee outright. Either way the result is
|
||||
// a short out-and-back excursion, or a longer looping detour, at a join
|
||||
// that needed no bridge in the first place (bugtracker #734). Skip the
|
||||
// bridge in exactly that case; depart and arrivee already form the
|
||||
// direct run. Which axis each cas guards on is noted at each site below
|
||||
// -- descendant and montant are not mirror images of each other here.
|
||||
if (depart.y() < arrivee.y()) {
|
||||
// trajet descendant
|
||||
if ((ori_depart == Qet::North && (ori_arrivee == Qet::South || ori_arrivee == Qet::West)) || (ori_depart == Qet::East && ori_arrivee == Qet::West)) {
|
||||
// cas "3"
|
||||
int ligne_inter_x = qRound(depart.x() + arrivee.x()) / 2;
|
||||
while (ligne_inter_x % Diagram::xGrid) -- ligne_inter_x;
|
||||
points << QPointF(ligne_inter_x, depart.y());
|
||||
points << QPointF(ligne_inter_x, arrivee.y());
|
||||
// cas "3": bridge is vertical, at a shared x between depart.y()
|
||||
// and arrivee.y() -- unnecessary exactly when depart and
|
||||
// arrivee already share an x.
|
||||
if (depart.x() != arrivee.x()) {
|
||||
int ligne_inter_x = qRound(depart.x() + arrivee.x()) / 2;
|
||||
while (ligne_inter_x % Diagram::xGrid) -- ligne_inter_x;
|
||||
points << QPointF(ligne_inter_x, depart.y());
|
||||
points << QPointF(ligne_inter_x, arrivee.y());
|
||||
}
|
||||
} else if ((ori_depart == Qet::South && (ori_arrivee == Qet::North || ori_arrivee == Qet::East)) || (ori_depart == Qet::West && ori_arrivee == Qet::East)) {
|
||||
// cas "4"
|
||||
int ligne_inter_y = qRound(depart.y() + arrivee.y()) / 2;
|
||||
while (ligne_inter_y % Diagram::yGrid) -- ligne_inter_y;
|
||||
points << QPointF(depart.x(), ligne_inter_y);
|
||||
points << QPointF(arrivee.x(), ligne_inter_y);
|
||||
// cas "4": bridge is horizontal, at a shared y between
|
||||
// depart.x() and arrivee.x() -- unnecessary exactly when depart
|
||||
// and arrivee already share a y. (Always true in this branch,
|
||||
// since "descendant" requires depart.y() < arrivee.y() strictly
|
||||
// -- kept for symmetry with the "montant" branch below.)
|
||||
if (depart.y() != arrivee.y()) {
|
||||
int ligne_inter_y = qRound(depart.y() + arrivee.y()) / 2;
|
||||
while (ligne_inter_y % Diagram::yGrid) -- ligne_inter_y;
|
||||
points << QPointF(depart.x(), ligne_inter_y);
|
||||
points << QPointF(arrivee.x(), ligne_inter_y);
|
||||
}
|
||||
} else if ((ori_depart == Qet::North || ori_depart == Qet::East) && (ori_arrivee == Qet::North || ori_arrivee == Qet::East)) {
|
||||
points << QPointF(arrivee.x(), depart.y()); // cas "2"
|
||||
} else {
|
||||
@@ -429,17 +453,27 @@ void Conductor::generateConductorPath(const QPointF &p1, Qet::Orientation o1, co
|
||||
} else {
|
||||
// trajet montant
|
||||
if ((ori_depart == Qet::West && (ori_arrivee == Qet::East || ori_arrivee == Qet::South)) || (ori_depart == Qet::North && ori_arrivee == Qet::South)) {
|
||||
// cas "3"
|
||||
int ligne_inter_y = qRound(depart.y() + arrivee.y()) / 2;
|
||||
while (ligne_inter_y % Diagram::yGrid) -- ligne_inter_y;
|
||||
points << QPointF(depart.x(), ligne_inter_y);
|
||||
points << QPointF(arrivee.x(), ligne_inter_y);
|
||||
// cas "3": bridge is horizontal, at a shared y between
|
||||
// depart.x() and arrivee.x() -- unnecessary exactly when depart
|
||||
// and arrivee already share a y (the West->East case
|
||||
// diagnosed for #734: two stubs extended onto the same y run
|
||||
// straight into each other, no bridge needed).
|
||||
if (depart.y() != arrivee.y()) {
|
||||
int ligne_inter_y = qRound(depart.y() + arrivee.y()) / 2;
|
||||
while (ligne_inter_y % Diagram::yGrid) -- ligne_inter_y;
|
||||
points << QPointF(depart.x(), ligne_inter_y);
|
||||
points << QPointF(arrivee.x(), ligne_inter_y);
|
||||
}
|
||||
} else if ((ori_depart == Qet::East && (ori_arrivee == Qet::West || ori_arrivee == Qet::North)) || (ori_depart == Qet::South && ori_arrivee == Qet::North)) {
|
||||
// cas "4"
|
||||
int ligne_inter_x = qRound(depart.x() + arrivee.x()) / 2;
|
||||
while (ligne_inter_x % Diagram::xGrid) -- ligne_inter_x;
|
||||
points << QPointF(ligne_inter_x, depart.y());
|
||||
points << QPointF(ligne_inter_x, arrivee.y());
|
||||
// cas "4": bridge is vertical, at a shared x between depart.y()
|
||||
// and arrivee.y() -- unnecessary exactly when depart and
|
||||
// arrivee already share an x.
|
||||
if (depart.x() != arrivee.x()) {
|
||||
int ligne_inter_x = qRound(depart.x() + arrivee.x()) / 2;
|
||||
while (ligne_inter_x % Diagram::xGrid) -- ligne_inter_x;
|
||||
points << QPointF(ligne_inter_x, depart.y());
|
||||
points << QPointF(ligne_inter_x, arrivee.y());
|
||||
}
|
||||
} else if ((ori_depart == Qet::West || ori_depart == Qet::North) && (ori_arrivee == Qet::West || ori_arrivee == Qet::North)) {
|
||||
points << QPointF(depart.x(), arrivee.y()); // cas "2"
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user