Skip to content

Instantly share code, notes, and snippets.

@bradmartin333
Last active May 12, 2023 18:39
Show Gist options
  • Save bradmartin333/714f7b87e5bc3254cb02689b71729ea1 to your computer and use it in GitHub Desktop.
Save bradmartin333/714f7b87e5bc3254cb02689b71729ea1 to your computer and use it in GitHub Desktop.
Keystone correction using y = mx + b
from pyray import *
import csv
# Constants
start_wid = 800
start_hgt = 600
debug = True
def lerp(v1: Vector2, v2: Vector2, ratio: float):
if v2.x == v1.x:
return Vector2(v1.x, v1.y + (v2.y - v1.y) * ratio)
m = (v2.y - v1.y) / (v2.x - v1.x)
b = v1.y - m * v1.x
delta = (v2.x - v1.x) * ratio
x = delta + v1.x
y = m * x + b
return Vector2(x, y)
def intersection_of_lines(p1: Vector2, p2: Vector2, p3: Vector2, p4: Vector2):
if p2.x == p1.x:
return Vector2(p1.x, p3.y + (p4.y - p3.y) * (p1.x - p3.x) / (p4.x - p3.x))
m1 = (p2.y - p1.y) / (p2.x - p1.x)
b1 = p1.y - m1 * p1.x
if p4.x == p3.x:
return Vector2(p3.x, p1.y + (p2.y - p1.y) * (p3.x - p1.x) / (p2.x - p1.x))
m2 = (p4.y - p3.y) / (p4.x - p3.x)
b2 = p3.y - m2 * p3.x
x = (b2 - b1) / (m1 - m2)
y = m1 * x + b1
return Vector2(x, y)
def shrink_poly(ps: list[Vector2], shrink_factor: float):
'''Shrink a polygon by shrink_factor pixels in all directions'''
return [
Vector2(ps[0].x + shrink_factor, ps[0].y + shrink_factor),
Vector2(ps[1].x - shrink_factor, ps[1].y + shrink_factor),
Vector2(ps[2].x - shrink_factor, ps[2].y - shrink_factor),
Vector2(ps[3].x + shrink_factor, ps[3].y - shrink_factor)
]
class Rect:
nw_frac = Vector2()
se_frac = Vector2()
p1 = Vector2()
p2 = Vector2()
p3 = Vector2()
p4 = Vector2()
color = BLACK
thickness = 3.0
def draw(self):
ps = shrink_poly([self.p1, self.p2, self.p3, self.p4], self.thickness)
draw_line_ex(ps[0], ps[1], self.thickness, self.color)
draw_line_ex(ps[1], ps[2], self.thickness, self.color)
draw_line_ex(ps[2], ps[3], self.thickness, self.color)
draw_line_ex(ps[3], ps[0], self.thickness, self.color)
# Create the window
print("Creating Window")
set_trace_log_level(8) # DEBUG
set_config_flags(ConfigFlags.FLAG_WINDOW_UNDECORATED)
set_config_flags(ConfigFlags.FLAG_MSAA_4X_HINT)
init_window(800, 600, 'Carmine')
# Setup monitor
set_window_monitor(0)
wid = get_screen_width(0)
hgt = get_screen_height(0)
set_window_size(wid, hgt)
hide_cursor()
# https://en.wikipedia.org/wiki/Keystone_effect
keystone_points = [Vector2(wid/2 - start_wid/2, hgt/2 - start_hgt/2),
Vector2(wid/2 + start_wid/2, hgt/2 - start_hgt/2),
Vector2(wid/2 - start_wid/2, hgt/2 + start_hgt/2),
Vector2(wid/2 + start_wid/2, hgt/2 + start_hgt/2)]
# Read the data from rects.csv
rects = []
with open('rects.csv', newline='') as csvfile:
reader = csv.reader(csvfile, delimiter=',')
next(reader) # Skip the header
for row in reader:
r = Rect()
r.nw_frac = Vector2(float(row[0]), float(row[1]))
r.se_frac = Vector2(float(row[2]), float(row[3]))
r.color = color_from_normalized(
Vector4(float(row[4]), float(row[5]), float(row[6]), float(row[7])))
r.thickness = float(row[8])
rects.append(r)
# Main loop
while not window_should_close():
begin_drawing()
clear_background(WHITE)
cursor_pos = get_mouse_position()
# Get the quadrant of the screen the cursor is in
quadrant = 0
if cursor_pos.x > wid/2:
quadrant += 1
if cursor_pos.y > hgt/2:
quadrant += 2
# User adjust keystone point
if is_mouse_button_pressed(MouseButton.MOUSE_BUTTON_LEFT):
keystone_points[quadrant] = cursor_pos
if is_key_pressed(KeyboardKey.KEY_LEFT):
keystone_points[quadrant].x -= 1
if is_key_pressed(KeyboardKey.KEY_RIGHT):
keystone_points[quadrant].x += 1
if is_key_pressed(KeyboardKey.KEY_UP):
keystone_points[quadrant].y -= 1
if is_key_pressed(KeyboardKey.KEY_DOWN):
keystone_points[quadrant].y += 1
if debug:
# Draw the quadrants
draw_rectangle_v(Vector2(0, 0), Vector2(wid/2, hgt/2),
fade(BLACK, 0.1 if quadrant == 0 else 0))
draw_rectangle_v(Vector2(wid/2, 0), Vector2(wid/2, hgt/2),
fade(BLACK, 0.1 if quadrant == 1 else 0))
draw_rectangle_v(Vector2(0, hgt/2), Vector2(wid/2, hgt/2),
fade(BLACK, 0.1 if quadrant == 2 else 0))
draw_rectangle_v(Vector2(wid/2, hgt/2), Vector2(wid/2, hgt/2),
fade(BLACK, 0.1 if quadrant == 3 else 0))
# Draw lines between the points
for i in range(4):
for j in range(4):
if i != j:
draw_line_ex(keystone_points[i],
keystone_points[j], 1, BLACK)
# Draw the cursor
draw_circle_v(cursor_pos, 20, BLACK)
draw_line_ex(Vector2(cursor_pos.x, cursor_pos.y - 20),
Vector2(cursor_pos.x, cursor_pos.y + 20), 3, WHITE)
draw_line_ex(Vector2(cursor_pos.x - 20, cursor_pos.y),
Vector2(cursor_pos.x + 20, cursor_pos.y), 3, WHITE)
# Draw the rects
for r in rects:
t1 = lerp(keystone_points[0], keystone_points[1], r.nw_frac.x)
t2 = lerp(keystone_points[0], keystone_points[1], r.se_frac.x)
b1 = lerp(keystone_points[2], keystone_points[3], r.nw_frac.x)
b2 = lerp(keystone_points[2], keystone_points[3], r.se_frac.x)
l1 = lerp(keystone_points[0], keystone_points[2], r.nw_frac.y)
l2 = lerp(keystone_points[0], keystone_points[2], r.se_frac.y)
r1 = lerp(keystone_points[1], keystone_points[3], r.nw_frac.y)
r2 = lerp(keystone_points[1], keystone_points[3], r.se_frac.y)
r.p1 = intersection_of_lines(t1, b1, l1, r1)
r.p2 = intersection_of_lines(t2, b2, l1, r1)
r.p3 = intersection_of_lines(t2, b2, l2, r2)
r.p4 = intersection_of_lines(t1, b1, l2, r2)
r.draw()
end_drawing()
close_window()
rx1 ry1 rx2 ry2 r g b a t
0.0 0.0 0.2 0.2 0.0 0.0 0.0 1.0 1.0
0.2 0.0 0.4 0.2 0.0 1.0 0.0 1.0 5.0
0.4 0.0 0.6 0.2 0.0 0.0 1.0 1.0 5.0
0.6 0.0 0.8 0.2 1.0 0.0 0.0 1.0 5.0
0.8 0.0 1.0 0.2 0.0 1.0 0.0 1.0 5.0
0.0 0.2 0.2 0.4 0.0 0.0 1.0 1.0 5.0
0.2 0.2 0.4 0.4 0.0 0.0 0.0 1.0 1.0
0.4 0.2 0.6 0.4 0.0 1.0 0.0 1.0 5.0
0.6 0.2 0.8 0.4 0.0 0.0 1.0 1.0 5.0
0.8 0.2 1.0 0.4 1.0 0.0 0.0 1.0 5.0
0.0 0.4 0.2 0.6 0.0 1.0 0.0 1.0 5.0
0.2 0.4 0.4 0.6 0.0 0.0 1.0 1.0 5.0
0.4 0.4 0.6 0.6 0.0 0.0 0.0 1.0 1.0
0.6 0.4 0.8 0.6 0.0 1.0 0.0 1.0 5.0
0.8 0.4 1.0 0.6 0.0 0.0 1.0 1.0 5.0
0.0 0.6 0.2 0.8 1.0 0.0 0.0 1.0 5.0
0.2 0.6 0.4 0.8 0.0 1.0 0.0 1.0 5.0
0.4 0.6 0.6 0.8 0.0 0.0 1.0 1.0 5.0
0.6 0.6 0.8 0.8 0.0 0.0 0.0 1.0 1.0
0.8 0.6 1.0 0.8 0.0 1.0 0.0 1.0 5.0
0.0 0.8 0.2 1.0 0.0 0.0 1.0 1.0 5.0
0.2 0.8 0.4 1.0 1.0 0.0 0.0 1.0 5.0
0.4 0.8 0.6 1.0 0.0 1.0 0.0 1.0 5.0
0.6 0.8 0.8 1.0 0.0 0.0 1.0 1.0 5.0
0.8 0.8 1.0 1.0 0.0 0.0 0.0 1.0 1.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment