TheAlgorithms/C++ 1.0.0
All the algorithms implemented in C++
Loading...
Searching...
No Matches
spirograph.cpp
Go to the documentation of this file.
1
16#ifdef USE_GLUT
17#ifdef __APPLE__
18#include <GLUT/glut.h> // include path on Macs is different
19#else
20#include <GL/glut.h>
21#endif // __APPLE__
22#endif
23#define _USE_MATH_DEFINES
24#include <array>
25#include <cmath>
26#include <cstdlib>
27#include <ctime>
28#include <fstream>
29#include <iomanip>
30#include <iostream>
31#include <sstream>
32#ifdef _OPENMP
33#include <omp.h>
34#endif
35
39namespace spirograph {
69template <std::size_t N>
70void spirograph(std::array<std::pair<double, double>, N> *points, double l,
71 double k, double rot) {
72 double dt = rot * 2.f * M_PI / N;
73 double R = 1.f;
74 const double k1 = 1.f - k;
75 int32_t step = 0;
76
77#ifdef _OPENMP
78#pragma omp for
79#endif
80 for (step = 0; step < N; step++) {
81 double t = dt * step;
82 double first = R * (k1 * std::cos(t) + l * k * std::cos(k1 * t / k));
83 double second = R * (k1 * std::sin(t) - l * k * std::sin(k1 * t / k));
84 points[0][step].first = first;
85 points[0][step].second = second;
86 }
87}
88
93void test() {
94 const size_t N = 500;
95 double l = 0.3, k = 0.75, rot = 10.;
96 std::stringstream fname;
97 fname << std::setw(3) << "spirograph_" << l << "_" << k << "_" << rot
98 << ".csv";
99 std::ofstream fp(fname.str());
100 if (!fp.is_open()) {
101 perror(fname.str().c_str());
102 exit(EXIT_FAILURE);
103 }
104
105 std::array<std::pair<double, double>, N> points;
106
107 spirograph(&points, l, k, rot);
108
109 for (size_t i = 0; i < N; i++) {
110 fp << points[i].first << "," << points[i].first;
111 if (i < N - 1) {
112 fp << '\n';
113 }
114 }
115
116 fp.close();
117}
118
119#ifdef USE_GLUT
120static bool paused = 0;
121static const int animation_speed = 25;
123static const double step = 0.01;
124static double l_ratio = step * 10;
125static double k_ratio = step;
126static const double num_rot = 20.;
130static inline void glutBitmapString(void *font, char *message) {
131 for (char *ch = message; *ch != '\0'; ch++) glutBitmapCharacter(font, *ch);
132}
133
144template <size_t N>
145void display_graph(const std::array<std::pair<double, double>, N> &points,
146 double l, double k) {
147 glClearColor(1.0f, 1.0f, 1.0f,
148 0.0f); // Set background color to white and opaque
149 glClear(GL_COLOR_BUFFER_BIT); // Clear the color buffer (background)
150
151 glBegin(GL_LINES); // draw line segments
152 glColor3f(0.f, 0.f, 1.f); // blue
153 glPointSize(2.f); // point size in pixels
154
155 for (size_t i = 1; i < N; i++) {
156 glVertex2f(points[i - 1].first, points[i - 1].second); // line from
157 glVertex2f(points[i].first, points[i].second); // line to
158 }
159 glEnd();
160
161 glColor3f(0.f, 0.f, 0.f);
162 std::stringstream buffer;
163 buffer << std::setw(3) << "l = " << l;
164 glRasterPos2f(-.85, .85);
165 glutBitmapString(GLUT_BITMAP_TIMES_ROMAN_24,
166 const_cast<char *>(buffer.str().c_str()));
167 buffer.str("");
168 buffer.clear();
169 buffer << std::setw(3) << "k = " << k;
170 glRasterPos2f(-.85, .70);
171 glutBitmapString(GLUT_BITMAP_TIMES_ROMAN_24,
172 const_cast<char *>(buffer.str().c_str()));
173
174 glutSwapBuffers();
175}
176
181void test2() {
182 const size_t N = 5000; // number of samples
183
184 static bool direction1 = true; // increment if true, otherwise decrement
185 static bool direction2 = true; // increment if true, otherwise decrement
186
187 std::array<std::pair<double, double>, N> points;
188
189 spirograph(&points, l_ratio, k_ratio, num_rot);
190 display_graph(points, l_ratio, k_ratio);
191
192 if (paused)
193 // if paused, do not update l_ratio and k_ratio
194 return;
195
196 if (direction1) { // increment k_ratio
197 if (k_ratio >= (1.f - step)) // maximum limit
198 direction1 = false; // reverse direction of k_ratio
199 else
200 k_ratio += step;
201 } else { // decrement k_ratio
202 if (k_ratio <= step) { // minimum limit
203 direction1 = true; // reverse direction of k_ratio
204
205 if (direction2) { // increment l_ratio
206 if (l_ratio >= (1.f - step)) // max limit of l_ratio
207 direction2 = false; // reverse direction of l_ratio
208 else
209 l_ratio += step;
210 } else { // decrement l_ratio
211 if (l_ratio <= step) // minimum limit of l_ratio
212 direction2 = true; // reverse direction of l_ratio
213 else
214 l_ratio -= step;
215 }
216 } else { // no min limit of k_ratio
217 k_ratio -= step;
218 }
219 }
220}
221
225void timer_cb(int t) {
226 glutTimerFunc(animation_speed, timer_cb, 0);
227 glutPostRedisplay();
228}
229
237void keyboard_cb(unsigned char key, int x, int y) {
238 switch (key) {
239 case ' ': // spacebar toggles pause
240 paused = !paused; // toggle
241 break;
242 case GLUT_KEY_UP:
243 case '+': // up arrow key
244 k_ratio += step;
245 break;
246 case GLUT_KEY_DOWN:
247 case '_': // down arrow key
248 k_ratio -= step;
249 break;
250 case GLUT_KEY_RIGHT:
251 case '=': // left arrow key
252 l_ratio += step;
253 break;
254 case GLUT_KEY_LEFT:
255 case '-': // right arrow key
256 l_ratio -= step;
257 break;
258 case 0x1B: // escape key exits
259 exit(EXIT_SUCCESS);
260 default:
261 return;
262 }
263}
264#endif
265} // namespace spirograph
266
268int main(int argc, char **argv) {
270
271#ifdef USE_GLUT
272 glutInit(&argc, argv);
273 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
274 glutCreateWindow("Spirograph");
275 glutInitWindowSize(400, 400);
276 // glutIdleFunc(glutPostRedisplay);
277 glutTimerFunc(spirograph::animation_speed, spirograph::timer_cb, 0);
278 glutKeyboardFunc(spirograph::keyboard_cb);
279 glutDisplayFunc(spirograph::test2);
280 glutMainLoop();
281#endif
282
283 return 0;
284}
double k(double x)
Another test function.
double l(double x)
Another test function.
static void test2()
Self-implementations, 2nd test.
int main()
Main function.
void test()
Test function to save resulting points to a CSV file.
constexpr uint32_t N
A struct to represent sparse table for min() as their invariant function, for the given array A....