Skip to content

Instantly share code, notes, and snippets.

@neizod
Last active August 4, 2022 13:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save neizod/a93d624a9b5439c2378723ee84b06184 to your computer and use it in GitHub Desktop.
Save neizod/a93d624a9b5439c2378723ee84b06184 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
size = (1000,1000)
polygon = [ (612,661), (668,661), (668,612), (752,757), (668,757), (668,950),
(312,334), (284,383), (326,407), (159,407), (201,334), ( 33,238),
(745,238), (717,189), (675,213), (759, 68), (801,141), (968, 44), ]
guards = polygon[4::6]
s = lambda v: int((4/5) * v)
size = [s(v) for v in size]
polygon = [(s(x),s(y)) for x, y in polygon]
guards = [(s(x),s(y)) for x, y in guards]
# ============================================================================
from operator import mul
from functools import reduce
from collections import namedtuple
from PIL import Image
from PIL.ImageDraw import Draw, floodfill
prod = lambda ls: reduce(mul, ls)
Matrix = namedtuple('Matrix', 'm') # dimension 3x3 only.
Matrix.from_points = lambda u, v, w: Matrix([ [u.x, v.x, w.x],
[u.y, v.y, w.y],
[ 1, 1, 1] ])
Matrix.diag_down = lambda self: ((self.m[j][(i+j)%3] for j in range(3))
for i in range(3))
Matrix.diag_up = lambda self: ((self.m[j][(i+3-j)%3] for j in range(3))
for i in range(3))
Matrix.det = lambda self: ( sum(prod(d) for d in self.diag_down())
- sum(prod(d) for d in self.diag_up()) )
Point = namedtuple('Point', 'x y')
Segment = namedtuple('Segment', 'p q')
Segment.from_floats = lambda x0, y0, x1, y1: Segment(Point(x0, y0), Point(x1, y1))
Segment.ccw = lambda self, p: Matrix.from_points(p, *self).det() > 0
Segment.through = lambda self, other: self.ccw(other.p) ^ self.ccw(other.q)
Segment.intersect = lambda self, other: self.through(other) and other.through(self)
def pairwise(ls, loop=True):
if not loop:
return zip(ls, ls[1:])
return zip(ls, ls[1:]+ls[:1])
def is_visible(point, guard):
line_of_sight = Segment(Point(*point), Point(*guard))
for edge in pairwise(polygon):
if guard in edge:
continue
obstracle = Segment(*[Point(*xy) for xy in edge])
if line_of_sight.intersect(obstracle):
return False
return True
def get_color(x, y):
return tuple([0,255][is_visible((x, y), guard)] for guard in guards)
# ============================================================================
image = Image.new('RGB', size)
pixels = image.load()
drawer = Draw(image)
for edge in pairwise(polygon):
drawer.line(edge, fill=(255,255,255))
floodfill(image, (0,0), (255,255,255))
for x in range(size[0]):
for y in range(size[1]):
if pixels[x,y] == (255,255,255):
continue
pixels[x,y] = get_color(x, y)
for edge in pairwise(polygon, loop=True):
drawer.line(edge, fill=(0,0,0))
r = 3
for (x, y), co in zip(guards, [(255,0,0), (0,255,0), (0,0,255)]):
drawer.ellipse((x-r,y-r,x+r,y+r), fill=co, outline='black')
image.save(open('visgon.png', 'wb'))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment