diff --git a/content/Triangulation.org b/content/Triangulation.org index 7148aa2..1b57909 100644 --- a/content/Triangulation.org +++ b/content/Triangulation.org @@ -1,57 +1,7 @@ #+TEST: [[file:Geometry][Geometry]] -* Quadtree -Recursively subdivide an AABB into 4 regions, hence Quad. They are usually -denoted as North West, North East, South West, and South East (NW, NE, SW, SE). -Several things can be created with this; -** Linked Implementation :datastructure: -** Array Implementation :datastructure: -** Insertion :algorithm: -** Query :algorithm: -** Find Nearest Neighbor :algorithm: +* Triangulation +Generate triangles from points +** Convex Hull Jarvis March (Gift wrapping) :algorithm: ** Resources -[[http://ericandrewlewis.github.io/how-a-quadtree-works/][Visualize a Quadtree]] -[[http://donar.umiacs.umd.edu/quadtree/][Academic Interactive Demo]] ** Notes -// exclude node if point is farther away than best distance in either axis -if (x < x1 - best.d || x > x2 + best.d || y < y1 - best.d || y > y2 + best.d) { - return best; -} - - -I don't know how to explain but I get it. Because of the euclidian distance and the fact that we're dealing with rectangles, the closest distance to a rectangle is a straight line in one of the x or y axis -So if the point we're checking is farther away from the rectangle on either axis, then it cannot possible be the case that it is closer -I still can't visualize or understand it intuitively, I more just trust that it works, maybe if I see it in action it'll click better -JosephFerano - — -Today at 4:15 PM -This is some clever math shit this guy is doing -Or that he picked up -https://gist.github.com/patricksurry/6478178 -Gist -D3JS quadtree nearest neighbor algorithm -D3JS quadtree nearest neighbor algorithm. GitHub Gist: instantly share code, notes, and snippets. -D3JS quadtree nearest neighbor algorithm - - // check if kid is on the right or left, and top or bottom - // and then recurse on most likely kids first, so we quickly find a - // nearby point and then exclude many larger rectangles later - var kids = node.nodes; - var rl = (2*x > x1 + x2), bt = (2*y > y1 + y2); - if (kids[bt*2+rl]) best = nearest(x, y, best, kids[bt*2+rl]); - if (kids[bt*2+(1-rl)]) best = nearest(x, y, best, kids[bt*2+(1-rl)]); - if (kids[(1-bt)*2+rl]) best = nearest(x, y, best, kids[(1-bt)*2+rl]); - if (kids[(1-bt)*2+(1-rl)]) best = nearest(x, y, best, kids[(1-bt)*2+(1-rl)]); - -That's kinda neat, estimating probability with some math and then going into the index of the array where the point is more likely to be -No idea why this works -But I think I'm done with this -Interesting, he doesn't even check if any of the rects contain the point -Hmmm -Oh I see -It's because he's tracking whether a node is visited or not, and I'm putting in a lot of work to make sure you don't revisit the same node twice, but I don't do it with a "visited" bool, which I intentionally avoided but now seeing his solution, I realize it may have been a mistake -JosephFerano - — -Today at 4:27 PM -Actually I don't think adding "visited" is a good idea, because you have to walk through the whole thing again once you're done to uncheck all the visited bools. That's a linear walk through all the nodes, which might not be much, but it's certainly making things slower -I'll have to investigate further diff --git a/triangulation.py b/triangulation.py index 2d5b03f..5d7bd60 100644 --- a/triangulation.py +++ b/triangulation.py @@ -3,13 +3,25 @@ from pyray import (Rectangle as Rect, Vector2 as Vec2, Vector3 as Vec3, Camera3D import math import pdb import random +from ctypes import Structure, c_float from typing import Optional, Tuple, List from dataclasses import dataclass, field -screen_width = 1280 -screen_height = 1024 +def dump(struct): + s = f"{RL.ffi.typeof(struct)}: (".replace('', '') + for field in dir(struct): + data = struct.__getattribute__(field) + if str(data).startswith(" World: cam = Camera3D(Vec3(0, 10, 10), Vec3(0, 0, 0), Vec3(0, 1, 0), 45, RL.CAMERA_PERSPECTIVE) @@ -29,24 +43,73 @@ def player_input(w: World): if RL.is_key_pressed(RL.KEY_SPACE): w.rotate_cam = not w.rotate_cam if RL.is_mouse_button_pressed(0): - mouse_pos = RL.get_mouse_position() - ray = RL.get_mouse_ray(mouse_pos, w.cam) + ray = RL.get_mouse_ray(RL.get_mouse_position(), w.cam) + # First try to collide with existing points + for v in w.vertices: + collision = RL.get_ray_collision_sphere(ray, v, vertex_radius) + if collision.hit: + w.dragging_vert = v + found_collision = True + return + + w.dragging_vert = None collision = RL.get_ray_collision_box(ray, w.floor_bb) if collision.hit: p = collision.point w.vertices.append(Vec3(p.x, 0, p.z)) + if RL.is_mouse_button_down(0): + if w.dragging_vert is not None: + ray = RL.get_mouse_ray(RL.get_mouse_position(), w.cam) + collision = RL.get_ray_collision_box(ray, w.floor_bb) + if collision.hit: + w.dragging_vert.x = collision.point.x + w.dragging_vert.z = collision.point.z + if RL.is_mouse_button_released(0): + print('no') + w.dragging_vert = None def update(w: World): - pass + if len(w.vertices) <= 2: + return + w.convex_hull_points.clear() + pending = sorted(w.vertices, key=lambda v: v.x) + w.convex_hull_points.append(pending[0]) + idx = 0 + # TODO: + while True: + v1 = w.convex_hull_points[-1] + left_most = pending[(idx + 1) % len(pending)] + idx += 1 + if v1 == left_most: + continue + for v2 in pending: + x1 = v1.x - left_most.x + x2 = v1.x - v2.x + y1 = v1.z - left_most.z + y2 = v1.z - v2.z + sign = y2*x1 - y1*x2 + if v1 == v2: + continue + if sign > 0: + left_most = v2 + if left_most == w.convex_hull_points[0]: + break + w.convex_hull_points.append(left_most) + def draw_3d(w: World): RL.draw_grid(grid_slices, grid_spacing) RL.draw_bounding_box(w.floor_bb, RL.GREEN) for vert in w.vertices: - RL.draw_sphere(vert, 0.1, RL.GREEN) + RL.draw_sphere(vert, vertex_radius, RL.GREEN) + if len(w.convex_hull_points) > 2: + for i,p in enumerate(w.convex_hull_points[:-1]): + RL.draw_line_3d(p, w.convex_hull_points[i+1], RL.GREEN) + RL.draw_line_3d(w.convex_hull_points[-1], w.convex_hull_points[0], RL.GREEN) + # exit(0) def draw_2d(w: World): - pass + RL.draw_fps(10, 10) RL.init_window(screen_width, screen_height, "Starter"); RL.set_target_fps(60)