From d9337616db6fef505eeb405f65d0a0510338db60 Mon Sep 17 00:00:00 2001 From: queue-miscreant Date: Sat, 8 Mar 2025 23:23:27 -0600 Subject: [PATCH] add image rendering script --- posts/pentagons/1/triangles.py | 389 +++++++++++++++++++++++++++++++++ 1 file changed, 389 insertions(+) create mode 100644 posts/pentagons/1/triangles.py diff --git a/posts/pentagons/1/triangles.py b/posts/pentagons/1/triangles.py new file mode 100644 index 0000000..78cbbbc --- /dev/null +++ b/posts/pentagons/1/triangles.py @@ -0,0 +1,389 @@ +import numpy as np +import matplotlib.pyplot as plt + +root3 = 0.5 - (3**0.5) / 2j +triangle_coords = lambda i: (i[0] + i[1] * root3.real, i[1] * root3.imag) + + +def hex_positions(n): + coordinates = [ + (i, j) for i in range(n) for j in range(n) if i + j < n and (i - j) % 3 + ] + drawing = [(i + j * root3.real, j * root3.imag) for (i, j) in coordinates] + return list(zip(*drawing)) + + +def hex_lines(n): + # vertices of hexagons in rightmost third of the the upper half plane + coordinates = [ + (i, j) for i in range(n) for j in range(n) if i + j < n and (i - j) % 3 + ] + # find connections between a vertex and its (up to 3) neighbors + lines = [ + filter( + lambda x: x[1] in coordinates, + [[(i, j), (i + 1, j)], [(i, j), (i, j + 1)], [(i, j), (i + 1, j - 1)]], + ) + for (i, j) in coordinates + ] + for line in lines: + for unfiltered in line: + plt.plot(*list(zip(*map(triangle_coords, unfiltered))), "ko-") + # flat_drawing = [map(triangle_coords, unzip) for line in lines for unzip in line] + # return list(zip(*flat_drawing)) + # for i in flat_drawing: + # plt.plot(*list(zip(*i)), "k") + + +def triangular_grid(n, show_hexes=False): + coordinates = [(i, j) for i in range(n) for j in range(n) if i + j < n] + drawing = [(i + j * root3.real, j * root3.imag) for (i, j) in coordinates] + # plt.plot(*list(zip(*drawing)), "o") + plt.triplot(*list(zip(*drawing)), "-", color="0.7", lw=0.75) + if show_hexes: + # plt.plot(*hex_positions(n), "ok") + hex_lines(n) + plt.gca().axis("off") + plt.xlim((-2, (1920 / 1080) * plt.ylim()[1])) + + +""" +def color_at_hex_coordinates(coord): + draw = None + if min(coord) == 0: #class 1 + #(0,1) = (1,0) => (2,1), (1,2), (2, 2) + #(0,2) = (2,0) => (3,2), (2,3), (3, 3) + big = max(coord) + draw = [(big, big+1), (big+1, big), (big+1, big+1)] + #plt.fill([big, big+1, big+1], [big, big, big+1],"r") + elif (coord[0] == coord[1]): #class 2 + #(1,1) => (2,0) |+| (1,1) + #(2,2) => (3,1) |+| (1,1) + #(n,n) => (n+1,n-1) |+| (1,1) + big = coord[0] + draw = [(big+1, big-1), (big+1, big), (big+2, big-1)] + #plt.fill([big+1, big+2, big+1], [big-1, big-1, big],"r") + else: + #choose one enantiomer + #(2,1) => [(3, 1), (3, 2), (4, 1)] + #(3,1) => [(4, 2), (3, 2), (4, 1)] + #(a,b) => [(a+1, b), (a+1, b+1), (a+2, b)] + a,b = coord + draw = [(a+1, b), (a+1, b+1), (a+2, b)] + + plt.fill(*list(zip(*map(triangle_coords, draw))), "r") +""" + + +def identify_triangles(coord, offset=0, point=True, fill_all=False, path=False): + # (a,b) specifies coordinates to the center of a hexagon + # (a,a) is the first hexagon for turning + # (2b, -b) is the length of the path after the 60 degree turn, meaning + # (a+2b, a-b) is the center of the hexagon + a, b = coord + if a != b and min(coord) > 0 and offset == 0: + offset = a - b + # origin + plt.fill( + *list( + zip( + *map( + triangle_coords, + [(offset, offset), (offset + 1, offset), (offset, offset + 1)], + ) + ) + ), + "r", + ) + + # control point + if point: + plt.plot(*triangle_coords((a + offset, b + offset)), "bo") + + c, d = (a - offset + 2 * (b + offset), a - b + offset) + if min(coord) == 0: + # upside-down triangle + triangle = [(c, d), (c - 1, d), (c, d - 1)] + # terminal + plt.fill(*list(zip(*map(triangle_coords, triangle))), "b") + + if fill_all: + plt.fill( + *list( + zip( + *map( + triangle_coords, + [ + (offset, offset), + (offset + a, offset), + (offset, offset + a), + ], + ) + ) + ), + "r", + ) + plt.fill( + *list( + zip( + *map( + triangle_coords, + [ + (offset, offset + a), + (offset + a, offset), + (offset + a, offset + a), + ], + ) + ) + ), + "b", + ) + else: + triangle = [(c, d), (c - 1, d), (c - 1, d + 1)] + # terminal + plt.fill(*list(zip(*map(triangle_coords, triangle))), "b") + # alternate terminal + c, d = (b - a + offset, b - offset + 2 * (a + offset)) + triangle2 = [(c, d), (c, d - 1), (c + 1, d - 1)] + plt.fill(*list(zip(*map(triangle_coords, triangle2))), "g") + + # lines connecting triangles + plt.plot( + *list( + zip( + *map( + triangle_coords, + [ + (offset + 1, offset), + triangle[1], + triangle[2], + triangle2[2], + triangle2[1], + (offset, offset + 1), + (offset + 1, offset), + ], + ) + ) + ), + color="0.25", + lw=2, + ) + + if fill_all and a == b: + # trapezoids + plt.fill( + *list( + zip( + *map( + triangle_coords, + [ + (offset, offset), + (offset, offset + a), + (offset + a, offset + a), + (offset + 2 * a, offset), + ], + ) + ) + ), + "r", + ) + plt.fill( + *list( + zip( + *map( + triangle_coords, + [ + (offset, offset + a), + (offset + a, offset + a), + (offset + a, offset + 2 * a), + (offset, offset + 3 * a), + ], + ) + ) + ), + "g", + ) + plt.fill( + *list( + zip( + *map( + triangle_coords, + [ + (offset + a, offset + a), + (offset + a, offset + 2 * a), + (offset + 3 * a, offset), + (offset + 2 * a, offset), + ], + ) + ) + ), + "b", + ) + + elif fill_all == 1: + plt.fill( + *list( + zip( + *map( + triangle_coords, + [ + (offset + 1, offset), + triangle[1], + triangle[2], + triangle2[2], + triangle2[1], + (offset, offset + 1), + (offset + 1, offset), + ], + ) + ) + ), + color="0.4", + ) + + elif fill_all == 2: + # dark gray interior + plt.fill( + *list( + zip( + *map( + triangle_coords, + [ + (offset + 1, offset), + triangle[1], + triangle[2], + triangle2[2], + triangle2[1], + (offset, offset + 1), + (offset + 1, offset), + ], + ) + ) + ), + color="0.4", + ) + + # lower parallelogram + plt.fill( + *list( + zip( + *map( + triangle_coords, + [ + (offset + 1, offset), + (offset + 1, offset + offset), + triangle[1], + (lambda x, y: (x, y - offset))(*triangle[1]), + (offset + 1, offset), + ], + ) + ) + ), + color="xkcd:light red", + ) + + # upper right parallelogram + plt.fill( + *list( + zip( + *map( + triangle_coords, + [ + triangle[2], + (lambda x, y: (x - offset, y))(*triangle[2]), + triangle2[2], + (lambda x, y: (x + offset, y))(*triangle2[2]), + triangle[2], + ], + ) + ) + ), + color="xkcd:light blue", + ) + + # upper left parallelogram + plt.fill( + *list( + zip( + *map( + triangle_coords, + [ + triangle2[1], + (lambda x, y: (x + offset, y - offset))(*triangle2[1]), + (offset, offset + 1), + (0, offset + 1 + offset), + triangle2[1], + ], + ) + ) + ), + color="xkcd:light green", + ) + + # center triangle + plt.fill( + *list( + zip( + *map( + triangle_coords, + [ + (offset, offset + offset), + (lambda x, y: (x - offset + 1, y - 1))(*triangle[2]), + (lambda x, y: (x + offset, y - offset + 1))( + *triangle2[1] + ), + (offset, offset + offset), + ], + ) + ) + ), + color="0.8", + ) + + if path: + plt.plot( + *list( + zip( + *map( + lambda x: triangle_coords((offset + x, offset + x)), + range(a + 1), + ) + ) + ), + marker="o", + color="xkcd:light red", + mfc="k", + lw=3, + ) + plt.text( + *triangle_coords((offset + a / 2 - 1, offset + a / 2 + 1.5)), + f"a = {a}", + bbox={"facecolor": "xkcd:light red", "pad": 6}, + ) + + plt.plot( + *list( + zip( + *map( + lambda x: triangle_coords((offset + a + 2 * x, offset + a - x)), + range(b + 1), + ) + ) + ), + marker="o", + color="xkcd:light blue", + mfc="k", + lw=3, + ) + plt.text( + *triangle_coords((offset + a + b, offset + a - b / 2 + 0.75)), + f"b = {b}", + bbox={"facecolor": "xkcd:light blue", "pad": 6}, + ) + + +if __name__ == "__main__": + triangular_grid(24, True) + # identify_triangles((4,2), point=False, path=True) + identify_triangles((4, 2), offset=5, point=False, path=True) + plt.show()