Basic Poincare Disk Renderer
This commit is contained in:
127
main.py
127
main.py
@@ -3,82 +3,129 @@ from kingdon import Algebra
|
||||
import math
|
||||
|
||||
ERROR = 0.00001
|
||||
DISK_RADIUS = 250
|
||||
WIDTH, HEIGHT = 800, 600
|
||||
CENTER_X, CENTER_Y = 400, 300
|
||||
|
||||
alg = Algebra(2,1,0)
|
||||
locals().update(alg.blades)
|
||||
b = 2*e12
|
||||
print(b)
|
||||
|
||||
def motor(generator):
|
||||
bivector = generator.grade(2)
|
||||
sqr = (bivector*bivector).grade(0).e
|
||||
mag = bivector.norm().e
|
||||
generator = bivector.normalized()
|
||||
if mag < ERROR:
|
||||
#Zero Norm
|
||||
return 1+bivector
|
||||
elif sqr < 0:
|
||||
return math.cos(mag) + math.sin(mag)*generator
|
||||
def point(x,y):
|
||||
#Construct a point.
|
||||
#Hyperbolic space is modeled as a hyperboloid embedded in 3D Minkowski space.
|
||||
#Find w such that x,y,w is a point on the hyperboloid.
|
||||
w_sqr = x*x + y*y + 1
|
||||
w = math.sqrt(w_sqr)
|
||||
return x*e23 -y*e13 + w*e12
|
||||
|
||||
def draw_point(point):
|
||||
#Normalize the point
|
||||
x_0 = point.e12
|
||||
x_1 = -point.e23
|
||||
x_2 = point.e13
|
||||
norm = math.sqrt(x_0*x_0 - x_1*x_1 - x_2*x_2)
|
||||
x_0 = x_0/norm
|
||||
x_1 = x_1/norm
|
||||
x_2 = x_2/norm
|
||||
#Transform it into the Poincare Space
|
||||
u = x_1/(1+x_0)
|
||||
v = x_2/(1+x_0)
|
||||
|
||||
pygame.draw.circle(screen, RED, (int(u*DISK_RADIUS+CENTER_X), int(v*DISK_RADIUS+CENTER_Y)), 5)
|
||||
|
||||
def draw_line(line):
|
||||
delta = line.e3
|
||||
if abs(delta) < ERROR:
|
||||
# The geodesic is a line through the origin.
|
||||
if abs(line.e2) < ERROR:
|
||||
pygame.draw.line(screen, BLUE, (CENTER_X, CENTER_Y+DISK_RADIUS), (CENTER_X, CENTER_Y-DISK_RADIUS), 1)
|
||||
else:
|
||||
return math.cosh(mag) + math.sinh(mag)*generator
|
||||
|
||||
motor(1*e12)
|
||||
motor(1*e13)
|
||||
motor(1*e23)
|
||||
slope = line.e1/line.e2
|
||||
pygame.draw.line(screen, BLUE, (CENTER_X-DISK_RADIUS, int(CENTER_Y-slope*DISK_RADIUS)), (CENTER_X+DISK_RADIUS, int(CENTER_Y+slope*DISK_RADIUS)), 1)
|
||||
else:
|
||||
#The geodesic is a circle
|
||||
a = line.e1
|
||||
b = line.e2
|
||||
sqr = a*a + b*b
|
||||
norm = math.sqrt(sqr)
|
||||
x_c = a/delta
|
||||
y_c = b/delta
|
||||
r = math.sqrt(x_c*x_c+y_c*y_c - 1)
|
||||
c_x = int(CENTER_X + x_c*DISK_RADIUS)
|
||||
c_y = int(CENTER_Y + y_c*DISK_RADIUS)
|
||||
pygame.draw.circle(screen, BLUE, (c_x, c_y), int(r*DISK_RADIUS), 1)
|
||||
|
||||
|
||||
|
||||
|
||||
y_axis = e1 #x = 0 line
|
||||
x_axis = e2 #y = 0 line
|
||||
|
||||
tx_generator = e13 #A translation in the x direction
|
||||
ty_generator = e23 #A translation in the y direction
|
||||
origin = e12 #The origin, and a rotation about the origin
|
||||
|
||||
|
||||
|
||||
'''
|
||||
# Initialize Pygame
|
||||
pygame.init()
|
||||
|
||||
# Set up the screen
|
||||
WIDTH, HEIGHT = 800, 600
|
||||
screen = pygame.display.set_mode((WIDTH, HEIGHT))
|
||||
pygame.display.set_caption("Clifford and Pygame Example")
|
||||
pygame.display.set_caption("Pygame Example")
|
||||
|
||||
# Colors
|
||||
BLACK = (0, 0, 0)
|
||||
WHITE = (255, 255, 255)
|
||||
RED = (255, 0, 0)
|
||||
BLUE = (0, 0, 255)
|
||||
|
||||
# Initial point in GA (e.g., a vector representing a point)
|
||||
# We'll represent it as a multivector with a vector component
|
||||
initial_point_ga = 100 * e1 + 50 * e2
|
||||
|
||||
# Create a rotor for rotation (e.g., 45 degrees counter-clockwise)
|
||||
angle = math.pi / 4 # 45 degrees
|
||||
rotor = math.e**(angle * e12)
|
||||
|
||||
# Game loop
|
||||
running = True
|
||||
t = 0
|
||||
|
||||
while running:
|
||||
t += 0.0002
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
running = False
|
||||
|
||||
# Clear the screen
|
||||
screen.fill(BLACK)
|
||||
screen.fill(WHITE)
|
||||
|
||||
# Apply the rotation to the point
|
||||
rotated_point_ga = rotor * initial_point_ga * ~rotor
|
||||
#Poincare Disk Boundary
|
||||
pygame.draw.circle(screen, BLACK, (CENTER_X, CENTER_Y), DISK_RADIUS, 1)
|
||||
|
||||
# Extract the vector components for Pygame display
|
||||
# We assume the point is a vector, so we access its e1 and e2 components
|
||||
x_coord = rotated_point_ga.value[e1.index] + WIDTH // 2 # Adjust for screen center
|
||||
y_coord = -rotated_point_ga.value[e2.index] + HEIGHT // 2 # Invert y for Pygame coordinates
|
||||
#Generate a transformation for demonstration
|
||||
transform = math.sin(t)*tx_generator + math.sin(math.sqrt(2)*t)*ty_generator + math.sin(math.sqrt(3)*t)*origin
|
||||
transform = transform
|
||||
motor = transform.exp()
|
||||
|
||||
# Draw the point
|
||||
pygame.draw.circle(screen, RED, (int(x_coord), int(y_coord)), 5)
|
||||
#Apply the transformation
|
||||
y_tick = motor*y_axis*motor.reverse()
|
||||
x_tick = motor*x_axis*motor.reverse()
|
||||
|
||||
#Construct a point as the intersection of the two lines
|
||||
point = y_tick^x_tick
|
||||
|
||||
#Draw everything
|
||||
draw_line(y_tick)
|
||||
draw_line(x_tick)
|
||||
draw_point(point)
|
||||
|
||||
tx = tx_generator.exp()
|
||||
ty = ty_generator.exp()
|
||||
point_a = tx*ty*origin*ty.reverse()*tx.reverse()
|
||||
point_b = ty*tx*origin*tx.reverse()*ty.reverse()
|
||||
draw_line(x_axis)
|
||||
draw_line(y_axis)
|
||||
draw_point(origin)
|
||||
draw_point(point_a)
|
||||
draw_point(point_b)
|
||||
|
||||
# Update the display
|
||||
pygame.display.flip()
|
||||
|
||||
|
||||
|
||||
# Quit Pygame
|
||||
pygame.quit()
|
||||
'''
|
||||
|
||||
|
||||
Reference in New Issue
Block a user