-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.cpp
144 lines (117 loc) · 4.98 KB
/
main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/** @file main.cpp
* @brief Cardioid program
* @details An SFML application that creates times table cardioid patterns
* @author Pablo Klaschka
* @copyright Copyright (c) 2019 by Pablo Klaschka and fliegwerk. All rights reserved.
*/
#include <iostream>
#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>
#include <cmath>
/**
* The width and height of the (square) window. By default, it's `1280`, corresponding to 1280px.
*/
unsigned int window_size = 1280;
/**
* The amount of lines / divisions of the circle present in the project. This can be adjusted to fit
* one's needs. It should be noted, however, that the time it takes to render a frame is linearly proportional to this
* number, and too many lines can mean worse results (since the limited amount of pixels and anti-aliasing decrease the
* quality of the image). Therefore, choosing this value is a balancing and there is no "correct" value (although even
* numbers work significantly better).
*/
const int count = 640;
/**
* Draws a white line from the given start point to the given end point
*
* Runs in \f$O(1)\f$
* @param window The RenderWindow in which the line gets drawn
* @param start The starting point of the line
* @param end The end point of the line
*/
void line(sf::RenderWindow *window, sf::Vector2i *start, sf::Vector2i *end) {
// Create vertex
sf::Vertex line[] =
{
sf::Vertex(sf::Vector2f(end->x, end->y)),
sf::Vertex(sf::Vector2f(start->x, start->y))
};
line->color = sf::Color::White;
window->draw(line, 2, sf::Lines); // Draw a line with 2 segments
}
/**
* Calculates the coordinates \f$(x,y)\f$ of a point on a circle, offset by an angle \f$\varphi\f$.
*
* Runs in \f$O(1)\f$
* @param angle The angle \f$\varphi\f$ in which the angle is offset clockwise from \f$(c_x, c_y - r)\f$
* @param radius The circle's radius \f$r\f$
* @param center The center coordinates of the circle \f$(c_x,c_y)\f$
* @return The coordinates of the point
*/
sf::Vector2i *pointOnCircle(double angle, const float radius, sf::Vector2i *center) {
// Calculate point on unit circle
sf::Vector2f unitCirclePoint(static_cast<float>(sin(M_PI - angle)), static_cast<float>(sin(1.5 * M_PI - angle)));
// Add the radius
unitCirclePoint.x *= radius;
unitCirclePoint.y *= radius;
// And the center offset
unitCirclePoint.x += center->x;
unitCirclePoint.y += center->y;
return new sf::Vector2i(static_cast<int>(unitCirclePoint.x), static_cast<int>(unitCirclePoint.y));
}
/**
* Draws all the lines
*
* Runs in \f$O(n)\f$, where \f$n\f$ is the count, i.e., the number of divisions of the circle.
* @param window The window the lines get drawn in
* @param radius The radius of the circle
* @param center The center coordinates of the circle, relative to the top-left point of the window
* @param count The count, i.e., the number of divisions of the circle.
* @param multiplier The multiplier
*/
void drawLines(sf::RenderWindow *window, float radius, sf::Vector2i *center, const int count, const double multiplier) {
double angleIncrement = 2 * M_PI / count;
for (int i = 0; i < count; i++) {
auto currentPos = pointOnCircle(i * angleIncrement, radius, center);
auto toPos = pointOnCircle(fmod(i * (multiplier), count) * angleIncrement, radius, center);
sf::CircleShape point(4);
point.setFillColor(sf::Color::White);
point.setPosition(currentPos->x - 2, currentPos->y - 2);
window->draw(point);
line(window, currentPos, toPos);
// Extremely important (otherwise, RAM will quickly get eaten up by the app ;-)):
delete currentPos;
delete toPos;
}
}
int main() {
sf::ContextSettings settings;
settings.antialiasingLevel = 8;
sf::RenderWindow window(sf::VideoMode(window_size, window_size), "SFML shapes", sf::Style::Default, settings);
double multiplier = 2.0;
while (window.isOpen()) {
sf::Event event{};
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed)
window.close();
if (event.type == sf::Event::MouseMoved) {
sf::Vector2i globalPosition = sf::Mouse::getPosition(window);
multiplier = 20.0 * globalPosition.y / window_size + 1.1;
}
}
sf::sleep(sf::milliseconds(5));
window.clear(sf::Color::Black);
float radius = window_size / 2 - 25; // NOLINT(bugprone-integer-division)
auto *circle = new sf::CircleShape(radius, 60);
circle->setOutlineColor(sf::Color::White);
circle->setFillColor(sf::Color::Black);
circle->setOutlineThickness(2.0f);
circle->setPosition(25, 25);
window.draw(*circle);
delete circle;
auto center = new sf::Vector2i(window_size / 2, window_size / 2);
drawLines(&window, radius, center, count, multiplier);
delete center;
window.display();
}
return EXIT_SUCCESS;
}