From 27b51e8c35e62183583a80a8689591fdbaf031f9 Mon Sep 17 00:00:00 2001 From: xAlpharax <42233094+xAlpharax@users.noreply.github.com> Date: Sat, 2 Sep 2023 15:41:23 +0300 Subject: Initial migration of the project. It does work but would require some documentation. Changes to be committed: new file: LorenzAttractor.cpp new file: LorenzAttractor.h modified: README.md new file: main.cpp new file: run.sh new file: vectormath.h --- LorenzAttractor.cpp | 514 ++++++++++++++++++++++++++++++++++++++++++++++++++++ LorenzAttractor.h | 111 ++++++++++++ README.md | 16 ++ main.cpp | 23 +++ run.sh | 9 + vectormath.h | 310 +++++++++++++++++++++++++++++++ 6 files changed, 983 insertions(+) create mode 100644 LorenzAttractor.cpp create mode 100644 LorenzAttractor.h create mode 100644 main.cpp create mode 100755 run.sh create mode 100644 vectormath.h diff --git a/LorenzAttractor.cpp b/LorenzAttractor.cpp new file mode 100644 index 0000000..70d66bd --- /dev/null +++ b/LorenzAttractor.cpp @@ -0,0 +1,514 @@ +#include "LorenzAttractor.h" + +LorenzAttractor::LorenzAttractor() +{ + // Text + font.loadFromFile("/usr/share/fontforge/pixmaps/Inconsolata-Regular.ttf"); + text.setFont(font); + text.setString(names[u]); + text.setScale(0.1f, 0.1f); + text.setPosition(sf::Vector2f(-85, -45)); + + // Re-center view + view.setCenter(sf::Vector2f(0.0f, 0.0f)); + view.setSize(sf::Vector2f(static_cast(g_screenWidth / 10), static_cast(g_screenHeight / 10))); + + // Set parameters + params = + { + {10.0f, 30.0f, 8 / 3}, + {1.24f, 1.1f, 4.4f, 3.21f}, + {0.95f, 0.7f, 0.6f, 3.5f, 0.25f, 0.1f}, + {0.3f, 1.0f}, + {5.0f, -10.0f, -0.38f}, + {1.4f}, + {0.001f, 0.2f, 1.1f}, + {0.4f, 0.175f}, + {1.5f}, + {0.2f} + }; + + colours = + { + sf::Color(115, 62, 101, 42), // 42 + sf::Color(255, 126, 210, 127), + sf::Color(109, 193, 202, 179), + sf::Color(135, 216, 10, 203), + sf::Color(125, 26, 133, 99), + sf::Color(8, 161, 163, 57), + sf::Color(134, 184, 38, 183), + sf::Color(132, 159, 149, 188), + sf::Color(100, 195, 167, 160), + sf::Color(190, 242, 126, 252), + }; + + trail_colours_params = + { + {61.3f, 62.1f, 33.9f}, + {-65.5125f, -27.8521f, -97.0907f}, + {-47.3382f, -49.5409f, -33.8347f}, + {-12.9346f, -76.7609f, 70.7356f}, + {-12.0673f, 51.6949f, 97.4566f}, + {93.4094f, -16.196f, 40.8949f}, + {-37.5288f, -31.3912f, -48.0061f}, + {-5.6245f, -49.0192f, 19.271f}, + {98.011f, -81.8857f, -80.084f}, + {44.3435f, -93.5679f, -52.0752f}, + + }; + std::cout << "\n\n\n"; + for (unsigned c = 0; c < colours.size(); c++) + { + std::cout << static_cast(colours[c].r) << " " << + static_cast(colours[c].g) << " " << + static_cast(colours[c].b) << " " << + static_cast(colours[c].a) << std::endl; + std::cout << trail_colours_params[c][0] << " " << trail_colours_params[c][1] << " " << trail_colours_params[c][2] << std::endl; + + } + + circle.resize(num_points); + point.resize(num_points); + trail.resize(num_points); + + + + // Create trial trackers + for (unsigned i = 0; i < num_points; i++) + j.push_back(0); + + for (unsigned i = 0; i < num_points; i++) + { + // Create balls + circle[i].setRadius(0.5f); + circle[i].setOrigin(circle[i].getRadius(), circle[i].getRadius()); + circle[i].setFillColor(colours[u]); + + // Set initial positions + point[i] = { getRandomNumber(1.0f, 1.0f), getRandomNumber(1.0f, 1.0f), getRandomNumber(1.0f, 1.0f) }; + + // Create trails + trail[i].resize(trail_length); + for (auto &pos : trail[i]) + pos = point[i]; + + } + + // Prepare colours + + // Create lineStrip object with two vertices. The first line should start with a first point. + line.setPrimitiveType(sf::LinesStrip); + line.append(sf::Vector2f(point[0].x, point[0].y)); + line.append(sf::Vector2f(point[0].x, point[0].y)); + + // Set Camera + switch (u) + { + case 0: {cam_position = { 0, 0, -50 }; cam_angle = { 0, 0, 0 }; break; } + case 1: {cam_position = { 1.07676f, 0.3f, -0.447995f }; cam_angle = { 0.1f, 4.84f, 0.0f }; break; } + case 2: {cam_position = { 2.25, 0, 0.75 }; cam_angle = { 0, -pi / 2, 0 }; break; } + case 3: {cam_position = { -7.5, 5, -15 }; cam_angle = { 0, pi / 6, 0 }; break; } + case 4: {cam_position = { 51.310f, -4.8f, 25.151f }; cam_angle = { -0.16f, -2.1f, 0.0f }; break; } + case 5: {cam_position = { -23.357f, -16.4f, -20.731f }; cam_angle = { -0.5f, -5.48f, 0.0f }; break; } + case 6: {cam_position = { 1.0216f, -5.7f, 6.1861f }; cam_angle = { -0.16f, 3.34f, 0.0f }; break; } + case 7: {cam_position = { 0, 0, -0.5 }; cam_angle = { 0, 0, -0.134f }; break; } + case 8: {cam_position = { -0.14397f, -8.4f, -1.3497f }; cam_angle = { -1.66f, -2.94f, 0 }; break; } + case 9: {cam_position = { 7.1565f, 4.2f, 2.6844f }; cam_angle = { 0.48f, -1.92f, 0 }; break; } + } +} + +void LorenzAttractor::input(sf::RenderWindow &window) +{ + while (window.pollEvent(event)) + { + // Window + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)) + endSubProgram = true; + if (sf::Keyboard::isKeyPressed(sf::Keyboard::F)) + { + isFullscreen = !isFullscreen; + window.create(sf::VideoMode(static_cast(g_screenWidth), static_cast(g_screenHeight)), "Coding Projects", (isFullscreen ? sf::Style::Fullscreen : sf::Style::Default), sf::ContextSettings()); + window.setPosition(sf::Vector2i(0, 0)); + window.setVerticalSyncEnabled(true); + window.setFramerateLimit(60); + } + if ((sf::Keyboard::isKeyPressed(sf::Keyboard::H) || sf::Keyboard::isKeyPressed(sf::Keyboard::G)) && input_timer >= 0.1) + { + input_timer = 0; + + if (sf::Keyboard::isKeyPressed(sf::Keyboard::H)) + { + u++; + if (u == params.size()) + u--; + } + else + { + u--; + if (u == -1) + u++; + } + + switch (u) + { + case 0: {cam_position = { 0, 0, -50 }; cam_angle = { 0, 0, 0 }; break; } + case 1: {cam_position = { 1.07676f, 0.3f, -0.447995f }; cam_angle = { 0.1f, 4.84f, 0.0f }; break; } + case 2: {cam_position = { 2.25, 0, 0.75 }; cam_angle = { 0, -pi / 2, 0 }; break; } + case 3: {cam_position = { -7.5, 5, -15 }; cam_angle = { 0, pi / 6, 0 }; break; } + case 4: {cam_position = { 51.310f, -4.8f, 25.151f }; cam_angle = { -0.16f, -2.1f, 0 }; break; } + case 5: {cam_position = { -23.357f, -16.4f, -20.731f }; cam_angle = { -0.5f, -5.48f, 0.0f }; break; } + case 6: {cam_position = { 1.0216f, -5.7f, 6.1861f }; cam_angle = { -0.16f, 3.34f, 0.0f }; break; } + case 7: {cam_position = { 0, 0, -0.5 }; cam_angle = { 0, 0, 0 }; break; } + case 8: {cam_position = { -0.1439f, -8.4f, -1.3497f }; cam_angle = { -1.66f, -2.94f, 0 }; break; } + case 9: {cam_position = { 7.1565f, 4.2f, 2.6844f }; cam_angle = { 0.48f, -1.92f, 0 }; break; } + } + + for (unsigned i = 0; i < num_points; i++) + { + circle[i].setFillColor(colours[u]); + point[i] = { getRandomNumber(-0.001f, 0.001f), getRandomNumber(-0.001f, 0.001f), getRandomNumber(-0.001f, 0.001f) }; + } + for (unsigned i = 0; i < num_points; i++) + { + for (auto &pos : trail[i]) + pos = point[i]; + } + + text.setString(names[u]); + } + } +} + +void LorenzAttractor::update() +{ + /// Calculate timestep + timestep = clock.getElapsedTime().asSeconds(); + input_timer += timestep; + clock.restart(); + + timestep *= speed; // Slow down or speed up time. + + // Update position according to chosen equation u + std::vector &m = params[u]; + switch (u) + { + case 0: + { + for (unsigned i = 0; i < num_points; i++) + { + point[i].x += static_cast(m[0] * (point[i].y - point[i].x) * timestep); + point[i].y += static_cast((point[i].x * (m[1] - point[i].z) - point[i].y) * timestep); + point[i].z += static_cast((point[i].x * point[i].y - m[2] * point[i].z) * timestep); + } + break; + } + case 1: + { + for (unsigned i = 0; i < num_points; i++) + { + float h1 = 0.5f * (abs(point[i].x + 1) - abs(point[i].x - 1)); + float h2 = 0.5f * (abs(point[i].y + 1) - abs(point[i].y - 1)); + float h3 = 0.5f * (abs(point[i].z + 1) - abs(point[i].z - 1)); + + point[i].x += static_cast((-point[i].x + m[0] * h1 - m[3] * h2 - m[3] * h3) * timestep); + point[i].y += static_cast((-point[i].y - m[3] * h1 + m[1] * h2 - m[2] * h3) * timestep); + point[i].z += static_cast((-point[i].z - m[3] * h1 + m[2] * h2 + h3) * timestep); + } + break; + } + case 2: + { + for (unsigned i = 0; i < num_points; i++) + { + point[i].x += static_cast(((point[i].z - m[1]) * point[i].x - m[3] * point[i].y) * timestep); + point[i].y += static_cast((m[3] * point[i].x + (point[i].z - m[1]) * point[i].y) * timestep); + point[i].z += static_cast((m[2] + m[0] * point[i].z - (point[i].z * point[i].z * point[i].z) / 3 - (point[i].x * point[i].x + point[i].y * point[i].y) * (1 + m[4] * point[i].z) + m[5] * point[i].z * point[i].x * point[i].x * point[i].x) * timestep); + } + break; + } + case 3: + { + for (unsigned i = 0; i < num_points; i++) + { + point[i].x += static_cast((point[i].x * (4 - point[i].y) + m[0] * point[i].z) * timestep); + point[i].y += static_cast((-point[i].y * (1 - point[i].x * point[i].x)) * timestep); + point[i].z += static_cast((-point[i].x * (1.5 - point[i].z * m[1]) - 0.05 * point[i].z) * timestep); + } + break; + } + case 4: + { + for (unsigned i = 0; i < num_points; i++) + { + point[i].x += static_cast((m[0] * point[i].x - point[i].y * point[i].z) * timestep * 0.25f); + point[i].y += static_cast((m[1] * point[i].y + point[i].x * point[i].z) * timestep * 0.25f); + point[i].z += static_cast((m[2] * point[i].z + point[i].x * point[i].y / 3) * timestep * 0.25f); + } + break; + } + case 5: + { + for (unsigned i = 0; i < num_points; i++) + { + point[i].x += static_cast((-m[0] * point[i].x - 4 * point[i].y - 4 * point[i].z - point[i].y * point[i].y) * timestep); + point[i].y += static_cast((-m[0] * point[i].y - 4 * point[i].z - 4 * point[i].x - point[i].z * point[i].z) * timestep); + point[i].z += static_cast((-m[0] * point[i].z - 4 * point[i].x - 4 * point[i].y - point[i].x * point[i].x) * timestep); + } + break; + } + case 6: + { + for (unsigned i = 0; i < num_points; i++) + { + point[i].x += static_cast(((1 / m[1] - m[0]) * point[i].x + point[i].z + point[i].x * point[i].y) * timestep); + point[i].y += static_cast((-m[1] * point[i].y - point[i].x * point[i].x) * timestep); + point[i].z += static_cast((-point[i].x - m[2] * point[i].z) * timestep); + } + break; + } + case 7: + { + for (unsigned i = 0; i < num_points; i++) + { + point[i].x += static_cast((-m[0] * point[i].x + point[i].y + 10.0f * point[i].y * point[i].z) * timestep); + point[i].y += static_cast((-point[i].x - 0.4 * point[i].y + 5.0f * point[i].x * point[i].z) * timestep); + point[i].z += static_cast((m[1] * point[i].z - 5.0f * point[i].x * point[i].y) * timestep); + } + break; + } + case 8: + { + for (unsigned i = 0; i < num_points; i++) + { + point[i].x += static_cast((point[i].y) * timestep); + point[i].y += static_cast((-point[i].x + point[i].y * point[i].z) * timestep); + point[i].z += static_cast((m[0] - point[i].y * point[i].y) * timestep); + } + break; + } + case 9: + { + for (unsigned i = 0; i < num_points; i++) + { + point[i].x += static_cast((-m[0] * point[i].x + sin(point[i].y)) * timestep); + point[i].y += static_cast((-m[0] * point[i].y + sin(point[i].z)) * timestep); + point[i].z += static_cast((-m[0] * point[i].z + sin(point[i].x)) * timestep); + } + break; + } + } + + /// Update Camera Position + + // Move Left and Right + if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) + { + cam_position.x -= sin(cam_angle[1] + pi / 2.0f) * 0.25f; + cam_position.z -= cos(cam_angle[1] + pi / 2.0f) * 0.25f; + } + if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) + { + cam_position.x += sin(cam_angle[1] + pi / 2.0f) * 0.25f; + cam_position.z += cos(cam_angle[1] + pi / 2.0f) * 0.25f; + } + + // Move Forwards and Backwards + if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) + { + cam_position.z -= cos(cam_angle[1]) * 0.25f; + cam_position.x -= sin(cam_angle[1]) * 0.25f; + } + if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) + { + cam_position.z += cos(cam_angle[1]) * 0.25f; + cam_position.x += sin(cam_angle[1]) * 0.25f; + } + + // Move Up and Down + if (sf::Keyboard::isKeyPressed(sf::Keyboard::LShift)) + cam_position.y += 0.1f; + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Space)) + cam_position.y -= 0.1f; + + /// Update Camera Angle + + // Look Left and Right + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) + cam_angle[1] -= 0.003f; + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) + cam_angle[1] += 0.003f; + + + // Look Up and Down + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) + cam_angle[0] += 0.003f; + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) + cam_angle[0] -= 0.003f; + + /// Compute Rotation Matrixes + + rotMatrixX = + { + {1, 0, 0}, + {0, cos(cam_angle[0]), sin(cam_angle[0])}, + {0, -sin(cam_angle[0]), cos(cam_angle[0])} + }; + rotMatrixY = + { + {cos(cam_angle[1]), 0, -sin(cam_angle[1])}, + {0, 1, 0}, + {sin(cam_angle[1]), 0, cos(cam_angle[1])} + }; + rotMatrixZ = + { + {cos(cam_angle[2]), sin(cam_angle[2]), 0}, + {-sin(cam_angle[2]), cos(cam_angle[2]), 0}, + {0, 0, 1} + }; + + + // Change speed + if (sf::Keyboard::isKeyPressed(sf::Keyboard::PageUp)) + speed += 0.025f; + if (sf::Keyboard::isKeyPressed(sf::Keyboard::PageDown)) + speed -= 0.025f; +} + +void LorenzAttractor::draw(sf::RenderWindow &window) +{ + // For every point + for (unsigned g = 0; g < num_points; g++) + { + /// Draw circle + + // Projection maths + sf::Vector3f d; + d = point[g] - cam_position; + d = rotMatrixX * (rotMatrixY * (rotMatrixZ * d)); + + // Only if the point is infront of the camera + if (d.z >= 0) + { + projected_point = + { + display_position.z * d.x / d.z + display_position.x, + display_position.z * d.y / d.z + display_position.y + }; + + circle[g].setPosition(sf::Vector2f(projected_point.x, projected_point.y)); + window.draw(circle[g]); + } + + /// Draw trail + + /* + The point of this algorithm is to use indexes in a clever manner in order to avoid shifting every + previous position one across in "trail" every frame, which takes a lot of time. It flows like a + "shifting" >for< loop. + */ + + trail[g][j[g]] = point[g]; // Add most recent position to trail at index j[g] + j[g]++; // j[g] incremented every frame, shifting the beginning of the for loop. + if (j[g] == trail[g].size() - 1) // If j[g] gets to the final index, set it to 0 + { + j[g] = 0; + trail[g][trail[g].size() - 1] = trail[g][trail[g].size() - 2]; // This has to be done. + } + + int k = 0; // Index that goes from 0 to num_points, used for colour + + // Starting from the index i right after j[g], then from 0 all the way to j[g]. + int i = j[g] + 1; + while (i != j[g]) + { + + // Project the front end of the trail + sf::Vector3f d1; + d1 = trail[g][i] - cam_position; + d1 = rotMatrixX * (rotMatrixY * (rotMatrixZ * d1)); + + sf::Vector2f proj1; + proj1 = { display_position.z * d1.x / d1.z + display_position.x, + display_position.z * d1.y / d1.z + display_position.y }; + + line[0].position = proj1; + + // Project the back end of the trail + sf::Vector3f d2; + if (i == 0) + d2 = trail[g][trail[g].size() - 2] - cam_position; + else + d2 = trail[g][i - 1] - cam_position; + d2 = rotMatrixX * (rotMatrixY * (rotMatrixZ * d2)); + + sf::Vector2f proj2; + proj2 = { display_position.z * d2.x / d2.z + display_position.x, + display_position.z * d2.y / d2.z + display_position.y }; + + line[1].position = proj2; + + // Calculate trail colours + sf::Color fade; + fade = sf::Color( + clamp(colours[u].r + trail_colours_params[u][0] * Magnitude(line[1].position - line[0].position)), + clamp(colours[u].g + trail_colours_params[u][1] * Magnitude(line[1].position - line[0].position)), + clamp(colours[u].b + trail_colours_params[u][2] * Magnitude(line[1].position - line[0].position)), + 0 + static_cast((k * 255 / trail[g].size()))); + + line[0].color = fade; + line[1].color = fade; + + // Draw if both the front and end of the trail are infront of the camera + if (d1.z >= 0 && d2.z >= 0) + window.draw(line); + + // Increment counters + i++; + if (i == trail[g].size()) // Set i to 0 once it gets to the end of "trail" + i = 0; + + k++; + } + } + + // Text + text.setString(names[u]); + text.setScale(0.1f, 0.1f); + text.setPosition(sf::Vector2f(-85, -45)); + window.draw(text); + + /// UNCOMMENT FOR ON-SCREEN COORDINATES + /// really unreadable, just use it if you wish to visualize/demonstrate changes in the first attractor (one point in lorenz) + + /* + for (unsigned i = 0; i < num_points; i++) + { + std::string coordinate_string = "(" + std::to_string(static_cast(point[i].x)) + ", " + std::to_string(static_cast(point[i].y)) + ", " + std::to_string(static_cast(point[i].z)) + ")"; + text.setString(coordinate_string); + text.setPosition(circle[i].getPosition() + sf::Vector2f(1.0f, -5.0f)); + window.draw(text); + } + */ + + // Display then clear the screen + window.display(); + window.clear(sf::Color(0, 0, 0, 255)); +} + +void LorenzAttractor::run(sf::RenderWindow &window) +{ + window.setView(view); + + while (window.isOpen() && !endSubProgram) + { + this->input(window); // Get Input + this->update(); // Update Graphics + this->draw(window); // Draw Graphics + } + + window.setView(sf::View(sf::Vector2f(static_cast(g_screenWidth / 2), static_cast(g_screenHeight / 2)), sf::Vector2f(static_cast(g_screenWidth), static_cast(g_screenHeight)))); +} + +LorenzAttractor::~LorenzAttractor() +{ +} diff --git a/LorenzAttractor.h b/LorenzAttractor.h new file mode 100644 index 0000000..9ebb1cb --- /dev/null +++ b/LorenzAttractor.h @@ -0,0 +1,111 @@ +#include "vectormath.h" + +#include +#include +#include + +class LorenzAttractor +{ +private: + sf::Event event; + sf::Clock clock; + + double input_timer = 0; + double timestep; + + float g_screenWidth = 1920; + float g_screenHeight = 1080; + + bool isFullscreen = true; + bool endSubProgram = false; + + sf::View view; + + // Camera values + sf::Vector3f cam_position = { 0, 0, -50 }; + std::vector cam_angle = { 0, 0, 0 }; + sf::Vector3f display_position = { 0, 0, 100 }; + + std::vector point; + sf::Vector2f projected_point; + + // Attractor parameters + unsigned u = 0; + std::vector> params; + + // Rotation Matrices + Matrix3 rotMatrixX; + Matrix3 rotMatrixY; + Matrix3 rotMatrixZ; + + // Visual assets + std::vector> trail; // Contains "num_points" many "trail_length" previous coordinates + std::vector j; // Indices of the last position drawn (algorithm for drawing trails without reallocating memory) + sf::VertexArray line; // Line object to be drawn + std::vector circle; + std::vector colours; + std::vector> trail_colours_params; + + // Visual parameters + unsigned num_points = 300; + unsigned trail_length = 100; + float speed = 1.f; + + // Constants + float pi = 3.141592653589f; + + // Names per attractor + sf::Text text; + sf::Font font; + std::vector names = + { + "Lorenz Attractor", + "3-Cells CNN Attractor", + "Aizawa Attractor", + "Bouali Attractor", + "Chen-Lee Attractor", + "Halvorsen Attractor", + "Finance Attractor", + "Newton-Leipnik Attractor", + "Nose-Hoover Attractor", + "Thomas Attractor" + }; + +public: + LorenzAttractor(); + + sf::Uint8 clamp(float x) + { + if (x <= 0) + return 0; + else if (x >= 255) + return 255; + else return static_cast(x); + } + + float getRandomNumber(float MIN, float MAX) + { + std::random_device device; + std::mt19937 generator(device()); + std::uniform_real_distribution distribution(MIN, MAX); + return distribution(generator); + } + + int getRandomNumber(int MIN, int MAX) + { + std::random_device device; + std::mt19937 generator(device()); + std::uniform_int_distribution distribution(MIN, MAX); + return distribution(generator); + } + + void input(sf::RenderWindow &window); + + void update(); + + void draw(sf::RenderWindow &window); + + void run(sf::RenderWindow &window); + + ~LorenzAttractor(); +}; diff --git a/README.md b/README.md index 55734b9..be16c4d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,18 @@ # chaotic-attractors Fork of https://github.com/orfeasliossatos/Coding-Projects tweaked and ported to Linux. + +The only requirement needed is SFML, you should be able to grab it from your package manager. +This project uses SFML 2.5.1 + +Run ./run.sh to compile and execute the program. + +Controls : +H to switch to the next attractor + +W/A/S/D for moving in the plane + +Space/Shift to move up and down + +Up/Down/Left/Right to turn the camera + +These will feel familiar to Minecraft players ;) diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..68813dd --- /dev/null +++ b/main.cpp @@ -0,0 +1,23 @@ +#include "LorenzAttractor.h" +#include + +int main() { + + /// Create a window + + bool isFullscreen = true; + + sf::RenderWindow window; + window.create(sf::VideoMode(1980, 1080), "Attractors", (isFullscreen ? sf::Style::Fullscreen : sf::Style::Default), sf::ContextSettings()); + // window.create(sf::VideoMode(1980, 1080), "Attractors", sf::Style::Default, sf::ContextSettings()); + window.setPosition(sf::Vector2i(0, 0)); + window.setVerticalSyncEnabled(true); + window.setFramerateLimit(144); + + /// Create an instance of the LorenzAttractor class + LorenzAttractor lorenz; + + /// Run the Lorenz Attractor simulation + lorenz.run(window); + +} diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..576894e --- /dev/null +++ b/run.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +set -e + +g++ -c main.cpp -o main.o + +g++ -c LorenzAttractor.cpp -o LorenzAttractor.o + +g++ main.o LorenzAttractor.o -o MyProgram -lsfml-graphics -lsfml-window -lsfml-system diff --git a/vectormath.h b/vectormath.h new file mode 100644 index 0000000..874502f --- /dev/null +++ b/vectormath.h @@ -0,0 +1,310 @@ +#pragma once +#include +#include +#include +#include +#include + +///////////////////// +// MATRIX CLASS // +///////////////////// + +template +class Matrix3 +{ +private: + T **m_data; +public: + Matrix3() + { + m_data = new T*[3]; + for (int i = 0; i < 3; i++) + m_data[i] = new T[3]; + } + + Matrix3(const std::initializer_list> &list_ext) + { + assert(list_ext.size() == 3); + + m_data = new T*[3]; + for (int i = 0; i < 3; i++) + m_data[i] = new T[3]; + + int i = 0, j = 0; + for (auto &list_int : list_ext) + { + assert(list_int.size() == 3); + j = 0; + for (auto &element : list_int) + { + m_data[i][j] = element; + j++; + } + i++; + } + } + + void erase() + { + for (int i = 0; i < 3; i++) + delete[] m_data[i]; + delete[] m_data; + + m_data = nullptr; + } + + const T* operator[](const int r) const + { + assert(r >= 0 && r < 3); + return m_data[r]; + } + + T* operator[](const int r) + { + assert(r >= 0 && r < 3); + return m_data[r]; + } + + Matrix3& operator=(const std::initializer_list> list_ext) + { + assert(list_ext.size() == 3); + + this->erase(); + + m_data = new T*[3]; + for (int i = 0; i < 3; i++) + m_data[i] = new T[3]; + + int i = 0, j = 0; + for (auto &list_int : list_ext) + { + assert(list_int.size() == 3); + j = 0; + for (auto &element : list_int) + { + m_data[i][j] = element; + j++; + } + i++; + } + + return (*this); + } + + Matrix3& operator=(const Matrix3 &m) + { + this->erase(); + + m_data = new T*[3]; + for (int i = 0; i < 3; i++) + m_data[i] = new T[3]; + + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + m_data[i][j] = m[i][j]; + + return (*this); + } + + ~Matrix3() + { + delete[] m_data[0]; + delete[] m_data[1]; + delete[] m_data[2]; + + delete[] m_data; + } +}; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +template +std::ostream& operator<<(std::ostream &out, Matrix3 &m) +{ + for (int r = 0; r < 3; r++) + { + for (int c = 0; c < 3; c++) + out << m[r][c] << " "; + out << "\n"; + } + + return out; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +template +bool operator==(Matrix3 m1, Matrix3 m2) +{ + int s = 0; + for (int r = 0; r < m1.getNumRows(); r++) + for (int c = 0; c < m1.getNumCols(); c++) + s += (m1[r][c] == m2[r][c]); + + if (s == m1.getNumRows() * m1.getNumCols()) + return true; + else return false; +} + +template +bool operator!=(Matrix3 m1, Matrix3 m2) +{ + int s = 0; + for (int r = 0; r < m1.getNumRows(); r++) + for (int c = 0; c < m1.getNumCols(); c++) + s += (m1[r][c] == m2[r][c]); + + if (s == m1.getNumRows() * m1.getNumCols()) + return false; + else return true; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +template +Matrix3 operator+(const Matrix3 &left, const Matrix3 &right) +{ + return { {left[0][0] + right[0][0], left[0][1] + right[0][1], left[0][2] + right[0][2]}, + {left[1][0] + right[1][0], left[1][1] + right[1][1], left[1][2] + right[1][2]}, + {left[2][0] + right[2][0], left[2][1] + right[2][1], left[2][2] + right[2][2]} }; +} + +template +Matrix3& operator+=(Matrix3 &left, const Matrix3 &right) +{ + for (int r = 0; r < 3; r++) + for (int c = 0; c < 3; c++) + left[r][c] += right[r][c]; + + return left; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +template +Matrix3 operator-(const Matrix3 &left, const Matrix3 &right) +{ + return { {left[0][0] - right[0][0], left[0][1] - right[0][1], left[0][2] - right[0][2]}, + {left[1][0] - right[1][0], left[1][1] - right[1][1], left[1][2] - right[1][2]}, + {left[2][0] - right[2][0], left[2][1] - right[2][1], left[2][2] - right[2][2]} }; +} + +template +Matrix3& operator-=(Matrix3 &left, const Matrix3 &right) +{ + for (int r = 0; r < 3; r++) + for (int c = 0; c < 3; c++) + left[r][c] -= right[r][c]; + + return left; +} + +template +Matrix3& operator-(Matrix3 &left) +{ + for (int r = 0; r < 3; r++) + for (int c = 0; c < 3; c++) + left[r][c] = -left[r][c]; + + return left; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +template +Matrix3& operator*=(Matrix3 &left, const U &right) +{ + for (int r = 0; r < 3; r++) + for (int c = 0; c < 3; c++) + left[r][c] *= right; + return left; +} + +template +Matrix3 operator*(const Matrix3 &left, const U &right) +{ + return { {left[0][0] * right, left[0][1] * right, left[0][2] * right}, + {left[1][0] * right, left[1][1] * right, left[1][2] * right}, + {left[2][0] * right, left[2][1] * right, left[2][2] * right} }; +} + +template +Matrix3 operator*(const U &left, const Matrix3 &right) +{ + return { {left * right[0][0], left * right[0][1], left * right[0][2]}, + {left * right[1][0], left * right[1][1], left * right[1][2]}, + {left * right[2][0], left * right[2][1], left * right[2][2]} }; +} + +template +Matrix3 operator*(Matrix3 &left, Matrix3 &right) +{ + T _00 = left[0][0] * right[0][0] + left[0][1] * right[1][0] + left[0][2] * right[2][0]; + T _01 = left[0][0] * right[0][1] + left[0][1] * right[1][1] + left[0][2] * right[2][1]; + T _02 = left[0][0] * right[0][2] + left[0][1] * right[1][2] + left[0][2] * right[2][2]; + + T _10 = left[1][0] * right[0][0] + left[1][1] * right[1][0] + left[1][2] * right[2][0]; + T _11 = left[1][0] * right[0][1] + left[1][1] * right[1][1] + left[1][2] * right[2][1]; + T _12 = left[1][0] * right[0][2] + left[1][1] * right[1][2] + left[1][2] * right[2][2]; + + T _20 = left[2][0] * right[0][0] + left[2][1] * right[1][0] + left[2][2] * right[2][0]; + T _21 = left[2][0] * right[0][1] + left[2][1] * right[1][1] + left[2][2] * right[2][1]; + T _22 = left[2][0] * right[0][2] + left[2][1] * right[1][2] + left[2][2] * right[2][2]; + + return { {_00,_01,_02},{_10,_11,_12},{_20,_21,_22} }; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +template +Matrix3& operator/=(Matrix3 &left, U right) +{ + for (int r = 0; r < 3; r++) + for (int c = 0; c < 3; c++) + left[r][c] /= right; + return left; +} + +template +Matrix3 operator/(Matrix3 left, U right) +{ + return { {left[0][0] / right, left[0][1] / right, left[0][2] / right}, + {left[1][0] / right, left[1][1] / right, left[1][2] / right}, + {left[2][0] / right, left[2][1] / right, left[2][2] / right} }; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +///////////////////// +// 2D VECTOR MATHS // +///////////////////// + +template +float Magnitude(const V2 &v) +{ + return sqrt(static_cast(v.x * v.x + v.y * v.y)); +} + +template +V2 UnitVector(const V2 &v) +{ + return v / Magnitude(v); +} + +template +bool operator>(const V2 &v1,const V2 &v2) +{ + if (Magnitude(v1) > Magnitude(v2)) + return true; + else return false; +} + +template +bool operator<(V2 &v1, V2 &v2) +{ + if (Magnitude(v1) > Magnitude(v2)) + return true; + else return false; +} + +///////////////////// +// 3D VECTOR MATHS // +///////////////////// + +template +sf::Vector3 operator*(const Matrix3 &m, const sf::Vector3 &v) +{ + return sf::Vector3( + m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z, + m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z, + m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z + ); +} -- cgit v1.2.3