WsParser_VS/StoryPresent/dag_layout.cpp

344 lines
9.8 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "dag_layout.h"
using namespace dags;
using namespace graph_data;
DAGLayerHelper::DAGLayerHelper(const Node& bind)
: bind_node(bind) {
}
Node DAGLayerHelper::bindPoint() const {
return this->bind_node;
}
int& dags::DAGLayerHelper::inputCount() {
return this->input_count;
}
int dags::DAGLayerHelper::layerValue() const {
return this->layer_v;
}
void dags::DAGLayerHelper::setLayerValue(int v) {
this->layer_v = v;
}
void DAGLayerHelper::nextAppend(std::shared_ptr<DAGLayerHelper> inst) {
if (this->next_points.contains(inst))
return;
this->next_points.append(inst);
inst->input_count++;
}
QList<std::shared_ptr<DAGLayerHelper>> DAGLayerHelper::nextNodes() const {
return this->next_points;
}
DAGOrderHelper::DAGOrderHelper(std::shared_ptr<DAGLayerHelper> bind) : layer_bind(bind) {
this->layer_number = bind->layerValue();
}
DAGOrderHelper::DAGOrderHelper(std::shared_ptr<DAGLayerHelper> f, std::shared_ptr<DAGLayerHelper> t)
: relate_bind(f), towards_to(t) {
}
bool DAGOrderHelper::isFakeNode() const {
return !this->layer_bind;
}
std::shared_ptr<DAGLayerHelper> dags::DAGOrderHelper::layerNode() const {
return this->layer_bind;
}
std::shared_ptr<DAGLayerHelper> dags::DAGOrderHelper::relateNode() const {
return this->relate_bind;
}
std::shared_ptr<DAGLayerHelper> dags::DAGOrderHelper::towardsNode() const {
return this->towards_to;
}
int dags::DAGOrderHelper::layerNumber() const {
return this->layer_number;
}
void dags::DAGOrderHelper::setLayerNumber(int v) {
this->layer_number = v;
}
double dags::DAGOrderHelper::sortNumber() const {
return this->sort_number;
}
void dags::DAGOrderHelper::setSortNumber(double v) {
this->sort_number = v;
}
QList<std::shared_ptr<DAGOrderHelper>> DAGOrderHelper::getUpstreamNodes() const {
return this->__prev_layer_nodes;
}
void DAGOrderHelper::appendUpstreamNode(std::shared_ptr<DAGOrderHelper> inst) {
this->__prev_layer_nodes.append(inst);
}
void DAGGraph::rebuildFromEdges(const QList<Arrow>& arrow_list) {
for (auto& arr : arrow_list) {
auto start = arr.startPoint();
std::shared_ptr<DAGLayerHelper> start_helper;
if (this->graph_inst.contains(start.name())) {
start_helper = this->graph_inst[start.name()];
}
else {
start_helper = std::make_shared<DAGLayerHelper>(start);
this->graph_inst[start.name()] = start_helper;
}
auto end = arr.endPoint();
std::shared_ptr< DAGLayerHelper> end_helper;
if (this->graph_inst.contains(end.name())) {
end_helper = this->graph_inst[end.name()];
}
else {
end_helper = std::make_shared<DAGLayerHelper>(end);
this->graph_inst[end.name()] = end_helper;
}
start_helper->nextAppend(end_helper);
}
}
QList<std::shared_ptr<DAGOrderHelper>> dags::DAGGraph::nodeWithLayout() const {
return this->node_with_layout;
}
int dags::DAGGraph::maxLayerCount() const {
return this->max_layer_count;
}
std::shared_ptr<DAGLayerHelper> DAGGraph::spawns_peak(QList<std::shared_ptr<DAGLayerHelper>>& ref_set) {
for (auto inst : ref_set) {
if (!inst->inputCount()) {
for (auto it_nxt : inst->nextNodes()) {
it_nxt->inputCount()--;
if (!ref_set.contains(it_nxt))
ref_set << it_nxt;
}
ref_set.removeAll(inst);
this->graph_inst.remove(inst->bindPoint().name());
return inst;
}
}
for (auto inst : this->graph_inst.values()) {
if (!inst->inputCount()) {
if (ref_set.contains(inst))
ref_set.removeAll(inst);
for (auto it_nxt : inst->nextNodes()) {
it_nxt->inputCount()--;
if (!ref_set.contains(it_nxt))
ref_set << it_nxt;
}
this->graph_inst.remove(inst->bindPoint().name());
return inst;
}
}
if (this->graph_inst.size()) {
throw "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>޻<EFBFBD>ͼ<EFBFBD>з<EFBFBD><EFBFBD>ֻ<EFBFBD><EFBFBD>λ<EFBFBD>·<EFBFBD><EFBFBD>";
}
return std::shared_ptr<DAGLayerHelper>();
}
void DAGGraph::graph_recovery(const QList<std::shared_ptr<DAGLayerHelper>> &sort_seqs) {
for (auto it : sort_seqs) {
it->inputCount() = 0;
}
for (auto it : sort_seqs) {
for (auto nxt : it->nextNodes()) {
nxt->inputCount()++;
}
}
this->graph_inst.clear();
for (auto it : sort_seqs) {
this->graph_inst[it->bindPoint().name()] = it;
}
}
int DAGGraph::node_layering(const std::shared_ptr<DAGLayerHelper> &inst, int layer_current) {
auto max_remains = layer_current;
if (!layer_current || inst->layerValue() < layer_current) {
inst->setLayerValue(layer_current);
for (auto fork : inst->nextNodes()) {
max_remains = std::max(this->node_layering(fork, inst->layerValue() + 1), max_remains);
}
}
return max_remains + 1;
}
int DAGGraph::node_layering_adj(std::shared_ptr<DAGLayerHelper> inst) {
if (inst->inputCount() > 1)
return inst->layerValue() - 1;
if (!inst->nextNodes().size())
return inst->layerValue() - 1;
auto layer_number = INT_MAX;
for (auto cinst : inst->nextNodes()) {
layer_number = std::min(layer_number, this->node_layering_adj(cinst));
}
inst->setLayerValue(layer_number);
return inst->layerValue() - 1;
}
QList<std::shared_ptr<DAGOrderHelper>> DAGGraph::tidy_graph_nodes() {
QHash<QString, std::shared_ptr<DAGOrderHelper>> nodes_temp;
for (auto node : this->graph_inst.values()) {
nodes_temp[node->bindPoint().name()] = std::make_shared<DAGOrderHelper>(node);
}
QList<std::shared_ptr<DAGOrderHelper>> temp_array(nodes_temp.values());
for (auto node : this->graph_inst.values()) {
for (auto next : node->nextNodes()) {
auto node_links = QList<std::shared_ptr<DAGOrderHelper>>{
nodes_temp[node->bindPoint().name()]
};
for (auto layer_index = node->layerValue() + 1; layer_index < next->layerValue(); ++layer_index) {
node_links.append(std::make_shared<DAGOrderHelper>(node, next));
node_links.last()->setLayerNumber(layer_index);
}
node_links.append(nodes_temp[next->bindPoint().name()]);
for (auto idx = 1; idx < node_links.size(); ++idx) {
auto start_point = node_links[idx - 1];
auto end_point = node_links[idx];
end_point->appendUpstreamNode(start_point);
}
temp_array.append(node_links.mid(1, node_links.size() - 2));
}
}
return temp_array;
}
#include <QDebug>
void DAGGraph::graph_layer_nodes_sort(int layer_index, const QList<std::shared_ptr<DAGOrderHelper>> &nodes) {
QList<std::shared_ptr<DAGOrderHelper>> nodes_within_current_layer;
for (auto n : nodes)
if (n->layerNumber() == layer_index) {
nodes_within_current_layer.append(n);
}
if (nodes_within_current_layer.size()) {
// <20><><EFBFBD>㵱ǰ<E3B5B1><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>нڵ<D0BD><DAB5><EFBFBD><EFBFBD><EFBFBD>
if (!layer_index) {
for (auto idx = 0; idx < nodes_within_current_layer.size(); ++idx) {
nodes_within_current_layer[idx]->setSortNumber(idx + 1);
}
}
else if (layer_index > 0) {
for (auto target_node : nodes_within_current_layer) {
QList<double> prev_sorts;
auto upstream_list = target_node->getUpstreamNodes();
std::transform(upstream_list.begin(), upstream_list.end(),
std::back_inserter(prev_sorts), [](std::shared_ptr<DAGOrderHelper> inst) {
return inst->sortNumber();
});
if (prev_sorts.size()) {
auto target_sum = std::accumulate(prev_sorts.begin(), prev_sorts.end(), 0.0);
target_node->setSortNumber(target_sum / prev_sorts.size());
if (!target_node->isFakeNode() && std::shared_ptr<DAGOrderHelper>(target_node)->layerNode()->bindPoint().name().contains(u8"Сʦ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>")) {
qDebug() << "";
}
}
}
// <20><>ȡ<EFBFBD><C8A1>ǰ<EFBFBD><C7B0><EFBFBD>νڵ<CEBD><DAB5><EFBFBD><EFBFBD><EFBFBD>ֵ
QList<double> sort_values;
std::transform(nodes_within_current_layer.begin(), nodes_within_current_layer.end(),
std::back_inserter(sort_values), [](std::shared_ptr<DAGOrderHelper> 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<DAGOrderHelper> 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->above_nodes_sort(layer_index, nodes);
this->graph_layer_nodes_sort(layer_index + 1, nodes);
}
}
void dags::DAGGraph::above_nodes_sort(int layer_index, const QList<std::shared_ptr<DAGOrderHelper>>& nodes)
{
// <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֪<EFBFBD>ڵ<EFBFBD>
QList<std::shared_ptr<DAGOrderHelper>> sorting_nodes;
std::copy_if(nodes.begin(), nodes.end(), std::back_inserter(sorting_nodes),
[&](std::shared_ptr<DAGOrderHelper> n) { return n->layerNumber() <= layer_index; });
// <20><><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
QList<double> sort_values;
std::transform(sorting_nodes.begin(), sorting_nodes.end(), std::back_inserter(sort_values),
[](std::shared_ptr<DAGOrderHelper> n)->double { return n->sortNumber(); });
sort_values = sort_values.toSet().toList();
std::sort(sort_values.begin(), sort_values.end());
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
auto temp_anchor = std::make_pair<double, int>(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);
}
// <20><><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD>
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<std::shared_ptr<DAGLayerHelper>> sort_seqs;
QList<std::shared_ptr<DAGLayerHelper>> refs;
while (1) {
auto peaks = this->spawns_peak(refs);
if (!peaks)
break;
sort_seqs.append(peaks);
}
this->graph_recovery(sort_seqs);
for (auto item : sort_seqs) {
if (!item->inputCount()) {
this->max_layer_count = std::max(this->max_layer_count, this->node_layering(item, 0));
}
}
for (auto item : sort_seqs) {
if (!item->inputCount()) {
this->node_layering_adj(item);
}
}
auto tidy_nodes = this->tidy_graph_nodes();
this->graph_layer_nodes_sort(0, tidy_nodes);
this->node_with_layout = tidy_nodes;
}