From dd5fe910d87bc89f75e4e4e7423a2defca3153a3 Mon Sep 17 00:00:00 2001 From: Quinta <0pietroquintavalle0@gmail.com> Date: Sat, 13 Jul 2024 15:12:05 +0200 Subject: [PATCH] C++ is hard --- .gitignore | 4 + .idea/.gitignore | 8 ++ .idea/ForestFireCPP.iml | 2 + .idea/misc.xml | 7 ++ .idea/modules.xml | 8 ++ .idea/vcs.xml | 6 + CMakeLists.txt | 13 ++ README.md | 77 ++++++++++++ main.cpp | 259 +++++++++++++++++++++++++++++++++++++++ vcpkg-configuration.json | 14 +++ vcpkg.json | 7 ++ 11 files changed, 405 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/ForestFireCPP.iml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 CMakeLists.txt create mode 100644 README.md create mode 100644 main.cpp create mode 100644 vcpkg-configuration.json create mode 100644 vcpkg.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0080421 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/build/ +/cmake-build-debug/ +/cmake-build-debug-mingw/ +/cmake-build-debug-visual-studio/ diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/ForestFireCPP.iml b/.idea/ForestFireCPP.iml new file mode 100644 index 0000000..f08604b --- /dev/null +++ b/.idea/ForestFireCPP.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..0b76fe5 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..703c914 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..4e51aab --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.28) +project(ForestFireCPP) + +set(CMAKE_CXX_STANDARD 17) + +# Add the vcpkg toolchain file +set(CMAKE_TOOLCHAIN_FILE "C:/Users/0piet/vcpkg/scripts/buildsystems/vcpkg.cmake" CACHE STRING "Vcpkg toolchain file") + +find_package(SFML COMPONENTS system window graphics CONFIG REQUIRED) + +add_executable(ForestFireCPP main.cpp) + +target_link_libraries(ForestFireCPP PRIVATE sfml-system sfml-window sfml-graphics) \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..f75c977 --- /dev/null +++ b/README.md @@ -0,0 +1,77 @@ +# Forest Fire Simulation + +This C++ project simulates the spread of forest fires using a cellular automaton model. It provides a visual representation of fire propagation in a forest environment, taking into account various factors such as wind speed, direction, and different vegetation types. + +## Features + +- Interactive grid-based simulation +- Customizable simulation parameters +- Real-time visualization using SFML graphics library +- Different vegetation types (Normal Forest, Dry Grass, Dense Trees, Water) +- Wind speed and direction influence on fire spread +- Zoom and pan functionality for detailed observation + +## Prerequisites + +To build and run this project, you'll need: + +- C++17 compatible compiler +- CMake (version 3.28 or higher) +- SFML library +- vcpkg package manager (recommended for easy SFML installation) + +## Building the Project + +1. Clone the repository: +```bash +git clone +``` +2. Install SFML using vcpkg: +```bash +vcpkg install sfml:x64-windows +``` +3. Configure the project using CMake: +```bash +mkdir build && cd build +cmake .. -DCMAKE_TOOLCHAIN_FILE=[path to vcpkg]/scripts/buildsystems/vcpkg.cmake +``` +4. Build the project: +```bash +cmake --build . +``` + +## Running the Simulation + +After building the project, run the executable: + +```bash +./ForestFireCPP +``` + +You will be prompted to enter simulation parameters: + +- Probability of fire spread (0.0 - 1.0) +- Probability of spontaneous ignition (0.0 - 1.0) +- Wind speed (0.0 - 1.0) +- Wind direction in degrees (0 - 360) +- Water ratio (0.0 - 1.0) + +After entering the parameters, press Enter to start the simulation. + +## Controls + +- Left-click and drag to pan the view +- Mouse wheel to zoom in/out + +## Contributing + +Contributions to improve the simulation or add new features are welcome. Please feel free to submit pull requests or open issues for bugs and feature requests. + +## License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. + +## Acknowledgments + +- Inspired by various forest fire simulation models and cellular automaton concepts and my already existing Python project (https://github.com/Quinta0/ForestFire.git) +- SFML library for graphics rendering (https://www.sfml-dev.org/) \ No newline at end of file diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..d239f76 --- /dev/null +++ b/main.cpp @@ -0,0 +1,259 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +// Constants +const int GRID_SIZE = 256; +const float CELL_SIZE = 5.0f; + +// Vegetation types +enum class CellType { + NormalForest, + DryGrass, + DenseTrees, + Water, + Burning, + Burned +}; + +// Simulation parameters +struct SimParams { + float p = 0.8f; + float pstart = 0.01f; + float w_speed = 0.5f; + float w_direction = 30.0f; + float water_ratio = 0.175f; +}; + +// Grid class +class Grid { +public: + Grid() : size(0) {} + + Grid(int size, float water_ratio) : size(size), cells(size, std::vector(size, CellType::NormalForest)) { + initializeGrid(water_ratio); + } + + void initializeGrid(float water_ratio) { + // Initialize grid similar to Python version + cells[size / 2][size / 2] = CellType::Burning; + cells[size / 4][size / 4] = CellType::DryGrass; + cells[3 * size / 4][3 * size / 4] = CellType::DenseTrees; + + // Implement water initialization + int num_water_cells = static_cast(size * size * water_ratio); + for (int i = 0; i < num_water_cells; ++i) { + int x = rand() % size; + int y = rand() % size; + cells[y][x] = CellType::Water; + } + } + + void update(float p, float pstart, float w_speed, float w_direction) { + std::vector> new_cells = cells; + for (int y = 0; y < size; ++y) { + for (int x = 0; x < size; ++x) { + new_cells[y][x] = updateCell(x, y, p, pstart, w_speed, w_direction); + } + } + cells = new_cells; + } + + CellType getCell(int x, int y) const { + return cells[y][x]; + } + +private: + int size; + std::vector> cells; + + CellType updateCell(int x, int y, float p, float pstart, float w_speed, float w_direction) { + CellType current = cells[y][x]; + if (current == CellType::Burning) return CellType::Burned; + if (current == CellType::Burned || current == CellType::Water) return current; + + for (const auto& neighbor : getNeighbors(x, y)) { + if (cells[neighbor.second][neighbor.first] == CellType::Burning) { + float angle = calculateAngle(x, y, neighbor.first, neighbor.second); + float directional_influence = calculateDirectionalInfluence(w_direction, angle); + float vegetation_factor = getVegetationFactor(current); + // Implement probability calculation and fire spread logic here + float adjusted_p = p * vegetation_factor * (1 + 0.1f * w_speed * directional_influence); + + if (static_cast(rand()) / RAND_MAX < adjusted_p) { + return CellType::Burning; + } + } + } + + if (static_cast(rand()) / RAND_MAX < pstart) { + return CellType::Burning; + } + + return current; + } + + std::vector> getNeighbors(int x, int y) { + std::vector> neighbors; + for (int dx = -1; dx <= 1; ++dx) { + for (int dy = -1; dy <= 1; ++dy) { + if (dx == 0 && dy == 0) continue; + int nx = x + dx, ny = y + dy; + if (nx >= 0 && nx < size && ny >= 0 && ny < size) { + neighbors.emplace_back(nx, ny); + } + } + } + return neighbors; + } + + float calculateAngle(int x1, int y1, int x2, int y2) { + return std::atan2(y2 - y1, x2 - x1) * 180 / M_PI; + } + + float calculateDirectionalInfluence(float w_direction, float angle) { + float angle_diff = std::abs(w_direction - angle); + angle_diff = std::min(angle_diff, 360.0f - angle_diff); + return 1.0f - (angle_diff / 180.0f); + } + + float getVegetationFactor(CellType type) { + switch (type) { + case CellType::NormalForest: return 1.0f; + case CellType::DryGrass: return 1.5f; + case CellType::DenseTrees: return 0.5f; + case CellType::Water: return 0.0f; + default: return 1.0f; + } + } +}; + +// Main application class +class ForestFireSim { +public: + void getSimulationParameters() { + std::cout << "Enter simulation parameters:\n"; + std::cout << "Probability of fire spread (0.0 - 1.0): "; + std::cin >> params.p; + std::cout << "Probability of spontaneous ignition (0.0 - 1.0): "; + std::cin >> params.pstart; + std::cout << "Wind speed (0.0 - 1.0): "; + std::cin >> params.w_speed; + std::cout << "Wind direction in degrees (0 - 360): "; + std::cin >> params.w_direction; + std::cout << "Water ratio (0.0 - 1.0): "; + std::cin >> params.water_ratio; + } + + ForestFireSim() : window(sf::VideoMode(800, 600), "Forest Fire Simulation"), + view(window.getDefaultView()), + grid(GRID_SIZE, params.water_ratio) { + window.setView(view); + getSimulationParameters(); + grid = Grid(GRID_SIZE, params.water_ratio); + } + + void run() { + while (window.isOpen()) { + handleEvents(); + update(); + render(); + } + } + + void startSimulation() { + std::cout << "Press Enter to start the simulation..."; + std::cin.ignore(std::numeric_limits::max(), '\n'); + std::cin.get(); + run(); + } + + +private: + sf::RenderWindow window; + Grid grid; + sf::View view; + SimParams params; + sf::Vector2f lastMousePos; + float zoomLevel = 1.0f; + + void handleEvents() { + sf::Event event; + while (window.pollEvent(event)) { + if (event.type == sf::Event::Closed) + window.close(); + else if (event.type == sf::Event::MouseButtonPressed) { + if (event.mouseButton.button == sf::Mouse::Left) { + lastMousePos = window.mapPixelToCoords(sf::Vector2i(event.mouseButton.x, event.mouseButton.y)); + } + } + else if (event.type == sf::Event::MouseMoved) { + if (sf::Mouse::isButtonPressed(sf::Mouse::Left)) { + sf::Vector2f newMousePos = window.mapPixelToCoords(sf::Vector2i(event.mouseMove.x, event.mouseMove.y)); + sf::Vector2f deltaPos = lastMousePos - newMousePos; + view.move(deltaPos); + lastMousePos = newMousePos; + } + } + else if (event.type == sf::Event::MouseWheelScrolled) { + if (event.mouseWheelScroll.delta > 0) + zoomLevel *= 1.1f; + else if (event.mouseWheelScroll.delta < 0) + zoomLevel /= 1.1f; + view.setSize(window.getDefaultView().getSize()); + view.zoom(zoomLevel); + } + } + } + + void update() { + grid.update(params.p, params.pstart, params.w_speed, params.w_direction); + } + + void render() { + window.clear(sf::Color::White); + window.setView(view); + + // Draw grid + for (int y = 0; y < GRID_SIZE; ++y) { + for (int x = 0; x < GRID_SIZE; ++x) { + sf::RectangleShape cell(sf::Vector2f(CELL_SIZE, CELL_SIZE)); + cell.setPosition(x * CELL_SIZE, y * CELL_SIZE); + cell.setFillColor(getCellColor(grid.getCell(x, y))); + window.draw(cell); + } + } + + window.display(); + } + + sf::Color getCellColor(CellType type) { + switch (type) { + case CellType::NormalForest: return sf::Color::Green; + case CellType::DryGrass: return sf::Color::Yellow; + case CellType::DenseTrees: return sf::Color(0, 100, 0); // Dark Green + case CellType::Water: return sf::Color::Blue; + case CellType::Burning: return sf::Color::Red; + case CellType::Burned: return sf::Color::Black; + default: return sf::Color::White; + } + } +}; + + + +int main() { + srand(static_cast(time(0))); + ForestFireSim sim; + sim.startSimulation(); + return 0; +} diff --git a/vcpkg-configuration.json b/vcpkg-configuration.json new file mode 100644 index 0000000..2599769 --- /dev/null +++ b/vcpkg-configuration.json @@ -0,0 +1,14 @@ +{ + "default-registry": { + "kind": "git", + "baseline": "3f530d4827b064f5894e94a8946473d40999826e", + "repository": "https://github.com/microsoft/vcpkg" + }, + "registries": [ + { + "kind": "artifact", + "location": "https://github.com/microsoft/vcpkg-ce-catalog/archive/refs/heads/main.zip", + "name": "microsoft" + } + ] +} diff --git a/vcpkg.json b/vcpkg.json new file mode 100644 index 0000000..9e147fa --- /dev/null +++ b/vcpkg.json @@ -0,0 +1,7 @@ +{ + "name": "forest-fire-cpp", + "version-string": "0.1.0", + "dependencies": [ + "sfml" + ] +}