microwerx icon

Ray-Circle Intersection

microwerx | PRO | 07/31/21 09:30:54 PM UTC | 0 ⭐ | 1648 👁️ | Never ⏰ | []
Python |

4.14 KB

|

None

|

0 👍

/

0 👎

import math
import pygame
import random
 
from pygame import draw
import time
 
pygame.init()
size = width, height = 1280, 720
screen = pygame.display.set_mode(size)
 
done = False
keys_pressed = dict.fromkeys(range(256))
 
sprite_x = 0
sprite_y = 0
 
def dot(A, B):
    return A[0]*B[0] + A[1]*B[1]
 
def hit_sphere(center, radius, r_origin, r_direction):
    oc = r_origin[0] - center[0], r_origin[1] - center[1]
    a = dot(r_direction, r_direction)
    b = 2.0 * dot(oc, r_direction)
    c = dot(oc, oc) - radius*radius
    discriminant = b*b - 4.0*a*c
    if discriminant < 0:
        return -1
 
    # apply the quadratic formula to calculate the roots
    t1 = (-b + math.sqrt(discriminant)) / (2*a)
    t2 = (-b - math.sqrt(discriminant)) / (2*a)
    if t1 < t2:
        return t1
    else:
        return t2
 
def draw_line(screen, color, start_pos, end_pos):
    pygame.draw.line(screen, color, start_pos, end_pos)
 
def draw_circle(screen, color, start_pos, end_pos):
    # pygame.draw.line(screen, color, start_pos, end_pos)
 
    width = abs(end_pos[0] - start_pos[0])
    height = abs(end_pos[1] - start_pos[1])
 
    rx = width / 2
    ry = height / 2
 
    x1 = start_pos[0] + rx
    y1 = start_pos[1] + ry
 
    theta = 0
    num_segments = 128
    dtheta = 2 * 3.141592653 / (num_segments + 1)
    x = x1 + rx * math.cos(theta)
    y = y1 + ry * math.sin(theta)
    for i in range(num_segments):
        last_x = x
        last_y = y
        theta += dtheta
        x = x1 + rx * math.cos(theta)
        y = y1 + ry * math.sin(theta)
        p0 = (last_x, last_y)
        p1 = (x, y)
        pygame.draw.line(screen, color, p0, p1)
 
 
# screen.fill((0, 0, 0))
# pygame.display.update()
# time.sleep(1)
# screen.fill((0, 0, 192))
# pygame.display.update()
# time.sleep(1)
# screen.fill((0, 192, 192))
# pygame.display.update()
# time.sleep(1)
# screen.fill((192, 192, 192))
# pygame.display.update()
# time.sleep(1)
 
draw_count = 0
theta = 0
frame_count = 0
 
time0 = pygame.time.get_ticks() / 1000.0
while not done:
    time1 = pygame.time.get_ticks() / 1000.0
    time_elapsed = time1 - time0
 
    for event in pygame.event.get():
        if event.type == pygame.constants.WINDOWCLOSE:
            done = True
        if event.type == pygame.constants.KEYDOWN:
            keys_pressed[event.key] = True
        if event.type == pygame.constants.KEYUP:
            keys_pressed[event.key] = False
 
    # check for ESCAPE key
    if keys_pressed[pygame.constants.K_ESCAPE]:
        done = True
 
    # handle user input for left/right
    dx = 0
    if keys_pressed[pygame.constants.K_a]:
        dx -= 1
    if keys_pressed[pygame.constants.K_d]:
        dx += 1
    sprite_x += dx
 
    dy = 0
    if keys_pressed[pygame.constants.K_w]:
        dy -= 1
    if keys_pressed[pygame.constants.K_s]:
        dy += 1
    sprite_y += dy
 
    screen.fill((25, 25, 25))
 
    # Calculate the location of the sphere
    C = Cx, Cy = width/3, height/3
    R = width/6
 
    # Calculate the origin and direction of the ray
    A = Ax, Ay = 0.75 * width, 0.75 * height
    B = Bx, By = math.cos(time1/5), math.sin(time1/5)
 
    t = 1000 # * (time1 - int(time1))
    # Point on a ray (or point at parameter t): P(t) = A + t*B
    start_pos = (Ax, Ay)
    end_pos = (Ax + t * Bx, Ay + t * By)
    color = (0, 0, 255)
    draw_line(screen, color, start_pos, end_pos)
 
    # Calculate intersection (if any)
    t = hit_sphere(C, R, A, B)
    if t < 0:
        color = (255, 0, 0)
    else:
        color = (0, 128, 0)
 
    start_pos = (Cx - R, Cy - R)
    end_pos   = (Cx + R, Cy + R)
    draw_circle(screen, color, start_pos, end_pos)
 
    # draw the intersection point
 
    if t >= 0:
        Px = Ax + t * Bx
        Py = Ay + t * By
        start_pos = (Ax, Ay)
        end_pos   = (Px, Py)
        color     = (255, 0, 255)
        draw_line(screen, color, start_pos, end_pos)
        start_pos = (Px-10, Py-10)
        end_pos   = (Px+10, Py+10)
        draw_circle(screen, color, start_pos, end_pos)
 
    pygame.display.update()
 
    theta += time_elapsed / 180
    frame_count += 1
 

Comments