From c6839451a6641db13a27fbdef9880c22432dbe76 Mon Sep 17 00:00:00 2001 From: Quentin Quadrat Date: Tue, 14 May 2024 03:01:01 +0200 Subject: [PATCH] Timed event graph: remove places when a transition is removed #14 --- include/TimedPetriNetEditor/PetriNet.hpp | 26 +++ src/Editor/DearImGui/Editor.cpp | 1 - src/Net/PetriNet.cpp | 192 ++++++++++++++--------- 3 files changed, 146 insertions(+), 73 deletions(-) diff --git a/include/TimedPetriNetEditor/PetriNet.hpp b/include/TimedPetriNetEditor/PetriNet.hpp index 1520726..eebef14 100644 --- a/include/TimedPetriNetEditor/PetriNet.hpp +++ b/include/TimedPetriNetEditor/PetriNet.hpp @@ -746,6 +746,32 @@ class Net //-------------------------------------------------------------------------- bool sanityArc(Node const& from, Node const& to, bool const strict) const; + //-------------------------------------------------------------------------- + //! \brief Helper method removing a transition. This function does not care + //! of upstream/downstream arcs: they shall be removed. + //! For fastest deletion, we simply swap the undesired node with the + //! latest node in the container. To do that, we have to iterate from the end + //! of the container. + //-------------------------------------------------------------------------- + void helperRemoveTransition(Node& node); + + //-------------------------------------------------------------------------- + //! \brief Helper method removing a place. This function does not care + //! of upstream/downstream arcs: they shall be removed. + //! For fastest deletion, we simply swap the undesired node with the + //! latest node in the container. To do that, we have to iterate from the end + //! of the container. + //-------------------------------------------------------------------------- + void helperRemovePlace(Node& node); + + //-------------------------------------------------------------------------- + //! \brief Helper method removing all arcs linked to the given node. + //! Note: For fastest deletion, we simply swap the undesired arc with the + //! latest arc in the container. To do that, we have to iterate from the end + //! of the container. + //-------------------------------------------------------------------------- + void helperRemoveArcFromNode(Node& node); + private: //! \brief Type of net GRAFCET, Petri, Timed Petri ... diff --git a/src/Editor/DearImGui/Editor.cpp b/src/Editor/DearImGui/Editor.cpp index c11b960..4c855f8 100644 --- a/src/Editor/DearImGui/Editor.cpp +++ b/src/Editor/DearImGui/Editor.cpp @@ -1560,7 +1560,6 @@ void Editor::PetriView::onHandleInput() auto action = std::make_unique(m_editor); action->before(m_editor.m_net); m_editor.m_net.removeNode(*node); - // FIXME: TimedEventGraph: supprimer aussi les places action->after(m_editor.m_net); m_editor.m_history.add(std::move(action)); } diff --git a/src/Net/PetriNet.cpp b/src/Net/PetriNet.cpp index 3a61522..9ee71c3 100644 --- a/src/Net/PetriNet.cpp +++ b/src/Net/PetriNet.cpp @@ -550,6 +550,8 @@ bool Net::removeArc(Arc const& a) //------------------------------------------------------------------------------ bool Net::removeArc(Node const& from, Node const& to) { +// Supprimer les arcs qui touchent la place supprimee + size_t i = m_arcs.size(); while (i--) { @@ -568,24 +570,130 @@ bool Net::removeArc(Node const& from, Node const& to) } //------------------------------------------------------------------------------ -void Net::removeNode(Node& node) +void Net::helperRemovePlace(Node& node) +{ + size_t i = m_places.size(); + while (i--) + { + // Found the undesired node: make the latest element take its + // location in the container. But before doing this we have to + // restore references on impacted arcs. + if (m_places[i].id == node.id) + { + // Swap element but keep the ID of the removed element + Place& pi = m_places[i]; + Place& pe = m_places[m_places.size() - 1u]; + if (pe.caption == pe.key) + { + m_places[i] = Place(pi.id, pi.key, pe.x, pe.y, pe.tokens); + } + else + { + m_places[i] = Place(pi.id, pe.caption, pe.x, pe.y, pe.tokens); + } + assert(m_next_place_id >= 1u); + m_next_place_id -= 1u; + + // Update the references to nodes of the arc + for (auto& a: m_arcs) // TODO optim: use in/out arcs but they may not be generated + { + if (a.to.key == pe.key) + a = Arc(a.from, m_places[i], a.duration); + if (a.from.key == pe.key) + a = Arc(m_places[i], a.to, a.duration); + } + + m_places.pop_back(); + } + } +} + +//------------------------------------------------------------------------------ +void Net::helperRemoveTransition(Node& node) +{ + size_t i = m_transitions.size(); + while (i--) + { + // Found the undesired node: make the latest element take its + // location in the container. But before doing this we have to + // restore references on impacted arcs. + if (m_transitions[i].id == node.id) + { + Transition& ti = m_transitions[i]; + Transition& te = m_transitions[m_transitions.size() - 1u]; + if (te.caption == te.key) + { + m_transitions[i] = Transition(ti.id, ti.key, te.x, te.y, te.angle, + (m_type == TypeOfNet::TimedPetriNet) + ? true : false); + } + else + { + m_transitions[i] = Transition(ti.id, te.caption, te.x, te.y, te.angle, + (m_type == TypeOfNet::TimedPetriNet) + ? true : false); + } + assert(m_next_transition_id >= 1u); + m_next_transition_id -= 1u; + + // Update the references to nodes of the arc + for (auto& a: m_arcs) // TODO optim: use in/out arcs but they may not be generated + { + if (a.to.key == te.key) + a = Arc(a.from, m_transitions[i], a.duration); + if (a.from.key == te.key) + a = Arc(m_transitions[i], a.to, a.duration); + } + + m_transitions.pop_back(); + } + } +} + +//------------------------------------------------------------------------------ +void Net::helperRemoveArcFromNode(Node& node) { - // Remove all arcs linked to this node. - // Note: For fastest deletion, we simply swap the undesired arc with the - // latest arc in the container. To do that, we have to iterate from the end - // of the container. size_t s = m_arcs.size(); size_t i = s; while (i--) { if ((m_arcs[i].to.key == node.key) || (m_arcs[i].from.key == node.key)) { - // Found the undesired arc: make the latest element take its - // location in the container. m_arcs[i] = m_arcs[m_arcs.size() - 1u]; m_arcs.pop_back(); } } +} + +//------------------------------------------------------------------------------ +void Net::removeNode(Node& node) +{ + std::vector nodes_to_remove; + if (m_type != TypeOfNet::TimedEventGraph) + { + helperRemoveArcFromNode(node); + } + else + { + for (auto& a: m_transitions[node.id].arcsIn) + { + nodes_to_remove.push_back(&a->from); + } + for (auto& a: m_transitions[node.id].arcsOut) + { + nodes_to_remove.push_back(&a->to); + } + + // Since we swap nodes inside the array before removing + // then, we have to start from greater id to lowest id. + std::sort(nodes_to_remove.begin(), nodes_to_remove.end(), + [](Node* a, Node* b) { return a->id > b-> id; }); + + for (auto it: nodes_to_remove) + { + helperRemoveArcFromNode(*it); + } + } // Search and remove the node. // Note: For fastest deletion, we simply swap the undesired node with the @@ -593,80 +701,20 @@ void Net::removeNode(Node& node) // of the container. if (node.type == Node::Type::Place) { - i = m_places.size(); - while (i--) - { - // Found the undesired node: make the latest element take its - // location in the container. But before doing this we have to - // restore references on impacted arcs. - if (m_places[i].id == node.id) - { - // Swap element but keep the ID of the removed element - Place& pi = m_places[i]; - Place& pe = m_places[m_places.size() - 1u]; - if (pe.caption == pe.key) - { - m_places[i] = Place(pi.id, pi.key, pe.x, pe.y, pe.tokens); - } - else - { - m_places[i] = Place(pi.id, pe.caption, pe.x, pe.y, pe.tokens); - } - assert(m_next_place_id >= 1u); - m_next_place_id -= 1u; - - // Update the references to nodes of the arc - for (auto& a: m_arcs) // TODO optim: use in/out arcs but they may not be generated - { - if (a.to.key == pe.key) - a = Arc(a.from, m_places[i], a.duration); - if (a.from.key == pe.key) - a = Arc(m_places[i], a.to, a.duration); - } - - m_places.pop_back(); - } - } + helperRemovePlace(node); } else { - i = m_transitions.size(); - while (i--) + helperRemoveTransition(node); + for (auto it: nodes_to_remove) { - if (m_transitions[i].id == node.id) - { - Transition& ti = m_transitions[i]; - Transition& te = m_transitions[m_transitions.size() - 1u]; - if (te.caption == te.key) - { - m_transitions[i] = Transition(ti.id, ti.key, te.x, te.y, te.angle, - (m_type == TypeOfNet::TimedPetriNet) - ? true : false); - } - else - { - m_transitions[i] = Transition(ti.id, te.caption, te.x, te.y, te.angle, - (m_type == TypeOfNet::TimedPetriNet) - ? true : false); - } - assert(m_next_transition_id >= 1u); - m_next_transition_id -= 1u; - - for (auto& a: m_arcs) // TODO idem - { - if (a.to.key == te.key) - a = Arc(a.from, m_transitions[i], a.duration); - if (a.from.key == te.key) - a = Arc(m_transitions[i], a.to, a.duration); - } - - m_transitions.pop_back(); - } + helperRemovePlace(*it); } } // Restore in arcs and out arcs for each node generateArcsInArcsOut(); + modified = true; } //------------------------------------------------------------------------------