12:38 PM, November-03-2022
#Python #computer graphic #Math
Hello Everyone, Welcome to this Blog about Lissajous curve table
A 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
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 ✌️