Les courbes de Lissajous

A propos du code

Le code dans cet article a été écrit avec Code::Blocks et la SDL 2.
Vous pouvez trouver ici un guide pour installer ces logiciels.
Bien qu'il soit basé sur la SDL, je n'utilise pas ses fonctions directement. J'ai écrit une petite bibliothèque
avec quelques fonctions basiques pour faciliter la compréhension et la portabilité dans un autre langage.
Vous pouvez en apprendre plus sur cette bibliothèque ici.

Cet article utilise la fonction de ligne qu'on a ajouté dans l'algorithme de ligne de Bresenham.

Jouons encore avec le cercle

Dans un précédent article on a parlé du cercle et on a trouvé ces équations
		x = xC + R * cos θ
		y = yC + R * sin θ
				
On a essayé de changer les rayons et d'ajouter une valeur à l'angle θ et on a obtenu diverses ellipses.
Mais que se passe-t-il si on multiplie θ par une valeur ?
		x = xC + R * cos(a1 * θ)
		y = yC + R * sin(a2 * θ)
				
Essayons avec a1 = 1 et a2 = 2;
		int main(int argc, char* argv[])
		{
			// init the window
			gfx.init("Lissajous", SCREEN_WIDTH, SCREEN_HEIGHT);
			gfx.init2D();
			gfx.clearScreen(Color(0, 0, 0, SDL_ALPHA_OPAQUE));

			int centerX = SCREEN_WIDTH / 2;
			int centerY = SCREEN_HEIGHT / 2;
			int radius = 200;

			for (int i = 0; i < 360; i++)
			{
				float angle0 = DEG_TO_RAD(i);
				int x0 = centerX + radius * cos(angle0);
				int y0 = centerY + radius * sin(2.0 * angle0);

				float angle1 = DEG_TO_RAD(i + 1);
				int x1 = centerX + radius * cos(angle1);
				int y1 = centerY + radius * sin(2.0 * angle1);

				gfx.line(x0, y0, x1, y1, Color(255, 255, 255));

				gfx.render();
				sys.wait(20);
			}

			// wait until we quit
			while (sys.isQuitRequested() == false)
			{
				gfx.render();
				sys.wait(20);
				sys.processEvents();
			}

			gfx.quit();

			return EXIT_SUCCESS;
		}

		Télécharger le code source
		Télécharger l'exécutable pour Windows
				
On obtient une courbe qui ressemble au symbole de l'infini.


Une famille de courbes

Si on fait varier a1 et a2 entre 1 et 5 on obtient différentes formes.
		#define SCREEN_WIDTH    640
		#define SCREEN_HEIGHT   640

		int main(int argc, char* argv[])
		{
			// init the window
			gfx.init("Lissajous 2", SCREEN_WIDTH, SCREEN_HEIGHT);
			gfx.init2D();
			gfx.clearScreen(Color(0, 0, 0, SDL_ALPHA_OPAQUE));


			for (int i = 0; i < 360; i++)
			{
				for (int c2 = 1; c2 < 6; c2++)
					for (int c1 = 1; c1 < 6; c1++)
					{
						int centerX = SCREEN_WIDTH / 2 + (c1 - 3) * 120;
						int centerY = SCREEN_HEIGHT/ 2 + (c2 - 3) * 120;
						int radius = 50;

						float angle0 = DEG_TO_RAD(i);
						int x0 = centerX + radius * cos(c1 * angle0);
						int y0 = centerY + radius * sin(c2 * angle0);

						float angle1 = DEG_TO_RAD(i + 1);
						int x1 = centerX + radius * cos(c1 * angle1);
						int y1 = centerY + radius * sin(c2 * angle1);

						gfx.line(x0, y0, x1, y1, Color(255, 255, 255));
					}

				gfx.render();
				sys.wait(20);
			}

			// wait until we quit
			while (sys.isQuitRequested() == false)
			{
				gfx.render();
				sys.wait(20);
				sys.processEvents();
			}

			gfx.quit();

			return EXIT_SUCCESS;
		}

		Télécharger le code source
		Télécharger l'exécutable pour Windows
				

Ces formes s'appellent des courbes de Lissajous.
Enfin ce n'est pas la vraie définition d'une courbe Lissajous car il devrait y avoir 2 sinus:
		x = xC + R * sin(a1 * θ)
		y = yC + R * sin(a2 * θ)
				
Mais notre définition donne le même type de courbes.

En électronique, quand vous utilisez un oscilloscope, vous pouvez y brancher un courant sinusoïdal pour déplacer le
point horizontalement et un autre pour le déplacer verticalement.
Si les courants ont des fréquences différentes, vous verrez ce genre de courbes.
C'est une methode qui est utilisée pour mesurer le déphasage entre les deux courants.

Cette courbe représente aussi le mouvement d'un double pendule, où l'un des pendules se déplace suivant l'axe x et
l'autre se déplace suivant l'axe y.

Jusqu'à maintenant on n'a utilise que des entiers pour a1 et a2.
Vous pouvez aussi essayer avec des valeurs non entières. Vous aurez alors besoin de modifier l'angle plus loin que
360 degrés pour obtenir la courbe en entier.
Mais vous obtiendrez le même type de formes parce que c'est seulement le rapport a1 / a2 qui les définit.

Remplir la courbe

Comme beaucoup de ces courbes sont symétriques par rapport à l'axe des x, une façon d'obtenir une courbe pleine est
tracer des lignes verticales depuis cet axe.
		int main(int argc, char* argv[])
		{
			// init the window
			gfx.init("Lissajous 3", SCREEN_WIDTH, SCREEN_HEIGHT);
			gfx.init2D();
			gfx.clearScreen(Color(0, 0, 0, SDL_ALPHA_OPAQUE));

			int centerX = SCREEN_WIDTH / 2;
			int centerY = SCREEN_HEIGHT/ 2;
			int radius = 200;

			for (int i = 0; i < 360; i++)
			{
				float angle = DEG_TO_RAD(i);
				int x = centerX + radius * cos(angle);
				int y = centerY + radius * sin(3.0 * angle);

				Color c;
				c.r = 255;
				c.g = 128 + 127 * cos(angle);
				c.b = 0;
				gfx.line(x, y, x, centerY, c);

				gfx.render();
				sys.wait(20);
			}

			// wait until we quit
			while (sys.isQuitRequested() == false)
			{
				gfx.render();
				sys.wait(20);
				sys.processEvents();
			}

			gfx.quit();

			return EXIT_SUCCESS;
		}

		Télécharger le code source
		Télécharger l'exécutable pour Windows
				

Multiplication et addition

Maintenant que se passe-t-il si on ajoute une valeur à l'angle, comme on l'a fait dans l'article précédent ?
		float angleAdd = DEG_TO_RAD(40);

		for (int i = 0; i < 360; i++)
		{
			float angle0 = DEG_TO_RAD(i);
			int x0 = centerX + radius * cos(angle0);
			int y0 = centerY + radius * sin(2.0 * angle0 + angleAdd);

			float angle1 = DEG_TO_RAD(i + 1);
			int x1 = centerX + radius * cos(angle1);
			int y1 = centerY + radius * sin(2.0 * angle1 + angleAdd);

			gfx.line(x0, y0, x1, y1, Color(255, 255, 255));

			gfx.render();
			sys.wait(20);
		}

		Télécharger le code source
		Télécharger l'exécutable pour Windows
				
On obtient une courbe déformée


Links

Vidéo du deuxième programme

Vidéo d'un double pendule traçant des Lissajous

Vidéo d'un harmonographe

Lissajous en Processing

Lissajous en p5.js