Created
December 6, 2025 17:40
-
-
Save FoamyGuy/aa97201f18161e718f0d12159a914541 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import math | |
| import bitmaptools | |
| import displayio | |
| import supervisor | |
| import time | |
| from adafruit_usb_host_mouse import find_and_init_boot_mouse | |
| def split_points(_points): | |
| _xs = [] | |
| _ys = [] | |
| for point in _points: | |
| _xs.append(point[0]) | |
| _ys.append(point[1]) | |
| return bytes(_xs), bytes(_ys) | |
| def distance(point_a, point_b): | |
| x1, y1 = point_a | |
| x2, y2 = point_b | |
| return math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2) | |
| def point_in_polygon(point, polygon): | |
| """ | |
| Determine if a point is inside a polygon using ray casting algorithm. | |
| Args: | |
| point: tuple (x, y) representing the point to test | |
| polygon: list of tuples [(x1, y1), (x2, y2), ...] representing polygon vertices | |
| Returns: | |
| bool: True if point is inside polygon, False otherwise | |
| """ | |
| x, y = point | |
| n = len(polygon) | |
| inside = False | |
| # Iterate through each edge of the polygon | |
| p1x, p1y = polygon[0] | |
| for i in range(1, n + 1): | |
| p2x, p2y = polygon[i % n] | |
| # Check if point is within the y-bounds of this edge | |
| if y > min(p1y, p2y): | |
| if y <= max(p1y, p2y): | |
| if x <= max(p1x, p2x): | |
| # Calculate x-intersection of the ray with the edge | |
| if p1y != p2y: | |
| x_intersection = (y - p1y) * (p2x - p1x) / (p2y - p1y) + p1x | |
| # If edge is vertical or point is to the left of intersection, toggle | |
| if p1x == p2x or x <= x_intersection: | |
| inside = not inside | |
| p1x, p1y = p2x, p2y | |
| return inside | |
| def find_point_in_polygon(polygon): | |
| # a_vertex = polygon[0] | |
| # | |
| # for _x in range(-3, 4): | |
| # for _y in range(-3, 4): | |
| # checking_point = (a_vertex[0] + _x, a_vertex[1] + _y) | |
| # if point_in_polygon(checking_point, polygon): | |
| # if snowflake_bmp[checking_point] == 1: | |
| # return checking_point | |
| if len(polygon) == 3: | |
| x1, y1 = polygon[0] | |
| x2, y2 = polygon[1] | |
| x3, y3 = polygon[2] | |
| centroid_x = (x1 + x2 + x3) // 3 | |
| centroid_y = (y1 + y2 + y3) // 3 | |
| return (centroid_x, centroid_y) | |
| for i in range(len(polygon)): | |
| point = polygon[i] | |
| for j in range(len(polygon)): | |
| checking_point = polygon[j] | |
| if i != j and j != i + 1 and j != i - 1: | |
| x1, y1 = point | |
| x2, y2 = checking_point | |
| midway = ((x1 + x2) // 2, (y1 + y2) // 2) | |
| if point_in_polygon(midway, polygon): | |
| if snowflake_bmp[midway] == 1: | |
| print(midway) | |
| return midway | |
| return None | |
| CLICK_COOLDOWN = 0.5 | |
| last_click_time = -1 | |
| display = supervisor.runtime.display | |
| main_group = displayio.Group() | |
| display.root_group = main_group | |
| palette = displayio.Palette(3) | |
| palette[0] = 0x000066 | |
| palette[1] = 0xffffff | |
| palette[2] = 0xff0000 | |
| snowflake_bmp = displayio.Bitmap(120, 120, 3) | |
| snowflake_bmp.fill(1) | |
| top_left_tg = displayio.TileGrid(snowflake_bmp, pixel_shader=palette) | |
| main_group.append(top_left_tg) | |
| # points = [(0, 0), (40, 0), (0, 40)] | |
| # xs, ys = split_points(points) | |
| # bitmaptools.draw_polygon(snowflake_bmp, xs, ys, 0) | |
| # bitmaptools.boundary_fill(snowflake_bmp, 1,1, 0, 1) | |
| top_right_tg = displayio.TileGrid(snowflake_bmp, pixel_shader=palette) | |
| top_right_tg.flip_x = True | |
| top_right_tg.x = top_left_tg.x + top_left_tg.tile_width | |
| main_group.append(top_right_tg) | |
| bottom_left_tg = displayio.TileGrid(snowflake_bmp, pixel_shader=palette) | |
| bottom_left_tg.flip_y = True | |
| bottom_left_tg.y = top_left_tg.y + top_left_tg.tile_height | |
| main_group.append(bottom_left_tg) | |
| bottom_right_tg = displayio.TileGrid(snowflake_bmp, pixel_shader=palette) | |
| bottom_right_tg.flip_x = True | |
| bottom_right_tg.flip_y = True | |
| bottom_right_tg.x = top_left_tg.x + top_left_tg.tile_width | |
| bottom_right_tg.y = top_left_tg.y + top_left_tg.tile_height | |
| main_group.append(bottom_right_tg) | |
| mouse = find_and_init_boot_mouse() | |
| if mouse is None: | |
| raise RuntimeError("No mouse found connected to USB Host") | |
| # add the mouse tile grid to the main group | |
| main_group.append(mouse.tilegrid) | |
| clicked_points = [] | |
| # display.auto_refresh = False | |
| while True: | |
| # update mouse | |
| pressed_btns = mouse.update() | |
| mouse.x = min(mouse.x, top_left_tg.x + top_left_tg.tile_width - 1) | |
| mouse.y = min(mouse.y, top_left_tg.y + top_left_tg.tile_height - 1) | |
| now = time.monotonic() | |
| if pressed_btns: | |
| if "left" in pressed_btns and now >= last_click_time + CLICK_COOLDOWN: | |
| # print(pressed_btns) | |
| last_click_time = now | |
| cur_clicked_point = ((mouse.x, mouse.y)) | |
| if len(clicked_points) == 0: | |
| clicked_points.append(cur_clicked_point) | |
| snowflake_bmp[cur_clicked_point] = 0 | |
| display.refresh() | |
| continue | |
| if distance(cur_clicked_point, clicked_points[0]) < 10: | |
| # points = [(0, 0), (40, 0), (0, 40)] | |
| xs, ys = split_points(clicked_points) | |
| bitmaptools.draw_polygon(snowflake_bmp, xs, ys, 0) | |
| inner_point = find_point_in_polygon(clicked_points) | |
| print(f"polygon: ", clicked_points) | |
| bitmaptools.boundary_fill(snowflake_bmp, inner_point[0], inner_point[1], 0, 1) | |
| snowflake_bmp[inner_point] = 2 | |
| clicked_points.clear() | |
| display.refresh() | |
| else: | |
| clicked_points.append(cur_clicked_point) | |
| snowflake_bmp[cur_clicked_point] = 0 | |
| display.refresh() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment