lissajous image

Lissajous Curve table with python

12:38 PM, November-03-2022

#Python #computer graphic #Math

Joseph Bakulikira


Hello Everyone, Welcome to this Blog about Lissajous curve table

Lissajous curve /ˈlɪsəʒuː/, also known as Lissajous figure or Bowditch curve /ˈbaʊdɪtʃ/, is the graph of a system of parametric equations

{\displaystyle x=A\sin(at+\delta ),\quad y=B\sin(bt),}

which describe complex harmonic motion. This family of curves was investigated by Nathaniel Bowditch in 1815, and later in more detail in 1857 by Jules Antoine Lissajous (for whom it has been named).

The appearance of the figure is highly sensitive to the ratio a/b. For a ratio of 1, the figure is an ellipse, with special cases including circles (A = B, δ = π/2 radians) and lines (δ = 0). Another simple Lissajous figure is the parabola (b/a = 2, δ = π/4). Other ratios produce more complicated curves, which are closed only if a/b is rational. The visual form of these curves is often suggestive of a three-dimensional knot, and indeed many kinds of knots, including those known as Lissajous knots, project to the plane as Lissajous figures.

To make our lissajous we gonna be using pygame , if you don't have pygame you can install it just by running this command in your terminal pip install pygame .

so First we gonna start by making a new file "curve.py": this file gonna contain the Curve Class and this class gonna just store all the point of any given curve and also keep track of the current point.

we gonna add a function in this class to render or draw this curve on the screen

import pygame
class Curve:
    def __init__(self, color):
        self.points = []
        self.color = color
        self.current = [0,0]
    def set_point_x(self, x):
        self.current[0] = x
    def set_point_y(self, y):
        self.current[1] = y
    def update_points(self):
        point = (int(self.current[0]), self.current[1]) 
        if point not in self.points:
            self.points.append(point )

    def draw(self, screen):
        for i in range(len(self.points)):
            if i >0:
                pygame.draw.line(screen, self.color, self.points[i-1], self.points[i], 2)
        pygame.draw.circle(screen, (200, 200,200), (int(self.current[0]), int(self.current[1])), 5)
        self.current = [0,0]

that's gonna be all that we gonna need in the curve file.

Now the next step gonna be to make a new file "main.py" which gonna be the root file.

First we gonna import all the libraries that we gonna need including pygame obviously.

and we gonna make some configuration of pygame , it's screen size, ...

import pygame
import math
from Curve import Curve
import colorsys
import numpy as np


width, height = 1920, 1080
size = (width, height )
h = 0
def hsv_to_rgb(h, s, v):
    return tuple(round(i * 255) for i in colorsys.hsv_to_rgb(h, s, v))

pygame.init()
pygame.display.set_caption("Lissajous Curves")
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()
fps = 60

let Initialize some variables that we gonna need to make our visualization , and loop trough the curves to give each curve a color:

white, black, gray = (245, 245, 245), (15, 15, 15), (150, 150, 150)
angle = 0
w = 140
restart= False

columns = width//w-1
rows = height// w-1
speed = 0.01

radius = int((w//2) - 0.1*w)
curves = [[i for i in range(columns)] for j in range(rows)]



for x in range(rows):
    for y in range(columns):
        curves[x][y] = Curve(hsv_to_rgb(h, 1, 1))
        h+= 0.001

At last let make the main loop of our programme , where every thing happens , the animations of points using the polar and cartesian coordinates formular and yeah basically all we need.

run = True
while run:
    clock.tick(fps)
    screen.fill(black)
    
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                run = False
            if event.key == pygame.K_r:
                restart = True

      
    for i in range(columns):
        a = w+10 + i * w + w//2
        b = w//2 + 15
        pygame.draw.circle(screen, white, (a, b), int(radius), 1)

        x = radius * math.cos(angle*(i+1) - math.pi/2)
        y = radius * math.sin(angle*(i+1) - math.pi/2)
        pygame.draw.line(screen, gray, (int(a+x), 0), (int(a+x), height), 1)
        pygame.draw.circle(screen, white, (int(a+x), int(b+y)), 8)
        for j in range(rows):
            curves[j][i].set_point_x(a+x)

    for j in range(rows):
        a = w//2 + 15
        b = w+10 + j * w + w//2
        pygame.draw.circle(screen, white, (a, b), radius, 1)

        x = radius * math.cos(angle*(j+1) - math.pi/2)
        y = radius * math.sin(angle*(j+1) - math.pi/2)
        pygame.draw.line(screen, gray, (0, int(b+y)), (width, int(b+y)), 1)
        pygame.draw.circle(screen, white, (int(a+x), int(b+y)), 8)
        for i in range(columns):
            curves[j][i].set_point_y(b+y)
    
    
    for x in range(rows):
        for y in range(columns):
            curves[x][y].update_points()
            curves[x][y].draw(screen)

    angle-= speed
    if angle < - 2 * math.pi or restart == True:
        for x in range(rows):
            for y in range(columns):
                curves[x][y].points = []
        angle = 0
        restart = False

    pygame.display.update()
#pygame.image.save(screen, "screenshot.jpg")
pygame.quit()

with that you can run the simulation and get something that looks like this

lissajouse-image-simulation

Github Repository: Lissajous-curve-table

Check out my Youtube Channel: Auctux

complete main.py file

import pygame
import math
from Curve import Curve
import colorsys
import numpy as np


width, height = 1920, 1080
size = (width, height )
h = 0
def hsv_to_rgb(h, s, v):
    return tuple(round(i * 255) for i in colorsys.hsv_to_rgb(h, s, v))

pygame.init()
pygame.display.set_caption("Lissajous Curves")
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()
fps = 60

white, black, gray = (245, 245, 245), (15, 15, 15), (150, 150, 150)
angle = 0
w = 140
restart= False

columns = width//w-1
rows = height// w-1
speed = 0.01

radius = int((w//2) - 0.1*w)
curves = [[i for i in range(columns)] for j in range(rows)]



for x in range(rows):
    for y in range(columns):
        curves[x][y] = Curve(hsv_to_rgb(h, 1, 1))
        h+= 0.001
run = True
while run:
    clock.tick(fps)
    screen.fill(black)
    
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                run = False
            if event.key == pygame.K_r:
                restart = True

      
    for i in range(columns):
        a = w+10 + i * w + w//2
        b = w//2 + 15
        pygame.draw.circle(screen, white, (a, b), int(radius), 1)

        x = radius * math.cos(angle*(i+1) - math.pi/2)
        y = radius * math.sin(angle*(i+1) - math.pi/2)
        pygame.draw.line(screen, gray, (int(a+x), 0), (int(a+x), height), 1)
        pygame.draw.circle(screen, white, (int(a+x), int(b+y)), 8)
        for j in range(rows):
            curves[j][i].set_point_x(a+x)

    for j in range(rows):
        a = w//2 + 15
        b = w+10 + j * w + w//2
        pygame.draw.circle(screen, white, (a, b), radius, 1)

        x = radius * math.cos(angle*(j+1) - math.pi/2)
        y = radius * math.sin(angle*(j+1) - math.pi/2)
        pygame.draw.line(screen, gray, (0, int(b+y)), (width, int(b+y)), 1)
        pygame.draw.circle(screen, white, (int(a+x), int(b+y)), 8)
        for i in range(columns):
            curves[j][i].set_point_y(b+y)
    
    
    for x in range(rows):
        for y in range(columns):
            curves[x][y].update_points()
            curves[x][y].draw(screen)

    angle-= speed
    if angle < - 2 * math.pi or restart == True:
        for x in range(rows):
            for y in range(columns):
                curves[x][y].points = []
        angle = 0
        restart = False

    pygame.display.update()
#pygame.image.save(screen, "screenshot.jpg")
pygame.quit()

Thank you ✌️