From dd6398223c1bd95560cfc51886a8f1623bb4b730 Mon Sep 17 00:00:00 2001 From: codeboss <2422523675@qq.com> Date: Sun, 6 Oct 2024 11:01:32 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=B9=E5=A4=96=E6=8F=90=E4=BE=9B=E5=B8=83?= =?UTF-8?q?=E5=B1=80=E8=B0=83=E6=95=B4=E5=85=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- StoryPresent/dag_layout.cpp | 108 ++++++++++++++++++++++++++++++++-- StoryPresent/dag_layout.h | 16 ++++- StoryPresent/dag_present.cpp | 29 +++++---- StoryPresent/dag_present.h | 5 ++ StoryPresent/storypresent.cpp | 23 ++++++++ StoryPresent/storypresent.h | 4 ++ 6 files changed, 168 insertions(+), 17 deletions(-) diff --git a/StoryPresent/dag_layout.cpp b/StoryPresent/dag_layout.cpp index b17bbbe..1eeb640 100644 --- a/StoryPresent/dag_layout.cpp +++ b/StoryPresent/dag_layout.cpp @@ -468,7 +468,94 @@ void dags::DAGGraph::nodes_sort_with_belows(int curr_layer, const QList>& total_nodes) +{ + int layer_index = 0; + while (this->node_adjust_inlayer_forward(layer_index, total_nodes)) { + layer_index++; + } +} + +bool dags::DAGGraph::node_adjust_inlayer_forward(int curr_layer, const QList>& total_nodes) +{ + // 挑选当前层次节点 + QList> curr_layer_nodes; + std::copy_if(total_nodes.begin(), total_nodes.end(), std::back_inserter(curr_layer_nodes), + [&](std::shared_ptr inst) { return inst->layerNumber() == curr_layer; }); + + if (!curr_layer_nodes.size()) + return false; + + // 计算排序系数 + QList, qlonglong, qlonglong>> orders_helper; + std::transform(curr_layer_nodes.begin(), curr_layer_nodes.end(), std::back_inserter(orders_helper), + [&](std::shared_ptr ins) { + auto val = this->node_evaluate_with_downstream(ins, total_nodes); + return std::make_tuple(ins, val.first, val.second); + }); + + // 排序当前层次节点 + std::sort(orders_helper.begin(), orders_helper.end(), + [](std::tuple, qlonglong, qlonglong> a, std::tuple, qlonglong, qlonglong> b) { + if (std::get<1>(a) == std::get<1>(b)) + return std::get<2>(a) < std::get<2>(b); + + return std::get<1>(a) < std::get<1>(b); + }); + + QList sort_values; + std::transform(curr_layer_nodes.begin(), curr_layer_nodes.end(), std::back_inserter(sort_values), + [](std::shared_ptr ins) { return ins->sortNumber().toInt(); }); + std::sort(sort_values.begin(), sort_values.end()); + + // 重新设定节点次序 + for (auto idx = 0; idx < sort_values.size(); ++idx) { + std::get<0>(orders_helper[idx])->setSortNumber(sort_values[idx]); + } + + return true; +} + +std::pair dags::DAGGraph::node_evaluate_with_downstream(std::shared_ptr node, const QList>& total_nodes) +{ + decltype(node) next_node; + if (node->isFakeNode()) { + auto n_data = node->headsNode(); + next_node = *std::find_if(total_nodes.begin(), total_nodes.end(), [&](decltype(node) n) { + if (!n->isFakeNode()) { + return n->layerNode() == n_data; + } + return false; + }); + } + else { + auto n_datas = node->layerNode()->nextNodes(); + if (!n_datas.size()) + return std::make_pair(node->layerNumber(), node->sortNumber().toLongLong()); + + QList> next_nodes; + std::transform(n_datas.begin(), n_datas.end(), std::back_inserter(next_nodes), + [&](std::shared_ptr inst) { + auto rst = std::find_if(total_nodes.begin(), total_nodes.end(), [&](decltype(node) n) { + if (!n->isFakeNode()) { + return n->layerNode() == inst; + } + return false; + }); + return *rst; + }); + next_node = *std::min_element(next_nodes.begin(), next_nodes.end(), + [](std::shared_ptr a, std::shared_ptr b) { + if (a->layerNumber() == b->layerNumber()) + return a->sortNumber() < b->sortNumber(); + return a->layerNumber() < b->layerNumber(); + }); + } + + return std::make_pair(next_node->layerNumber(), next_node->sortNumber().toLongLong()); +} + +void dags::DAGGraph::primitiveGraphLayout() { QList> sort_seqs; QList> refs; while (1) { @@ -493,12 +580,21 @@ void dags::DAGGraph::graphLayout() { auto tidy_nodes = this->tidy_graph_nodes(); this->graph_layer_nodes_sort_forward(0, tidy_nodes); this->node_with_layout = tidy_nodes; +} - int times = 1; - while (times--) { - this->graph_adjust_after_layout(tidy_nodes); - this->graph_layer_nodes_sort_forward(0, tidy_nodes); - } +void dags::DAGGraph::forwardsLayoutImpls() +{ + this->graph_layer_nodes_sort_forward(0, this->node_with_layout); +} + +void dags::DAGGraph::backwardsLayoutImpls() +{ + this->graph_adjust_after_layout(this->node_with_layout); +} + +void dags::DAGGraph::adjustLayoutImpls() +{ + this->node_adjust_ingraph_forward(this->node_with_layout); } diff --git a/StoryPresent/dag_layout.h b/StoryPresent/dag_layout.h index 95cee49..f3b82c5 100644 --- a/StoryPresent/dag_layout.h +++ b/StoryPresent/dag_layout.h @@ -76,7 +76,10 @@ namespace dags { public: void rebuildFromEdges(const QList& arrow_list); - void graphLayout(); + void primitiveGraphLayout(); + void forwardsLayoutImpls(); + void backwardsLayoutImpls(); + void adjustLayoutImpls(); QList> nodeWithLayout() const; int maxLayerCount() const; @@ -97,5 +100,16 @@ namespace dags { void nodes_sort_with_above(int curr_layer, const QList>& total_nodes); void nodes_sort_with_belows(int curr_layer, const QList>& total_nodes); + void node_adjust_ingraph_forward(const QList>& total_nodes); + bool node_adjust_inlayer_forward(int curr_layer, const QList>& total_nodes); + /** + * . + * + * \param node + * \param total_nodes + * \return <层次,排序值> + */ + std::pair node_evaluate_with_downstream(std::shared_ptr node, const QList>& total_nodes); + }; } diff --git a/StoryPresent/dag_present.cpp b/StoryPresent/dag_present.cpp index 066de36..678dbf3 100644 --- a/StoryPresent/dag_present.cpp +++ b/StoryPresent/dag_present.cpp @@ -145,7 +145,7 @@ void TransitionCurve::paint(QPainter* painter, const QStyleOptionGraphicsItem* o } DAGActiveView::DAGActiveView(QWidget* parent) - : QGraphicsView(parent) { + : QGraphicsView(parent), _layout_engine(new DAGGraph){ this->setViewportUpdateMode(QGraphicsView::FullViewportUpdate); this->setScene(&this->scene_bind); @@ -240,16 +240,10 @@ QList DAGActiveView::layer_nodes_construction(const QHash void DAGActiveView::updateWithEdges(QList arrows) { - // 清除当前视图 - this->scene_bind.clear(); - this->total_graph_nodes.clear(); + _layout_engine->rebuildFromEdges(arrows); + _layout_engine->primitiveGraphLayout(); - DAGGraph tools; - tools.rebuildFromEdges(arrows); - tools.graphLayout(); - - auto total_nodes = tools.nodeWithLayout(); - total_graph_nodes = this->layer_nodes_construction(QHash>(), total_nodes); + this->refreshGraph(); } void DAGActiveView::highlightGraphLink(const QList arrows) { @@ -307,6 +301,21 @@ void DAGActiveView::highlightGraphLink(const QList arrows) { this->update(); } +DAGGraph* dags::DAGActiveView::layoutEngine() const +{ + return this->_layout_engine; +} + +void dags::DAGActiveView::refreshGraph() +{ + // 清除当前视图 + this->scene_bind.clear(); + this->total_graph_nodes.clear(); + + auto total_nodes = _layout_engine->nodeWithLayout(); + total_graph_nodes = this->layer_nodes_construction(QHash>(), total_nodes); +} + void DAGActiveView::mousePressEvent(QMouseEvent* ev) { QGraphicsView::mousePressEvent(ev); diff --git a/StoryPresent/dag_present.h b/StoryPresent/dag_present.h index e2a6bad..10cc9ab 100644 --- a/StoryPresent/dag_present.h +++ b/StoryPresent/dag_present.h @@ -103,6 +103,8 @@ namespace dags { QList highlight_nodelist; QList total_graph_nodes; + DAGGraph *const _layout_engine; + signals: void nodeClicked(const QPointF &pos, const QList &node_name); @@ -112,6 +114,9 @@ namespace dags { void updateWithEdges(QList arrows); void highlightGraphLink(const QList color_path); + DAGGraph* layoutEngine() const; + void refreshGraph(); + // QGraphicsView virtual void mousePressEvent(QMouseEvent *ev) override; diff --git a/StoryPresent/storypresent.cpp b/StoryPresent/storypresent.cpp index ac40571..be48cc0 100644 --- a/StoryPresent/storypresent.cpp +++ b/StoryPresent/storypresent.cpp @@ -16,6 +16,11 @@ StoryPresent::StoryPresent(QWidget* parent) auto view = mbar->addMenu(u8"视图"); view->addAction(u8"缩小", this, &StoryPresent::lesser, Qt::CTRL + Qt::Key_N); view->addAction(u8"放大", this, &StoryPresent::bigger, Qt::CTRL + Qt::Key_P); + + auto layout = mbar->addMenu(u8"布局调整"); + layout->addAction(u8"正向布局", this, &StoryPresent::forwardLayout); + layout->addAction(u8"逆向布局", this, &StoryPresent::backwardLayout); + layout->addAction(u8"调整布局", this, &StoryPresent::adjustLayout); } StoryPresent::~StoryPresent() @@ -79,3 +84,21 @@ void StoryPresent::lesser() trans_base.scale(_scale_value, _scale_value); this->_story_present->setTransform(trans_base); } + +void StoryPresent::forwardLayout() +{ + this->_story_present->layoutEngine()->forwardsLayoutImpls(); + this->_story_present->refreshGraph(); +} + +void StoryPresent::backwardLayout() +{ + this->_story_present->layoutEngine()->backwardsLayoutImpls(); + this->_story_present->refreshGraph(); +} + +void StoryPresent::adjustLayout() +{ + this->_story_present->layoutEngine()->adjustLayoutImpls(); + this->_story_present->refreshGraph(); +} diff --git a/StoryPresent/storypresent.h b/StoryPresent/storypresent.h index 3beae04..79464fb 100644 --- a/StoryPresent/storypresent.h +++ b/StoryPresent/storypresent.h @@ -20,4 +20,8 @@ private: void bigger(); void lesser(); + + void forwardLayout(); + void backwardLayout(); + void adjustLayout(); };