From e7974701036fa168c0f585f5bce1400fca583850 Mon Sep 17 00:00:00 2001 From: Lily Iliana Luna Ylva Anderson Appleseed Grigaitis Date: Sat, 16 Aug 2025 01:03:47 -0500 Subject: [PATCH] Basic Poincare Disk Renderer --- main.py | 127 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 87 insertions(+), 40 deletions(-) diff --git a/main.py b/main.py index efbe1ce..29d8a0e 100644 --- a/main.py +++ b/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: + 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: - return math.cosh(mag) + math.sinh(mag)*generator - -motor(1*e12) -motor(1*e13) -motor(1*e23) + #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() -''' -