Initial commit

This commit is contained in:
Matt Low 2020-11-13 18:46:31 +04:00
commit 699acd1602
11 changed files with 453 additions and 0 deletions

138
.gitignore vendored Normal file
View File

@ -0,0 +1,138 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/

24
geom.py Executable file
View File

@ -0,0 +1,24 @@
#!/usr/bin/env python
import geom
import pygame
import sys
def main():
pygame.init()
geom.init()
clock = pygame.time.Clock()
elapsed = 0
while geom.loop():
clock.tick(60)
#elapsed += clock.get_time()
#if elapsed >= 1000:
# print(f"FPS: {clock.get_fps()}")
# elapsed = 0
pygame.quit()
sys.exit()
if __name__ == "__main__":
main()

34
geom/__init__.py Normal file
View File

@ -0,0 +1,34 @@
import pygame
from pygame.locals import *
from . import text
WIDTH = 1280
HEIGHT = 720
surface = None
screen = None
def init():
pygame.display.set_caption("Geom Demo")
pygame.mouse.set_visible(False)
global surface
global screen
surface = pygame.display.set_mode((WIDTH, HEIGHT))
text.init()
from .screen import Screen
screen = Screen()
def loop():
for event in pygame.event.get(QUIT):
return False
surface.fill((0, 0, 0))
screen.render(surface)
pygame.display.update()
return True

9
geom/colors.py Normal file
View File

@ -0,0 +1,9 @@
RED = (255, 0, 0, 255)
YELLOW = (255, 255, 0, 255)
GREEN = (0, 255, 0, 255)
CYAN = (0, 255, 255, 255)
BLUE = (0, 0, 255, 255)
VIOLET = (255, 0, 255, 255)
WHITE = (255, 255, 255, 255)
BLACK = (0, 0, 0, 255)

85
geom/demos/aabb.py Normal file
View File

@ -0,0 +1,85 @@
from pygame import draw, mouse
from .. import text
from ..geom.rect import Rect
from .. import WIDTH, HEIGHT, text
from ..colors import *
from ..math import *
class AABBDistance:
title = "AABB Distance"
def render(self, surface):
rect_a = Rect(
WIDTH / 2 - (WIDTH / 8),
HEIGHT / 2 - (HEIGHT / 8),
WIDTH / 4,
HEIGHT / 4,
)
rect_b = Rect(
*mouse.get_pos(),
WIDTH / 5,
HEIGHT / 5
)
# cx, cy = center
dist_x = abs(rect_b.cx - rect_a.cx)
dist_y = abs(rect_b.cy - rect_a.cy)
gap_x = dist_x - rect_a.halfwidth - rect_b.halfwidth
gap_y = dist_y - rect_a.halfheight - rect_b.halfheight
distance = 0
if gap_x < 0 and gap_y < 0:
distance = max(gap_x, gap_y)
else:
if gap_x < 0:
distance = gap_y
elif gap_y < 0:
distance = gap_x
else:
distance = length(gap_x, gap_y)
text.draw(surface, (10, HEIGHT - 20), WHITE, f"Distance: {distance}")
rect_a.draw(surface, YELLOW, 4)
rect_b.draw(surface, WHITE, 4)
draw.line(surface, RED if distance < 0 else GREEN,
rect_a.get_center(), rect_b.get_center(), 2)
class PointAABBDistance:
title = "Point-AABB Distance"
def render(self, surface):
rect_a = Rect(
WIDTH / 2 - (WIDTH / 8),
HEIGHT / 2 - (HEIGHT / 8),
WIDTH / 4,
HEIGHT / 4,
)
cx, cy = mouse.get_pos()
# cx, cy = point
dist_x = abs(cx - rect_a.cx)
dist_y = abs(cy - rect_a.cy)
gap_x = dist_x - rect_a.halfwidth
gap_y = dist_y - rect_a.halfheight
distance = 0
if gap_x < 0 and gap_y < 0:
distance = max(gap_x, gap_y)
else:
if gap_x < 0:
distance = gap_y
elif gap_y < 0:
distance = gap_x
else:
distance = length(gap_x, gap_y)
text.draw(surface, (10, HEIGHT - 20), WHITE, f"Distance: {distance}")
rect_a.draw(surface, YELLOW, 4)
draw.line(surface, RED if distance < 0 else GREEN,
rect_a.get_center(), (cx, cy), 2)

29
geom/demos/vec_proj.py Normal file
View File

@ -0,0 +1,29 @@
from pygame import draw, mouse
from .. import HEIGHT, WIDTH
from ..colors import *
from ..math import *
class VecProj:
title = "Vector Projection"
def render(self, surface):
x1 = WIDTH / 4
y1 = HEIGHT / 2 + 100
x2 = 0.75 * WIDTH
y2 = HEIGHT / 2
cx, cy = mouse.get_pos()
lx, ly = x2 - x1, y2 - y1 # line vector
llen = length(lx, ly)
lnx, lny = lx / llen, ly / llen # line normal
lcx, lcy = cx - x1, cy - y1 # line start - cursor vector
proj = dot(lcx, lcy, lx, ly) / llen
draw.line(
surface, GREEN, (cx, cy), add(x1, y1, *scale(lnx, lny, proj)), 5
)
draw.line(surface, WHITE, (cx, cy), (x1, y1), 5)
draw.line(surface, YELLOW, (x1, y1), (x2, y2), 5)

55
geom/geom/rect.py Normal file
View File

@ -0,0 +1,55 @@
from pygame import draw, gfxdraw
from pygame.rect import Rect as pRect
class Rect:
def __init__(self, x, y, width, height):
self.x = x
self.y = y
self.height = height
self.width = width
self.update()
def update(self):
self.min_x = self.x
self.min_y = self.y
self.max_x = self.x + self.width
self.max_y = self.y + self.height
self.min = (self.min_x, self.min_y)
self.max = (self.max_x, self.max_y)
self.halfwidth = self.width / 2
self.halfheight = self.height / 2
self.cx = self.x + self.width / 2
self.cy = self.y + self.height / 2
self.vertices = [
(self.x, self.y),
(self.x + self.width, self.y),
(self.x + self.width, self.y + self.height),
(self.x, self.y + self.height)
]
self.segments = [
(self.vertices[0], self.vertices[1]),
(self.vertices[1], self.vertices[2]),
(self.vertices[2], self.vertices[3]),
(self.vertices[3], self.vertices[0]),
]
def get_center(self):
return (self.cx, self.cy)
def get_center_px(self):
return (int(self.cx), int(self.cy))
def contains(self, x, y):
return (x >= self.min_x and x <= self.max_x
and y >= self.min_y and y <= self.max_y)
def draw(self, surface, colour, width):
#gfxdraw.pixel(surface, *self.get_center_px(), colour)
draw.rect(surface, colour,
pRect(self.x, self.y, self.width, self.height),
width)

28
geom/math.py Normal file
View File

@ -0,0 +1,28 @@
import math
ZERO = (0, 0)
def dot(x1, y1, x2, y2):
return (x1 * x2) + (y1 * y2)
def length(x, y):
return math.sqrt((x * x) + (y * y))
def normalize(x, y):
_len = length(x, y)
return x / _len, y / _len
def scale(x, y, factor):
return x * factor, y * factor
def add(x1, y1, x2, y2):
return x1 + x2, y1 + y2
def sub(x1, y1, x2, y2):
return x1 - x2, y1 - y2
def vmin(x1, y1, x2, y2):
return min(x1, x2), min(y1, y2)
def vmax(x1, y1, x2, y2):
return max(x1, x2), max(y1, y2)

40
geom/screen.py Normal file
View File

@ -0,0 +1,40 @@
import pygame
from .demos import aabb, vec_proj
from . import text, HEIGHT
from .colors import *
class Screen:
def __init__(self):
self.demos = [
vec_proj.VecProj(),
aabb.AABBDistance(),
aabb.PointAABBDistance(),
]
self.demo = 0
def handle_input(self):
for event in pygame.event.get(pygame.KEYDOWN):
if event.key == pygame.K_DOWN:
self.demo += 1
if self.demo >= len(self.demos):
self.demo = 0
elif event.key == pygame.K_UP:
self.demo -= 1
if self.demo < 0:
self.demo = len(self.demos) - 1
def draw_demo_list(self, surface):
y_offset = 10
for i in range(len(self.demos)):
text.draw(surface,
(10, y_offset + i * 20),
CYAN if self.demo == i else WHITE,
self.demos[i].title)
def render(self, surface):
self.handle_input()
self.demos[self.demo].render(surface)
self.draw_demo_list(surface)

10
geom/text.py Normal file
View File

@ -0,0 +1,10 @@
from pygame import freetype
FONT = None
def init():
global FONT
FONT = freetype.SysFont('Arial', 16)
def draw(surface, position, color, text):
FONT.render_to(surface, position, text, color)

1
requirements.txt Normal file
View File

@ -0,0 +1 @@
pygame==2.0.0