diff --git a/sources/diagramevent/diagrameventaddelement.cpp b/sources/diagramevent/diagrameventaddelement.cpp index 9949c54d8..dee2834c0 100644 --- a/sources/diagramevent/diagrameventaddelement.cpp +++ b/sources/diagramevent/diagrameventaddelement.cpp @@ -20,44 +20,11 @@ #include "../conductorautonumerotation.h" #include "../diagram.h" #include "../undocommand/addgraphicsobjectcommand.h" -#include "../undocommand/deleteqgraphicsitemcommand.h" #include "../factory/elementfactory.h" #include "../qetapp.h" #include "../qetdiagrameditor.h" #include "../qetgraphicsitem/element.h" #include "../qetgraphicsitem/conductor.h" -#include "../qetgraphicsitem/terminal.h" -#include "../qet.h" -#include -#include - -namespace { - /** - @brief distanceToSegment - @param point : point to measure from - @param segment : the finite segment (not the infinite line through it) - @return the distance from @a point to the closest point actually on - @a segment. Unlike QET::orthogonalProjection(), which reports a hit - for any point on the segment's infinite extension, this clamps the - projection to the segment itself: a point collinear with a wire but - past its actual drawn end is correctly reported as far away, not "on" - the wire. - */ - qreal distanceToSegment(const QPointF &point, const QLineF &segment) - { - const QPointF a = segment.p1(); - const QPointF b = segment.p2(); - const QPointF ab = b - a; - const qreal len2 = QPointF::dotProduct(ab, ab); - - if (len2 <= 0.0) - return QLineF(point, a).length(); - - qreal t = QPointF::dotProduct(point - a, ab) / len2; - t = qBound(0.0, t, 1.0); - return QLineF(point, a + t * ab).length(); - } -} /** @brief DiagramEventAddElement::DiagramEventAddElement @@ -281,213 +248,16 @@ void DiagramEventAddElement::addElement() QUndoCommand *undo_object = new QUndoCommand(tr("Ajouter %1").arg(element->name())); new AddGraphicsObjectCommand(element, m_diagram, m_element -> pos(), undo_object); - //When we search for free aligned terminal we temporally remove m_element to - //avoid any interaction with the function Element::AlignedFreeTerminals - //This is useful when an element has two (or more) terminals on opposite sides, - //because m_element is exactly at the same pos of the new element - //added to the scene so new conductor are created between terminal of the new element - //and the opposite terminal of m_element. + //When we search for free aligned terminal we temporally remove m_element to + //avoid any interaction with the function Element::AlignedFreeTerminals + //This is useful when an element has two (or more) terminals on opposite sides, + //because m_element is exactly at the same pos of the new element + //added to the scene so new conductor are created between terminal of the new element + //and the opposite terminal of m_element. m_diagram->removeItem(m_element); - - //Auto break conductor: if a terminal of the new element lies on an existing - //conductor, break the conductor and reconnect through the new element's terminal. - //Track the endpoints of broken conductors so auto-connect doesn't create duplicates. - QSet broken_endpoints; - - if (m_diagram->project()->autoBreakConductor()) + while (!element -> AlignedFreeTerminals().isEmpty() && m_diagram -> project() -> autoConductor()) { - //Track which conductors we already handled for this element - QList conductors_handled; - //Track which terminals of the new element are already used (by break or other-connect) - QSet used_terminals; - - foreach (Terminal *t, element->terminals()) - { - //Skip terminals already used by a previous break+reconnect (other_terminal) - if (used_terminals.contains(t)) - continue; - - QPointF t_dock = t->dockConductor(); - - //Collect all conductors that pass through this dock point. - struct ConductorMatch { - Conductor *conductor; - Terminal *connect_to; //endpoint "before" the dock point (based on orientation) - Terminal *other; //endpoint "after" the dock point - }; - QList all_matches; - - foreach (Conductor *c, m_diagram->conductors()) - { - //Skip conductors we already handled or connected to the new element - if (conductors_handled.contains(c) || - c->terminal1->parentElement() == element || - c->terminal2->parentElement() == element) - continue; - - //Check if dock point lies on the conductor path. Distance is - //measured to the segment itself (clamped), not the infinite - //line through it -- see distanceToSegment(). - QPointF local_dock = c->mapFromScene(t_dock); - bool point_on_conductor = false; - QPainterPath path = c->path(); - for (int i = 0; i < path.elementCount() - 1; ++i) - { - const QPainterPath::Element &e1 = path.elementAt(i); - const QPainterPath::Element &e2 = path.elementAt(i + 1); - QLineF segment(QPointF(e1.x, e1.y), QPointF(e2.x, e2.y)); - if (distanceToSegment(local_dock, segment) < 5.0) - { - point_on_conductor = true; - break; - } - } - - if (!point_on_conductor) - continue; - - Terminal *c1 = c->terminal1; - Terminal *c2 = c->terminal2; - QPointF c1_dock = c1->dockConductor(); - QPointF c2_dock = c2->dockConductor(); - - Terminal *connect_to = nullptr; - Terminal *other = nullptr; - - switch (t->orientation()) { - case Qet::North: - if (c1_dock.y() < t_dock.y()) { connect_to = c1; other = c2; } - else if (c2_dock.y() < t_dock.y()) { connect_to = c2; other = c1; } - break; - case Qet::South: - if (c1_dock.y() > t_dock.y()) { connect_to = c1; other = c2; } - else if (c2_dock.y() > t_dock.y()) { connect_to = c2; other = c1; } - break; - case Qet::East: - if (c1_dock.x() > t_dock.x()) { connect_to = c1; other = c2; } - else if (c2_dock.x() > t_dock.x()) { connect_to = c2; other = c1; } - break; - case Qet::West: - if (c1_dock.x() < t_dock.x()) { connect_to = c1; other = c2; } - else if (c2_dock.x() < t_dock.x()) { connect_to = c2; other = c1; } - break; - } - - if (!connect_to) { - qreal d1 = QLineF(t_dock, c1_dock).length(); - qreal d2 = QLineF(t_dock, c2_dock).length(); - if (d1 <= d2) { connect_to = c1; other = c2; } - else { connect_to = c2; other = c1; } - } - - all_matches.append({c, connect_to, other}); - } - - if (all_matches.isEmpty()) - continue; - - //Group matches by their "other" endpoint and find the largest group. - //This ensures that when multiple independent circuits cross at the - //same dock point, the group with the most conductors gets priority, - //not whichever happens to have the nearest connect_to endpoint. - QMap> groups; - for (const auto &m : all_matches) { - groups[m.other].append(m); - } - Terminal *best_other = nullptr; - int best_count = 0; - for (auto it = groups.constBegin(); it != groups.constEnd(); ++it) { - if (it.value().size() > best_count) { - best_count = it.value().size(); - best_other = it.key(); - } - } - - //Only break conductors in the largest group (same "other" endpoint). - //This prevents bridging independent nets: if two unrelated conductors - //cross at a dock point, only the larger group gets broken. - const QList &matches = groups[best_other]; - - //Mark terminal as used - used_terminals.insert(t); - - //Delete all matched conductors in one batch - DiagramContent content; - for (const auto &m : matches) { - content.m_other_conductors.append(m.conductor); - conductors_handled.append(m.conductor); - } - new DeleteQGraphicsItemCommand(m_diagram, content, undo_object); - - //Create new conductors from each connect_to endpoint to this terminal. - //This creates junctions at the terminal when multiple conductors - //from the same circuit pass through the dock point (e.g. left and - //right conductors going to the same terminal strip terminal). - for (const auto &m : matches) { - Conductor *new_c = new Conductor(m.connect_to, t); - new AddGraphicsObjectCommand(new_c, m_diagram, QPointF(), undo_object); - ConductorAutoNumerotation can(new_c, m_diagram, undo_object); - can.numerate(); - if (m_diagram->freezeNewConductors() || m_diagram->project()->isFreezeNewConductors()) - new_c->setFreezeLabel(true); - - broken_endpoints.insert(m.connect_to); - } - - //Connect the shared "other" endpoint to the nearest free terminal - //with matching orientation. - QPointF other_dock = best_other->dockConductor(); - Terminal *other_terminal = nullptr; - qreal best_dist = std::numeric_limits::max(); - foreach (Terminal *ot, element->terminals()) - { - if (used_terminals.contains(ot)) - continue; - - //Check that the other_dock approaches from the correct direction - //relative to the candidate terminal's orientation. - QPointF ot_dock = ot->dockConductor(); - bool orientation_ok = false; - switch (ot->orientation()) { - case Qet::North: orientation_ok = other_dock.y() < ot_dock.y(); break; - case Qet::South: orientation_ok = other_dock.y() > ot_dock.y(); break; - case Qet::East: orientation_ok = other_dock.x() > ot_dock.x(); break; - case Qet::West: orientation_ok = other_dock.x() < ot_dock.x(); break; - } - if (!orientation_ok) - continue; - - qreal dist = QLineF(ot_dock, other_dock).length(); - if (dist < best_dist) { - best_dist = dist; - other_terminal = ot; - } - } - - if (other_terminal) { - Conductor *new_c2 = new Conductor(best_other, other_terminal); - new AddGraphicsObjectCommand(new_c2, m_diagram, QPointF(), undo_object); - ConductorAutoNumerotation can2(new_c2, m_diagram, undo_object); - can2.numerate(); - if (m_diagram->freezeNewConductors() || m_diagram->project()->isFreezeNewConductors()) - new_c2->setFreezeLabel(true); - - broken_endpoints.insert(best_other); - used_terminals.insert(other_terminal); - } - } - } - - //Auto-connect: collect all aligned pairs first, then filter and process. - QList> aligned_pairs; - if (m_diagram->project()->autoConductor()) - aligned_pairs = element->AlignedFreeTerminals(); - - for (const QPair &pair : aligned_pairs) - { - //Skip if the other terminal was an endpoint of a broken conductor - if (broken_endpoints.contains(pair.second)) - continue; + QPair pair = element -> AlignedFreeTerminals().takeFirst(); Conductor *conductor = new Conductor(pair.first, pair.second); new AddGraphicsObjectCommand(conductor, m_diagram, QPointF(), undo_object); diff --git a/sources/qetdiagrameditor.cpp b/sources/qetdiagrameditor.cpp index 1ae771162..655bcd0d4 100644 --- a/sources/qetdiagrameditor.cpp +++ b/sources/qetdiagrameditor.cpp @@ -370,21 +370,6 @@ void QETDiagramEditor::setUpActions() pv->project()->setAutoConductor(ac); }); - //AutoBreakConductor - m_auto_break_conductor = new QAction (QET::Icons::Conductor, tr("Coupure automatique de conducteur(s)","Tool tip of auto break conductor"), this); - m_auto_break_conductor->setStatusTip (tr("Couper automatiquement les conducteurs existants lors du placement d'un élément", "Status tip of auto break conductor")); - m_auto_break_conductor->setCheckable (true); - { - QSettings settings; - m_auto_break_conductor->setChecked(settings.value("diagrameditor/auto_break_conductor", false).toBool()); - } - connect(m_auto_break_conductor, &QAction::triggered, [this](bool abc) { - QSettings settings; - settings.setValue("diagrameditor/auto_break_conductor", abc); - if (ProjectView *pv = currentProjectView()) - pv->project()->setAutoBreakConductor(abc); - }); - //Switch background color m_grey_background = new QAction (QET::Icons::DiagramBg, tr("Couleur de fond blanc/gris","Tool tip of white/grey background button"), this); m_grey_background -> setStatusTip (tr("Affiche la couleur de fond du folio en blanc ou en gris", "Status tip of white/grey background button")); @@ -824,7 +809,6 @@ void QETDiagramEditor::setUpToolBar() diagram_tool_bar -> addAction (m_edit_diagram_properties); diagram_tool_bar -> addAction (m_conductor_reset); diagram_tool_bar -> addAction (m_auto_conductor); - diagram_tool_bar -> addAction (m_auto_break_conductor); m_add_item_tool_bar = new QToolBar(tr("Ajouter"), this); m_add_item_tool_bar->setObjectName("adding"); @@ -1912,14 +1896,9 @@ void QETDiagramEditor::slot_updateModeActions() { m_auto_conductor -> setEnabled (true); m_auto_conductor -> setChecked (pv -> project() -> autoConductor()); - m_auto_break_conductor -> setEnabled (true); - m_auto_break_conductor -> setChecked (pv -> project() -> autoBreakConductor()); } else - { m_auto_conductor -> setDisabled(true); - m_auto_break_conductor -> setDisabled(true); - } } /** diff --git a/sources/qetdiagrameditor.h b/sources/qetdiagrameditor.h index 21df421f7..f5666f781 100644 --- a/sources/qetdiagrameditor.h +++ b/sources/qetdiagrameditor.h @@ -192,8 +192,6 @@ class QETDiagramEditor : public QETMainWindow *redo, ///< Redo the latest cancelled operation *m_paste, ///< Paste clipboard content on the current diagram *m_auto_conductor, ///< Enable/Disable the use of auto conductor - *m_auto_break_conductor, ///< Enable/Disable the use of auto break conductor - *conductor_default, ///< Show a dialog to edit default conductor properties *m_grey_background, ///< Switch the background color in white or grey *m_draw_grid, ///< Switch the background grid display or not *m_draw_guides = nullptr, ///< Switch the custom guides display or not diff --git a/sources/qetproject.cpp b/sources/qetproject.cpp index 31dfb6365..9b115458d 100644 --- a/sources/qetproject.cpp +++ b/sources/qetproject.cpp @@ -69,10 +69,6 @@ m_project_properties_handler{this} init(); QSettings settings; - - //Read auto break conductor default from global settings - m_auto_break_conductor = settings.value(QStringLiteral("diagrameditor/auto_break_conductor"), false).toBool(); - int size = settings.beginReadArray(QStringLiteral("diagrameditor/defaultguides")); for (int i = 0; i < size; ++i) { settings.setArrayIndex(i); @@ -931,28 +927,6 @@ void QETProject::setAutoConductor(bool ac) m_auto_conductor = ac; } -/** - @brief QETProject::autoBreakConductor - @return true if use of auto break conductor is authorized. - See also Q_PROPERTY autoBreakConductor -*/ -bool QETProject::autoBreakConductor() const -{ - return m_auto_break_conductor; -} - -/** - @brief QETProject::setAutoBreakConductor - @param abc - Enable the use of auto break conductor if true - See also Q_PROPERTY autoBreakConductor -*/ -void QETProject::setAutoBreakConductor(bool abc) -{ - if (abc != m_auto_break_conductor) - m_auto_break_conductor = abc; -} - /** @brief QETProject::autoFolioNumberingNewFolios emit Signal to add new Diagram with autonum @@ -1761,7 +1735,6 @@ void QETProject::readDefaultPropertiesXml(QDomDocument &xml_project) { m_current_conductor_autonum = conds_autonums.attribute(QStringLiteral("current_autonum")); m_freeze_new_conductors = conds_autonums.attribute(QStringLiteral("freeze_new_conductors")) == QLatin1String("true"); - m_auto_break_conductor = conds_autonums.attribute(QStringLiteral("auto_break_conductors")) == QLatin1String("true"); for (auto elmt : QET::findInDomElement(conds_autonums, QStringLiteral("conductor_autonum"))) { NumerotationContext nc; @@ -1888,7 +1861,6 @@ void QETProject::writeDefaultPropertiesXml(QDomElement &xml_element) QDomElement conductor_autonums = xml_document.createElement("conductors_autonums"); conductor_autonums.setAttribute("current_autonum", m_current_conductor_autonum); conductor_autonums.setAttribute("freeze_new_conductors", m_freeze_new_conductors ? "true" : "false"); - conductor_autonums.setAttribute("auto_break_conductors", m_auto_break_conductor ? "true" : "false"); foreach (QString key, conductorAutoNum().keys()) { QDomElement conductor_autonum = conductorAutoNum(key).toXml(xml_document, "conductor_autonum"); if (key != "" && conductorAutoNumFormula(key) != "") { diff --git a/sources/qetproject.h b/sources/qetproject.h index b08e2b5b4..61427ca72 100644 --- a/sources/qetproject.h +++ b/sources/qetproject.h @@ -90,7 +90,6 @@ class QETProject : public QObject }; Q_PROPERTY(bool autoConductor READ autoConductor WRITE setAutoConductor) - Q_PROPERTY(bool autoBreakConductor READ autoBreakConductor WRITE setAutoBreakConductor) // constructors, destructor public: @@ -182,11 +181,9 @@ class QETProject : public QObject void setFreezeNewConductors(bool); bool autoConductor () const; - bool autoBreakConductor () const; bool autoElement () const; bool autoFolio () const; void setAutoConductor (bool ac); - void setAutoBreakConductor (bool abc); void setAutoElement (bool ae); void autoFolioNumberingNewFolios (); void autoFolioNumberingSelectedFolios(int, int, const QString&); @@ -321,7 +318,6 @@ class QETProject : public QObject QHash m_element_autonum; //Title and NumContext hash QString m_current_element_autonum; bool m_auto_conductor = true; - bool m_auto_break_conductor = false; XmlElementCollection *m_elements_collection = nullptr; bool m_freeze_new_elements = false; bool m_freeze_new_conductors = false;