Triangulation: Find the convex hull Jarvis March (Gift wrapping)
This commit is contained in:
parent
9d66afaaca
commit
8df43af3e6
@ -1,57 +1,7 @@
|
|||||||
#+TEST: [[file:Geometry][Geometry]]
|
#+TEST: [[file:Geometry][Geometry]]
|
||||||
|
|
||||||
* Quadtree
|
* Triangulation
|
||||||
Recursively subdivide an AABB into 4 regions, hence Quad. They are usually
|
Generate triangles from points
|
||||||
denoted as North West, North East, South West, and South East (NW, NE, SW, SE).
|
** Convex Hull Jarvis March (Gift wrapping) :algorithm:
|
||||||
Several things can be created with this;
|
|
||||||
** Linked Implementation :datastructure:
|
|
||||||
** Array Implementation :datastructure:
|
|
||||||
** Insertion :algorithm:
|
|
||||||
** Query :algorithm:
|
|
||||||
** Find Nearest Neighbor :algorithm:
|
|
||||||
** Resources
|
** Resources
|
||||||
[[http://ericandrewlewis.github.io/how-a-quadtree-works/][Visualize a Quadtree]]
|
|
||||||
[[http://donar.umiacs.umd.edu/quadtree/][Academic Interactive Demo]]
|
|
||||||
** Notes
|
** 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
|
|
||||||
|
@ -3,13 +3,25 @@ from pyray import (Rectangle as Rect, Vector2 as Vec2, Vector3 as Vec3, Camera3D
|
|||||||
import math
|
import math
|
||||||
import pdb
|
import pdb
|
||||||
import random
|
import random
|
||||||
|
from ctypes import Structure, c_float
|
||||||
from typing import Optional, Tuple, List
|
from typing import Optional, Tuple, List
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
screen_width = 1280
|
def dump(struct):
|
||||||
screen_height = 1024
|
s = f"{RL.ffi.typeof(struct)}: (".replace('<ctype ', '').replace('>', '')
|
||||||
|
for field in dir(struct):
|
||||||
|
data = struct.__getattribute__(field)
|
||||||
|
if str(data).startswith("<cdata"):
|
||||||
|
data = dump(data)
|
||||||
|
s += f"{field}:{data} "
|
||||||
|
s += ")"
|
||||||
|
return s
|
||||||
|
|
||||||
|
screen_width = 1024
|
||||||
|
screen_height = 768
|
||||||
grid_slices = 100
|
grid_slices = 100
|
||||||
grid_spacing = 0.2
|
grid_spacing = 0.2
|
||||||
|
vertex_radius = 0.12
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class World:
|
class World:
|
||||||
@ -18,6 +30,8 @@ class World:
|
|||||||
rotate_cam: bool = True
|
rotate_cam: bool = True
|
||||||
frame_count: int = 0
|
frame_count: int = 0
|
||||||
vertices: List[Vec3] = field(default_factory=list)
|
vertices: List[Vec3] = field(default_factory=list)
|
||||||
|
dragging_vert: Vec3 = None
|
||||||
|
convex_hull_points: List[Vec3] = field(default_factory=list)
|
||||||
|
|
||||||
def init() -> World:
|
def init() -> World:
|
||||||
cam = Camera3D(Vec3(0, 10, 10), Vec3(0, 0, 0), Vec3(0, 1, 0), 45, RL.CAMERA_PERSPECTIVE)
|
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):
|
if RL.is_key_pressed(RL.KEY_SPACE):
|
||||||
w.rotate_cam = not w.rotate_cam
|
w.rotate_cam = not w.rotate_cam
|
||||||
if RL.is_mouse_button_pressed(0):
|
if RL.is_mouse_button_pressed(0):
|
||||||
mouse_pos = RL.get_mouse_position()
|
ray = RL.get_mouse_ray(RL.get_mouse_position(), w.cam)
|
||||||
ray = RL.get_mouse_ray(mouse_pos, 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)
|
collision = RL.get_ray_collision_box(ray, w.floor_bb)
|
||||||
if collision.hit:
|
if collision.hit:
|
||||||
p = collision.point
|
p = collision.point
|
||||||
w.vertices.append(Vec3(p.x, 0, p.z))
|
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):
|
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):
|
def draw_3d(w: World):
|
||||||
RL.draw_grid(grid_slices, grid_spacing)
|
RL.draw_grid(grid_slices, grid_spacing)
|
||||||
RL.draw_bounding_box(w.floor_bb, RL.GREEN)
|
RL.draw_bounding_box(w.floor_bb, RL.GREEN)
|
||||||
for vert in w.vertices:
|
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):
|
def draw_2d(w: World):
|
||||||
pass
|
RL.draw_fps(10, 10)
|
||||||
|
|
||||||
RL.init_window(screen_width, screen_height, "Starter");
|
RL.init_window(screen_width, screen_height, "Starter");
|
||||||
RL.set_target_fps(60)
|
RL.set_target_fps(60)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user