#pragma once /* * Copyright (C) 2024 Brett Terpstra * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef GRAPHS_GRAPH_H #define GRAPHS_GRAPH_H #include #include #include #include #include #include #include namespace im = ImGui; struct bounding_box { int min_x = 0; int min_y = 0; int max_x = 0; int max_y = 0; bounding_box(const int min_x, const int min_y, const int max_x, const int max_y): min_x(min_x), min_y(min_y), max_x(max_x), max_y(max_y) { } bool is_screen = true; }; class graph_t { friend struct loader_t; friend class selector_t; private: std::vector nodes; blt::hashmap_t names_to_node; blt::hashset_t edges; blt::hashmap_t> connected_nodes; bool sim = false; bool run_infinitely = true; float sim_speed = 1; float threshold = 0; float max_force_last = 1; int current_iterations = 0; int max_iterations = 5000; std::unique_ptr equation; void create_random_graph(bounding_box bb, blt::size_t min_nodes, blt::size_t max_nodes, blt::f64 connectivity, blt::f64 scaling_connectivity, blt::f64 distance_factor); public: graph_t() { use_Eades(); } void make_new(const bounding_box& bb, const blt::size_t min_nodes, const blt::size_t max_nodes, const blt::f64 connectivity) { create_random_graph(bb, min_nodes, max_nodes, connectivity, 0, 25); } void reset(const bounding_box& bb, const blt::size_t min_nodes, const blt::size_t max_nodes, const blt::f64 connectivity, const blt::f64 scaling_connectivity, const blt::f64 distance_factor) { clear(); create_random_graph(bb, min_nodes, max_nodes, connectivity, scaling_connectivity, distance_factor); } void clear() { sim = false; current_iterations = 0; max_force_last = 1.0; nodes.clear(); edges.clear(); connected_nodes.clear(); names_to_node.clear(); } void connect(const blt::u64 n1, const blt::u64 n2) { connected_nodes[n1].insert(n2); connected_nodes[n2].insert(n1); edges.insert({n1, n2}); } void disconnect(const blt::u64 n1, const blt::u64 n2) { connected_nodes[n1].erase(n2); connected_nodes[n2].erase(n1); edges.erase({n1, n2}); } bool is_connected(const blt::u64 n1, const blt::u64 n2) { return edges.contains({n1, n2}); } void connect(const edge_t& edge) { connected_nodes[edge.getFirst()].insert(edge.getSecond()); connected_nodes[edge.getSecond()].insert(edge.getFirst()); edges.insert(edge); } [[nodiscard]] std::optional> connected(blt::u64 n1, blt::u64 n2) const { auto itr = edges.find(edge_t{n1, n2}); if (itr == edges.end()) return {}; return *itr; } void render(); void use_Eades() { equation = std::make_unique(); } void use_Fruchterman_Reingold() { equation = std::make_unique(); } void start_sim() { sim = true; } void stop_sim() { sim = false; } [[nodiscard]] std::string getSimulatorName() const { return equation->name(); } [[nodiscard]] auto* getSimulator() const { return equation.get(); } [[nodiscard]] auto getCoolingFactor() const { return equation->cooling_factor(current_iterations); } void reset_iterations() { current_iterations = 0; } [[nodiscard]] bool& getIterControl() { return run_infinitely; } [[nodiscard]] float& getSimSpeed() { return sim_speed; } [[nodiscard]] float& getThreshold() { return threshold; } [[nodiscard]] int& getMaxIterations() { return max_iterations; } [[nodiscard]] int numberOfNodes() const { return static_cast(nodes.size()); } }; class engine_t { friend struct loader_t; private: graph_t graph; selector_t selector{graph}; void draw_gui(const blt::gfx::window_data& data); public: void init(const blt::gfx::window_data& data) { graph.make_new({0, 0, data.width, data.height}, 5, 25, 0.2); } void render(const blt::gfx::window_data& data) { draw_gui(data); auto& io = ImGui::GetIO(); if (!io.WantCaptureMouse) selector.process_mouse(data.width, data.height); if (!io.WantCaptureKeyboard) selector.process_keyboard(data.width, data.height); graph.render(); selector.render(data.width, data.height); } }; #endif //GRAPHS_GRAPH_H