19 #include "mapped_graph.h"
20 #include "dynamic_graph.h"
24 #include <unordered_map>
25 #include <unordered_set>
47 template <
typename StaticLayout>
50 using node_live_sets = std::unordered_map<node_id, detail::live_set>;
51 using edge_live_sets = std::unordered_map<edge_id, detail::live_set>;
64 : m_tolerance(tolerance)
65 , m_canvas_width(canvas_width)
66 , m_canvas_height(canvas_height)
86 void set_tolerance(
float tolerance) { m_tolerance = tolerance; }
105 if (dgraph.
states().empty()) {
109 float calculation_h = CalculationHeight;
110 float calculation_w = calculation_h * m_canvas_width / m_canvas_height;
113 basic_layout(dgraph.
states(), calculation_w, calculation_h);
116 if (m_tolerance != 0) {
117 tolerance(dgraph.
states(), calculation_w, calculation_h, m_tolerance);
121 for (
auto& state : dgraph.
states()) {
122 rescale(state, calculation_w, calculation_h, m_canvas_width, m_canvas_height);
123 move(state, 0.0, 0.0, m_center.x, m_center.y);
128 static constexpr
float CalculationHeight = 1;
131 float m_canvas_width;
132 float m_canvas_height;
135 cooling m_cooling{ 250, 0.4, [](
float t){
return t * 0.977; } };
136 StaticLayout m_static_layout;
137 bool m_relative_distance =
true;
140 virtual void tolerance(
141 std::vector<graph_state>& states
144 ,
float tolerance_value) {
145 float temp = m_cooling.start_temperature;
149 if (!m_relative_distance) {
150 tolerance_value *= m_static_layout.relative_unit(width, height) * max_nodes(states);
152 for (
unsigned i = 0; i < m_cooling.iterations; ++i) {
153 for (
unsigned s = 0; s < states.size(); ++s) {
154 graph_state copy = states[s];
155 m_static_layout.iteration(copy, width, height, temp);
156 if ((s == 0 || distance(copy, states[s - 1]) < tolerance_value)
157 && (s >= states.size() - 1
158 || distance(copy, states[s + 1]) < tolerance_value)) {
159 states[s] = std::move(copy);
162 temp = m_cooling.anneal(temp);
166 void basic_layout(std::vector<graph_state>& states,
float width,
float height) {
167 node_live_sets nodes_live = node_live_times(states);
168 edge_live_sets edges_live = edge_live_times(states);
171 auto supergraph = calculate_supergraph(states);
172 auto gap = calculate_gap(std::move(supergraph), nodes_live, edges_live);
173 auto rgap = calculate_rgap(std::move(gap));
175 m_static_layout(rgap.graph(), width, height);
178 for (
auto& state : states) {
179 for (
auto& node : state.nodes()) {
180 const auto& target_node = rgap.node_at(node.id());
181 node.pos() = target_node.pos();
186 void rescale(graph_state& graph
190 ,
float dst_height)
const {
191 float w_coeff = dst_width / src_width;
192 float h_coeff = dst_height / src_height;
193 auto perform = [&w_coeff, &h_coeff](coords& c){
197 for (
auto& node : graph.nodes()) {
202 void move(graph_state& graph
206 ,
float dst_y)
const {
207 float x_diff = dst_x - src_x;
208 float y_diff = dst_y - src_y;
209 auto perform = [&x_diff, &y_diff](coords& c){
213 for (
auto& node : graph.nodes()) {
218 node_live_sets node_live_times(
const std::vector<graph_state>& states)
const {
219 std::unordered_map<node_id, detail::live_set> result;
220 for (
unsigned t = 0; t < states.size(); ++t) {
221 for (
const auto& node : states[t].nodes()) {
222 result[node.id()].add(t);
228 edge_live_sets edge_live_times(
const std::vector<graph_state>& states)
const {
229 std::unordered_map<edge_id, detail::live_set> result;
230 for (
unsigned t = 0; t < states.size(); ++t) {
231 for (
const auto& edge : states[t].edges()) {
232 result[edge.id()].add(t);
239 graph_state calculate_supergraph(
const std::vector<graph_state>& animation)
const {
240 graph_state supergraph;
241 for (
auto& state : animation) {
242 for (
const auto& node : state.nodes()) {
243 supergraph.emplace_node(node.id());
245 for (
const auto& edge : state.edges()) {
246 supergraph.emplace_edge(edge.id(), edge.one_id(), edge.two_id());
254 detail::mapped_graph calculate_gap(
const graph_state& supergraph,
255 const node_live_sets& nodes_live,
256 const edge_live_sets& edges_live)
const {
257 detail::mapped_graph gap;
258 for (
auto& node : supergraph.nodes()) {
260 for (
auto& partition : gap.graph().nodes()) {
261 node_id partition_id = partition.id();
262 if (partition.live_time().intersection(nodes_live.at(node.id())).empty()) {
263 partition.add_live_time(nodes_live.at(node.id()));
264 gap.map_node(node.id(), partition_id);
270 auto& added = gap.graph().push_node(node.id());
271 added.add_live_time(nodes_live.at(node.id()));
275 for (
auto& edge : supergraph.edges()) {
276 node_id one = gap.node_at(edge.one_id()).id();
277 node_id two = gap.node_at(edge.two_id()).id();
278 auto& added = gap.graph().emplace_edge(edge.id(), one, two);
279 added.add_live_time(edges_live.at(edge.id()));
286 detail::mapped_graph calculate_rgap(detail::mapped_graph gap)
const {
287 detail::mapped_graph rgap = gap;
289 std::unordered_set<edge_id> removed;
290 auto same_edge = [](
const auto& a,
const auto& b){
292 return (a.one_id() == b.one_id() && a.two_id() == b.two_id())
293 || (a.one_id() == b.two_id() && a.two_id() == b.one_id());
295 for (
unsigned i = 0; i < gap.graph().edges().size(); ++i) {
296 auto& edge_i = gap.graph().edges()[i];
297 if (!removed.count(edge_i.id())) {
298 detail::edge_partition& current_partition
299 = rgap.graph().emplace_edge(edge_i.id(), edge_i.one_id(), edge_i.two_id());
300 current_partition.add_live_time(edge_i.live_time());
301 for (
unsigned k = i + 1; k < gap.graph().edges().size(); ++k) {
302 auto& edge_k = gap.graph().edges()[k];
303 if (!removed.count(edge_k.id())
304 && same_edge(edge_i, edge_k)
305 && current_partition.live_time()
306 .intersection(edge_k.live_time()).empty()) {
307 rgap.map_edge(edge_k.id(), current_partition.id());
308 current_partition.add_live_time(edge_k.live_time());
309 removed.insert(edge_k.id());
318 unsigned max_nodes(std::vector<graph_state>& states)
const {
319 const auto& max = *std::max_element(states.begin(), states.end(),
320 [](
const graph_state& a,
const graph_state& b) {
321 return a.nodes().size() < b.nodes().size();
323 return max.nodes().size();
327 float distance(
const graph_state& one,
const graph_state& two)
const {
330 for (
const auto& node : one.nodes()) {
331 if (two.node_exists(node.id())) {
332 const auto& other = two.node_at(node.id());
333 float diff_x = node.pos().x - other.pos().x;
334 float diff_y = node.pos().y - other.pos().y;
335 result += std::sqrt(diff_x * diff_x + diff_y * diff_y);
339 if (m_relative_distance) {
340 return result /
static_cast<float>(count);