From 6906c2fe10b8ec33e36927f2a9a5ad0c64fe7579 Mon Sep 17 00:00:00 2001 From: codeboss <2422523675@qq.com> Date: Sat, 5 Oct 2024 17:20:41 +0800 Subject: [PATCH] 1 --- StoryPresent/dag_layout.cpp | 296 ++++++++++++++++++++++++++++++---- StoryPresent/dag_layout.h | 19 ++- StoryPresent/dag_present.cpp | 1 + StoryPresent/storypresent.cpp | 26 +++ StoryPresent/storypresent.h | 4 + 5 files changed, 310 insertions(+), 36 deletions(-) diff --git a/StoryPresent/dag_layout.cpp b/StoryPresent/dag_layout.cpp index e8edc53..fa30579 100644 --- a/StoryPresent/dag_layout.cpp +++ b/StoryPresent/dag_layout.cpp @@ -228,7 +228,7 @@ QList> DAGGraph::tidy_graph_nodes() { } #include -void DAGGraph::graph_layer_nodes_sort(int layer_index, const QList>& nodes) { +void DAGGraph::graph_layer_nodes_sort_forward(int layer_index, const QList>& nodes) { QList> nodes_within_current_layer; for (auto n : nodes) if (n->layerNumber() == layer_index) { @@ -254,36 +254,80 @@ void DAGGraph::graph_layer_nodes_sort(int layer_index, const QListsetSortNumber(target_sum / prev_sorts.size()); - if (!target_node->isFakeNode() && std::shared_ptr(target_node)->layerNode()->bindPoint().name().contains(u8"小师姐叛逃")) { - qDebug() << ""; - } } } // 提取当前层次节点排序值 - QList sort_values; - std::transform(nodes_within_current_layer.begin(), nodes_within_current_layer.end(), - std::back_inserter(sort_values), [](std::shared_ptr n) { return n->sortNumber(); }); - sort_values = sort_values.toSet().toList(); - - for (auto& sort_v : sort_values) { - decltype(nodes_within_current_layer) pick_items; - std::copy_if(nodes_within_current_layer.begin(), nodes_within_current_layer.end(), - std::back_inserter(pick_items), [=](std::shared_ptr ins) { return ins->sortNumber() == sort_v; }); - - for (int idx = 0; idx < pick_items.size(); ++idx) { - auto item = pick_items[idx]; - item->setSortNumber(item->sortNumber() + 0.000000001 * idx); - } - } + //this->current_nodelist_separate(nodes_within_current_layer); + this->current_nodelist_filling(layer_index, nodes); } - this->above_nodes_sort(layer_index, nodes); - this->graph_layer_nodes_sort(layer_index + 1, nodes); + this->nodes_sort_with_above(layer_index, nodes); + this->graph_layer_nodes_sort_forward(layer_index + 1, nodes); } } -void dags::DAGGraph::above_nodes_sort(int layer_index, const QList>& nodes) +void dags::DAGGraph::current_nodelist_filling(int layer_index, const QList>& nodes) +{ + // 提取既有排序成果 + QList> ordered_node; + std::copy_if(nodes.begin(), nodes.end(), std::back_inserter(ordered_node), + [=](std::shared_ptr ins) { + if (!ins->isFakeNode() && ins->layerNumber() < layer_index) { + auto next_nodes = ins->layerNode()->nextNodes(); + for (auto nd : next_nodes) { + if (nd->layerValue() >= layer_index) + return true; + } + } + return false; + }); + QList ordered_values; + std::transform(ordered_node.begin(), ordered_node.end(), std::back_inserter(ordered_values), + [=](std::shared_ptr ins) { + return (int) ins->sortNumber(); + }); + ordered_values = ordered_values.toSet().toList(); + std::sort(ordered_values.begin(), ordered_values.end()); + + // 提取当前层次节点并排序 + QList> nodes_within_current_layer; + std::copy_if(nodes.begin(), nodes.end(), std::back_inserter(nodes_within_current_layer), + [=](std::shared_ptr ins) { return ins->layerNumber() == layer_index; }); + + std::for_each(nodes_within_current_layer.begin(), nodes_within_current_layer.end(), + [&](std::shared_ptr n) { if (!n->getUpstreamNodes().size()) n->setSortNumber(ordered_values.first() - 1); }); + std::sort(nodes_within_current_layer.begin(), nodes_within_current_layer.end(), + [](std::shared_ptr a, std::shared_ptr b) { return a->sortNumber() < b->sortNumber(); }); + + // 填缝排序 + ordered_values.prepend(ordered_values.first() - 1); + ordered_values << ordered_values.last() + 1; + for (auto idx = 1; idx < ordered_values.size(); ++idx) { + auto prev_sortv = ordered_values[idx - 1]; + auto curr_sortv = ordered_values[idx]; + + QList> pick_ups; + std::copy_if(nodes_within_current_layer.begin(), nodes_within_current_layer.end(), std::back_inserter(pick_ups), + [=](std::shared_ptr ins) { return ins->sortNumber() >= prev_sortv && ins->sortNumber() < curr_sortv; }); + + for (int idx = 0; idx < std::min(curr_sortv - prev_sortv, pick_ups.size()); idx++) { + auto target_node = pick_ups[idx]; + target_node->setSortNumber(prev_sortv + idx); + } + if (curr_sortv - prev_sortv < pick_ups.size()) { + auto npicks = pick_ups.mid(curr_sortv - prev_sortv); + auto inc_span = 1.0 / (npicks.size() + 4); + + for (auto idx = 0; idx < npicks.size(); ++idx) { + auto nsortv = curr_sortv - 1 + (idx + 1) * inc_span; + npicks[idx]->setSortNumber(nsortv); + } + } + } +} + +void dags::DAGGraph::nodes_sort_with_above(int layer_index, const QList>& nodes) { // 提取所有已知节点 QList> sorting_nodes; @@ -313,14 +357,67 @@ void dags::DAGGraph::above_nodes_sort(int layer_index, const QList>& total_nodes) +void dags::DAGGraph::current_nodelist_separate(const QList>& nodes_within_current_layer) { - int curr_layer = 0; - while (layer_adjust_after_layout(curr_layer++, total_nodes)) { - this->above_nodes_sort(curr_layer, total_nodes); + QList sort_values; + std::transform(nodes_within_current_layer.begin(), nodes_within_current_layer.end(), + std::back_inserter(sort_values), [](std::shared_ptr n) { return n->sortNumber(); }); + sort_values = sort_values.toSet().toList(); + + for (auto& sort_v : sort_values) { + QList> pick_items; + std::copy_if(nodes_within_current_layer.begin(), nodes_within_current_layer.end(), + std::back_inserter(pick_items), [=](std::shared_ptr ins) { return ins->sortNumber() == sort_v; }); + + std::sort(pick_items.begin(), pick_items.end(), + [](std::shared_ptra, std::shared_ptr b)->bool { + auto prevs_a = a->getUpstreamNodes(); + auto prevs_b = b->getUpstreamNodes(); + + if (!prevs_a.size() && !prevs_b.size()) + return a < b; + if (!prevs_a.size()) + return false; + if (!prevs_b.size()) + return true; + + auto upnode_a = std::min_element(prevs_a.begin(), prevs_a.end(), + [](std::shared_ptr a, std::shared_ptr b) { return a->sortNumber() < b->sortNumber(); }); + auto upnode_b = std::min_element(prevs_b.begin(), prevs_b.end(), + [](std::shared_ptr a, std::shared_ptr b) { return a->sortNumber() < b->sortNumber(); }); + + return (*upnode_a)->sortNumber() > (*upnode_b)->sortNumber(); + }); + + for (int idx = 0; idx < pick_items.size(); ++idx) { + auto item = pick_items[idx]; + item->setSortNumber(item->sortNumber() - 0.000000001 * idx); + } } } +void dags::DAGGraph::current_layer_separate(int layer_index, const QList>& nodes) +{ + QList> nodes_within_current_layer; + for (auto n : nodes) + if (n->layerNumber() == layer_index) { + nodes_within_current_layer.append(n); + } + + this->current_nodelist_separate(nodes_within_current_layer); +} + +void dags::DAGGraph::graph_adjust_after_layout(const QList>& total_nodes) +{ + auto layer_index = this->maxLayerCount() - 1; + while (layer_index > -1) { + this->layer_adjust_via_next_sibling(layer_index, total_nodes); + this->current_layer_separate(layer_index, total_nodes); + this->nodes_sort_with_belows(layer_index, total_nodes); + layer_index--; + }; +} +/* bool dags::DAGGraph::layer_adjust_after_layout(int curr_layer, const QList>& total_nodes) { QList> nodes_within_current_layer; @@ -330,18 +427,153 @@ bool dags::DAGGraph::layer_adjust_after_layout(int curr_layer, const QList a, std::shared_ptr b) { return a->sortNumber() < b->sortNumber(); }); + + std::shared_ptr prev_sort = nullptr; for (auto node : nodes_within_current_layer) { - this->node_adjust_after_layout(node, total_nodes); + this->node_adjust_after_layout(prev_sort, node, total_nodes); + prev_sort = node; } return true; } -void dags::DAGGraph::node_adjust_after_layout(std::shared_ptr curr_node, const QList>& total_nodes) +void dags::DAGGraph::node_adjust_after_layout(std::shared_ptr prev, std::shared_ptr curr_node, const QList>& total_nodes) { - auto next_data = curr_node->headsNode(); + // 计算上游调整 + auto prev_layer_nodes = curr_node->getUpstreamNodes(); + QList prev_sort_values; + std::transform(prev_layer_nodes.begin(), prev_layer_nodes.end(), std::back_inserter(prev_sort_values), + [](std::shared_ptr inst) { return inst->sortNumber(); }); - auto upstream_nodes = curr_node->getUpstreamNodes(); + + + // 计算下游调整 + QList> next_layer_nodes; + std::copy_if(total_nodes.begin(), total_nodes.end(), std::back_inserter(next_layer_nodes), + [&](std::shared_ptr inst) { + if (inst->layerNumber() == curr_node->layerNumber() + 1) { + if (curr_node->isFakeNode()) { + if (inst->isFakeNode()) { + return curr_node->tailsNode() == inst->tailsNode() && curr_node->headsNode() == inst->headsNode(); + } + return curr_node->headsNode() == inst->layerNode(); + } + else { + if (inst->isFakeNode()) { + return curr_node->layerNode() == inst->tailsNode(); + } + else { + auto next_vnodes = curr_node->layerNode()->nextNodes(); + return next_vnodes.contains(inst->layerNode()); + } + } + } + return false; + }); + QList next_sort_values; + std::transform(next_layer_nodes.begin(), next_layer_nodes.end(), std::back_inserter(next_sort_values), + [](std::shared_ptr ins) {return ins->sortNumber(); }); + + + if (prev_sort_values.size() + next_sort_values.size()) { + auto prev_pos_sum = std::accumulate(prev_sort_values.begin(), prev_sort_values.end(), 0.0); + auto next_pos_sum = std::accumulate(next_sort_values.begin(), next_sort_values.end(), 0.0); + auto target_pos = 0.0; + + if (prev_sort_values.size() && next_sort_values.size()) { + target_pos = (prev_pos_sum / prev_sort_values.size() + next_pos_sum / next_sort_values.size()) / 2; + } + else if (prev_sort_values.size()) { + target_pos = prev_pos_sum / prev_sort_values.size(); + } + else { + target_pos = next_pos_sum / next_sort_values.size(); + } + + curr_node->setSortNumber(target_pos); + } } +*/ +bool dags::DAGGraph::layer_adjust_via_next_sibling(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; }); + + for (auto node : curr_layer_nodes) { + this->node_adjust_via_next_sibling(node, total_nodes); + } + + return curr_layer; +} + +void dags::DAGGraph::node_adjust_via_next_sibling(std::shared_ptr curr_node, const QList>& total_nodes) +{ + // 计算下游调整 + QList> next_layer_nodes; + std::copy_if(total_nodes.begin(), total_nodes.end(), std::back_inserter(next_layer_nodes), + [&](std::shared_ptr inst) { + if (inst->layerNumber() == curr_node->layerNumber() + 1) { + if (curr_node->isFakeNode()) { + if (inst->isFakeNode()) { + return curr_node->tailsNode() == inst->tailsNode() && curr_node->headsNode() == inst->headsNode(); + } + return curr_node->headsNode() == inst->layerNode(); + } + else { + if (inst->isFakeNode()) { + return curr_node->layerNode() == inst->tailsNode(); + } + else { + auto next_vnodes = curr_node->layerNode()->nextNodes(); + return next_vnodes.contains(inst->layerNode()); + } + } + } + return false; + }); + + std::sort(next_layer_nodes.begin(), next_layer_nodes.end(), + [](std::shared_ptr a, std::shared_ptr b) { + return a->sortNumber() < b->sortNumber(); + }); + + if (next_layer_nodes.size()) { + curr_node->setSortNumber(next_layer_nodes.first()->sortNumber()); + } +} + +void dags::DAGGraph::nodes_sort_with_belows(int curr_layer, const QList>& total_nodes) +{ + // 提取所有已知节点 + QList> sorting_nodes; + std::copy_if(total_nodes.begin(), total_nodes.end(), std::back_inserter(sorting_nodes), + [=](std::shared_ptr ins) { return ins->layerNumber() >= curr_layer; }); + + // 排序值提取与重排 + QList sort_values; + std::transform(sorting_nodes.begin(), sorting_nodes.end(), std::back_inserter(sort_values), + [](std::shared_ptr n)->double { return n->sortNumber(); }); + sort_values = sort_values.toSet().toList(); + std::sort(sort_values.begin(), sort_values.end()); + + // 检索排序中轴 + auto temp_anchor = std::make_pair(DBL_MAX, -1); + for (int nidx = 0; nidx < sort_values.size(); ++nidx) { + auto value_span = std::abs(sort_values[nidx]); + if (value_span <= temp_anchor.first) + temp_anchor = std::make_pair(value_span, nidx); + } + + // 排序值重整 + for (int sorting_idx = 0; sorting_idx < sorting_nodes.size(); ++sorting_idx) { + auto node = sorting_nodes[sorting_idx]; + auto sort_idx = sort_values.indexOf(node->sortNumber()); + node->setSortNumber(sort_idx - temp_anchor.second); + } +} + void dags::DAGGraph::graphLayout() { QList> sort_seqs; @@ -366,8 +598,10 @@ void dags::DAGGraph::graphLayout() { } auto tidy_nodes = this->tidy_graph_nodes(); - this->graph_layer_nodes_sort(0, tidy_nodes); + this->graph_layer_nodes_sort_forward(0, tidy_nodes); this->node_with_layout = tidy_nodes; + + this->graph_adjust_after_layout(tidy_nodes); } diff --git a/StoryPresent/dag_layout.h b/StoryPresent/dag_layout.h index a1905fd..53d6da6 100644 --- a/StoryPresent/dag_layout.h +++ b/StoryPresent/dag_layout.h @@ -76,9 +76,9 @@ namespace dags { public: void rebuildFromEdges(const QList& arrow_list); + void graphLayout(); QList> nodeWithLayout() const; int maxLayerCount() const; - void graphLayout(); private: std::shared_ptr spawns_peak(QList>& ref_set); @@ -86,11 +86,20 @@ namespace dags { int node_layering(const std::shared_ptr &inst, int layer_current); int node_layering_adj(std::shared_ptr inst); QList> tidy_graph_nodes(); - void graph_layer_nodes_sort(int layer_index, const QList> &nodes); - void above_nodes_sort(int curr_layer, const QList>& total_nodes); + void graph_layer_nodes_sort_forward(int layer_index, const QList> &nodes); + + void current_nodelist_filling(int curr_layer, const QList>& total_nodes); + void nodes_sort_with_above(int curr_layer, const QList>& total_nodes); + + void current_nodelist_separate(const QList>& total_nodes); + void current_layer_separate(int layer_index, const QList>& nodes); void graph_adjust_after_layout(const QList>& total_nodes); - bool layer_adjust_after_layout(int curr_layer, const QList>& total_nodes); - void node_adjust_after_layout(std::shared_ptr curr_node, const QList>& total_nodes); + //bool layer_adjust_after_layout(int curr_layer, const QList>& total_nodes); + //void node_adjust_after_layout(std::shared_ptr prev_node, std::shared_ptr curr_node, const QList>& total_nodes); + + bool layer_adjust_via_next_sibling(int curr_layer, const QList>& total_nodes); + void node_adjust_via_next_sibling(std::shared_ptr curr_node, const QList>& total_nodes); + void nodes_sort_with_belows(int curr_layer, const QList>& total_nodes); }; } diff --git a/StoryPresent/dag_present.cpp b/StoryPresent/dag_present.cpp index 84ed5e7..c642e21 100644 --- a/StoryPresent/dag_present.cpp +++ b/StoryPresent/dag_present.cpp @@ -60,6 +60,7 @@ void PenetrateNode::paint(QPainter* painter, const QStyleOptionGraphicsItem* opt auto outline = this->boundingRect(); painter->save(); + painter->setRenderHint(QPainter::Antialiasing); auto ypos = outline.height() / 2 - 3; if (this->isHighlighted()) diff --git a/StoryPresent/storypresent.cpp b/StoryPresent/storypresent.cpp index 5601778..ac40571 100644 --- a/StoryPresent/storypresent.cpp +++ b/StoryPresent/storypresent.cpp @@ -1,6 +1,8 @@ #include "storypresent.h" #include #include +#include +#include using namespace dags; using namespace xast_parse; @@ -9,6 +11,11 @@ StoryPresent::StoryPresent(QWidget* parent) : QMainWindow(parent), _story_present(new DAGActiveView(this)) { setCentralWidget(_story_present); + + auto mbar = menuBar(); + 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); } StoryPresent::~StoryPresent() @@ -53,3 +60,22 @@ void StoryPresent::loadXAST(const QString& ast_path) this->_story_present->updateWithEdges(arrows); } + +#include +void StoryPresent::bigger() +{ + _scale_value *= 1.1; + + QTransform trans_base; + trans_base.scale(_scale_value, _scale_value); + this->_story_present->setTransform(trans_base); +} + +void StoryPresent::lesser() +{ + _scale_value /= 1.1; + + QTransform trans_base; + trans_base.scale(_scale_value, _scale_value); + this->_story_present->setTransform(trans_base); +} diff --git a/StoryPresent/storypresent.h b/StoryPresent/storypresent.h index 3e93433..3beae04 100644 --- a/StoryPresent/storypresent.h +++ b/StoryPresent/storypresent.h @@ -14,6 +14,10 @@ public: void loadXAST(const QString &ast_path); private: + double _scale_value = 1; dags::DAGActiveView *const _story_present; QHash> _story_graph; + + void bigger(); + void lesser(); };