diff options
author | xAlpharax <42233094+xAlpharax@users.noreply.github.com> | 2023-09-02 15:41:23 +0300 |
---|---|---|
committer | xAlpharax <42233094+xAlpharax@users.noreply.github.com> | 2023-09-02 15:41:23 +0300 |
commit | 27b51e8c35e62183583a80a8689591fdbaf031f9 (patch) | |
tree | c0af7189ad3cc35bb56c912aa3a2fe99235826f5 | |
parent | fa6df107cb0d78e708cb8457c0f7d74969156f56 (diff) |
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
-rw-r--r-- | LorenzAttractor.cpp | 514 | ||||
-rw-r--r-- | LorenzAttractor.h | 111 | ||||
-rw-r--r-- | README.md | 16 | ||||
-rw-r--r-- | main.cpp | 23 | ||||
-rwxr-xr-x | run.sh | 9 | ||||
-rw-r--r-- | vectormath.h | 310 |
6 files changed, 983 insertions, 0 deletions
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<float>(g_screenWidth / 10), static_cast<float>(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<int>(colours[c].r) << " " <<
+ static_cast<int>(colours[c].g) << " " <<
+ static_cast<int>(colours[c].b) << " " <<
+ static_cast<int>(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<int>(g_screenWidth), static_cast<int>(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<float> &m = params[u];
+ switch (u)
+ {
+ case 0:
+ {
+ for (unsigned i = 0; i < num_points; i++)
+ {
+ point[i].x += static_cast<float>(m[0] * (point[i].y - point[i].x) * timestep);
+ point[i].y += static_cast<float>((point[i].x * (m[1] - point[i].z) - point[i].y) * timestep);
+ point[i].z += static_cast<float>((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<float>((-point[i].x + m[0] * h1 - m[3] * h2 - m[3] * h3) * timestep);
+ point[i].y += static_cast<float>((-point[i].y - m[3] * h1 + m[1] * h2 - m[2] * h3) * timestep);
+ point[i].z += static_cast<float>((-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<float>(((point[i].z - m[1]) * point[i].x - m[3] * point[i].y) * timestep);
+ point[i].y += static_cast<float>((m[3] * point[i].x + (point[i].z - m[1]) * point[i].y) * timestep);
+ point[i].z += static_cast<float>((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<float>((point[i].x * (4 - point[i].y) + m[0] * point[i].z) * timestep);
+ point[i].y += static_cast<float>((-point[i].y * (1 - point[i].x * point[i].x)) * timestep);
+ point[i].z += static_cast<float>((-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<float>((m[0] * point[i].x - point[i].y * point[i].z) * timestep * 0.25f);
+ point[i].y += static_cast<float>((m[1] * point[i].y + point[i].x * point[i].z) * timestep * 0.25f);
+ point[i].z += static_cast<float>((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<float>((-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<float>((-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<float>((-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<float>(((1 / m[1] - m[0]) * point[i].x + point[i].z + point[i].x * point[i].y) * timestep);
+ point[i].y += static_cast<float>((-m[1] * point[i].y - point[i].x * point[i].x) * timestep);
+ point[i].z += static_cast<float>((-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<float>((-m[0] * point[i].x + point[i].y + 10.0f * point[i].y * point[i].z) * timestep);
+ point[i].y += static_cast<float>((-point[i].x - 0.4 * point[i].y + 5.0f * point[i].x * point[i].z) * timestep);
+ point[i].z += static_cast<float>((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<float>((point[i].y) * timestep);
+ point[i].y += static_cast<float>((-point[i].x + point[i].y * point[i].z) * timestep);
+ point[i].z += static_cast<float>((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<float>((-m[0] * point[i].x + sin(point[i].y)) * timestep);
+ point[i].y += static_cast<float>((-m[0] * point[i].y + sin(point[i].z)) * timestep);
+ point[i].z += static_cast<float>((-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<sf::Uint8>((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<int>(point[i].x)) + ", " + std::to_string(static_cast<int>(point[i].y)) + ", " + std::to_string(static_cast<int>(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<float>(g_screenWidth / 2), static_cast<float>(g_screenHeight / 2)), sf::Vector2f(static_cast<float>(g_screenWidth), static_cast<float>(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 <random>
+#include <string>
+#include <SFML/Graphics.hpp>
+
+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<float> cam_angle = { 0, 0, 0 };
+ sf::Vector3f display_position = { 0, 0, 100 };
+
+ std::vector<sf::Vector3f> point;
+ sf::Vector2f projected_point;
+
+ // Attractor parameters
+ unsigned u = 0;
+ std::vector<std::vector<float>> params;
+
+ // Rotation Matrices
+ Matrix3<float> rotMatrixX;
+ Matrix3<float> rotMatrixY;
+ Matrix3<float> rotMatrixZ;
+
+ // Visual assets
+ std::vector<std::vector<sf::Vector3f>> trail; // Contains "num_points" many "trail_length" previous coordinates
+ std::vector<unsigned> j; // Indices of the last position drawn (algorithm for drawing trails without reallocating memory)
+ sf::VertexArray line; // Line object to be drawn
+ std::vector<sf::CircleShape> circle;
+ std::vector<sf::Color> colours;
+ std::vector<std::vector<float>> 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<std::string> 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<sf::Uint8>(x);
+ }
+
+ float getRandomNumber(float MIN, float MAX)
+ {
+ std::random_device device;
+ std::mt19937 generator(device());
+ std::uniform_real_distribution<float> distribution(MIN, MAX);
+ return distribution(generator);
+ }
+
+ int getRandomNumber(int MIN, int MAX)
+ {
+ std::random_device device;
+ std::mt19937 generator(device());
+ std::uniform_int_distribution<int> distribution(MIN, MAX);
+ return distribution(generator);
+ }
+
+ void input(sf::RenderWindow &window);
+
+ void update();
+
+ void draw(sf::RenderWindow &window);
+
+ void run(sf::RenderWindow &window);
+
+ ~LorenzAttractor();
+};
@@ -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 <SFML/Graphics.hpp> + +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); + +} @@ -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 <SFML/Graphics.hpp>
+#include <iostream>
+#include <assert.h>
+#include <initializer_list>
+#include <math.h>
+
+/////////////////////
+// MATRIX CLASS //
+/////////////////////
+
+template<class T>
+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<std::initializer_list<T>> &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<T>& operator=(const std::initializer_list<std::initializer_list<T>> 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<T>& operator=(const Matrix3<T> &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<typename T>
+std::ostream& operator<<(std::ostream &out, Matrix3<T> &m)
+{
+ for (int r = 0; r < 3; r++)
+ {
+ for (int c = 0; c < 3; c++)
+ out << m[r][c] << " ";
+ out << "\n";
+ }
+
+ return out;
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+template<typename T>
+bool operator==(Matrix3<T> m1, Matrix3<T> 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<typename T>
+bool operator!=(Matrix3<T> m1, Matrix3<T> 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<typename T>
+Matrix3<T> operator+(const Matrix3<T> &left, const Matrix3<T> &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<typename T>
+Matrix3<T>& operator+=(Matrix3<T> &left, const Matrix3<T> &right)
+{
+ for (int r = 0; r < 3; r++)
+ for (int c = 0; c < 3; c++)
+ left[r][c] += right[r][c];
+
+ return left;
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+template<typename T>
+Matrix3<T> operator-(const Matrix3<T> &left, const Matrix3<T> &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<typename T>
+Matrix3<T>& operator-=(Matrix3<T> &left, const Matrix3<T> &right)
+{
+ for (int r = 0; r < 3; r++)
+ for (int c = 0; c < 3; c++)
+ left[r][c] -= right[r][c];
+
+ return left;
+}
+
+template<typename T>
+Matrix3<T>& operator-(Matrix3<T> &left)
+{
+ for (int r = 0; r < 3; r++)
+ for (int c = 0; c < 3; c++)
+ left[r][c] = -left[r][c];
+
+ return left;
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+template<typename T, typename U>
+Matrix3<T>& operator*=(Matrix3<T> &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<typename T, typename U>
+Matrix3<T> operator*(const Matrix3<T> &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<typename T, typename U>
+Matrix3<T> operator*(const U &left, const Matrix3<T> &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<typename T>
+Matrix3<T> operator*(Matrix3<T> &left, Matrix3<T> &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<typename T, typename U>
+Matrix3<T>& operator/=(Matrix3<T> &left, U right)
+{
+ for (int r = 0; r < 3; r++)
+ for (int c = 0; c < 3; c++)
+ left[r][c] /= right;
+ return left;
+}
+
+template<typename T, typename U>
+Matrix3<T> operator/(Matrix3<T> 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<typename V2>
+float Magnitude(const V2 &v)
+{
+ return sqrt(static_cast<float>(v.x * v.x + v.y * v.y));
+}
+
+template<typename V2>
+V2 UnitVector(const V2 &v)
+{
+ return v / Magnitude(v);
+}
+
+template<typename V2>
+bool operator>(const V2 &v1,const V2 &v2)
+{
+ if (Magnitude(v1) > Magnitude(v2))
+ return true;
+ else return false;
+}
+
+template<typename V2>
+bool operator<(V2 &v1, V2 &v2)
+{
+ if (Magnitude(v1) > Magnitude(v2))
+ return true;
+ else return false;
+}
+
+/////////////////////
+// 3D VECTOR MATHS //
+/////////////////////
+
+template<typename T>
+sf::Vector3<T> operator*(const Matrix3<T> &m, const sf::Vector3<T> &v)
+{
+ return sf::Vector3<T>(
+ 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
+ );
+}
|