import pygame
from math import sin, cos
from random import randint

SCREEN_WIDTH, SCREEN_HEIGHT = 650, 650
FPS = 850
BACKGROUND = [ 0 ] * 3

# --- Core ---------------------------------------------------------

class FuncDrawer:
	def __init__(self, x_func, y_func, t_begin, t_end, t_step=0.1, tail=100):
		self._x_func = x_func
		self._y_func = y_func
		self._t_begin = t_begin
		self._t_end = t_end
		self._t_step = t_step
		self._tail = tail

		self._points = [ ]
		self._current_t = self._t_begin

		self._prepare()

	def _prepare(self):
		x_max, y_max = x_min, y_min = self._calc(self._t_begin)

		t = self._t_begin + self._t_step
		while t <= self._t_end:
			curr_x, curr_y = self._calc(t)

			if curr_x < x_min:
				x_min = curr_x
			if curr_x > x_max:
				x_max = curr_x
			if curr_y < y_min:
				y_min = curr_y
			if curr_y > y_max:
				y_max = curr_y

			t += self._t_step

		self._x_min = x_min
		self._y_min = y_min
		self._x_max = x_max
		self._y_max = y_max

	def _calc(self, t):
		return self._x_func(t), self._y_func(t)

	def _draw(self, screen, t, color, size):
		width, height = screen.get_size()

		x_zoom = width / (self._x_max - self._x_min)
		y_zoom = height / (self._y_max - self._y_min)

		zoom = min(x_zoom, y_zoom)

		x = int((self._x_func(t) - self._x_min) * zoom)
		y = int((self._y_func(t) - self._y_min) * zoom)

		pygame.draw.circle(screen, color, (x, y), size)

		return [ x, y ]

	def draw_next(self, screen, color, size):
		self._points.append(self._draw(screen, self._current_t, color, size))

		if len(self._points) > self._tail:
			pygame.draw.circle(animation_screen, BACKGROUND, self._points[0], size)
			del self._points[0]

		self._current_t += self._t_step

def get_rand_color():
	return ( randint(1, 255), randint(1, 255), randint(1, 255) )

def sign(t):
	return 1 if t > 0 else (-1 if t < 0 else 0)

# --- Main program -------------------------------------------------

def f1(t):
	return 8*cos(t/10 + 1)*cos(0.5*t - 15)

def f2(t):
	return 8*cos(1.1*t + 1)*cos(t / 2)*sin(t/100 + 15)

pygame.init()

animation_screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
animation_screen.set_alpha(255)

size = 2
t_step = 0.01
t_begin = 0
t_end   = 1e4

# fd3 = FuncDrawer(lambda t: sin(t) ** 1, lambda t: cos(t) ** 1, 0, 3.15 * 2, 750)
fd1 = FuncDrawer(f1, f2, t_begin, t_end, t_step, 850)
fd2 = FuncDrawer(f2, f1, t_begin, t_end, t_step, 850)
fd3 = FuncDrawer(lambda t: abs(cos(t)) ** 0.5 * sign(cos(t)), lambda t: abs(sin(t)) ** 0.5 * sign(sin(t)), 0, 7, t_step / 4, 630)


points = [ ]
t = t_begin
done = False
while not done:
	for event in pygame.event.get():
			if event.type == pygame.QUIT:
				done = True

	fd1.draw_next(animation_screen, (255, 0, 0), size)
	fd2.draw_next(animation_screen, (0, 255, 0), size)
	fd3.draw_next(animation_screen, (0, 0, 255), size)

	pygame.display.flip()
	pygame.time.wait(1000 // FPS)

pygame.quit()