Triangulate a convex hull
This commit is contained in:
parent
8df43af3e6
commit
8fe7b273a5
@ -12,6 +12,8 @@ Several things can be created with this;
|
|||||||
** Resources
|
** Resources
|
||||||
[[http://ericandrewlewis.github.io/how-a-quadtree-works/][Visualize a Quadtree]]
|
[[http://ericandrewlewis.github.io/how-a-quadtree-works/][Visualize a Quadtree]]
|
||||||
[[http://donar.umiacs.umd.edu/quadtree/][Academic Interactive Demo]]
|
[[http://donar.umiacs.umd.edu/quadtree/][Academic Interactive Demo]]
|
||||||
|
[[https://codepen.io/_bm/pen/ExPBMrW][Codepen (Js example)]]
|
||||||
|
[[https://gist.github.com/patricksurry/6478178][D3.js Example]]
|
||||||
** Notes
|
** Notes
|
||||||
// exclude node if point is farther away than best distance in either axis
|
// 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) {
|
if (x < x1 - best.d || x > x2 + best.d || y < y1 - best.d || y > y2 + best.d) {
|
||||||
|
@ -3,5 +3,10 @@
|
|||||||
* Triangulation
|
* Triangulation
|
||||||
Generate triangles from points
|
Generate triangles from points
|
||||||
** Convex Hull Jarvis March (Gift wrapping) :algorithm:
|
** Convex Hull Jarvis March (Gift wrapping) :algorithm:
|
||||||
|
[[file:~/Development/gaming-pads/convexhull-jarvismarch.py][Python Code]]
|
||||||
** Resources
|
** Resources
|
||||||
|
https://www.youtube.com/watch?v=Vu84lmMzP2o
|
||||||
|
https://www.habrador.com/tutorials/math/8-convex-hull/
|
||||||
|
https://www.youtube.com/watch?v=B2AJoQSZf4M
|
||||||
|
https://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf
|
||||||
** Notes
|
** Notes
|
||||||
|
@ -65,7 +65,6 @@ def player_input(w: World):
|
|||||||
w.dragging_vert.x = collision.point.x
|
w.dragging_vert.x = collision.point.x
|
||||||
w.dragging_vert.z = collision.point.z
|
w.dragging_vert.z = collision.point.z
|
||||||
if RL.is_mouse_button_released(0):
|
if RL.is_mouse_button_released(0):
|
||||||
print('no')
|
|
||||||
w.dragging_vert = None
|
w.dragging_vert = None
|
||||||
|
|
||||||
def update(w: World):
|
def update(w: World):
|
23
starter.py
23
starter.py
@ -1,13 +1,23 @@
|
|||||||
import pyray as RL
|
import pyray as RL
|
||||||
from pyray import (Rectangle as Rect, Vector2 as Vec2, Vector3 as Vec3, Camera3D)
|
from pyray import (Rectangle as Rect, Vector2 as Vec2, Vector3 as Vec3, Camera3D, BoundingBox)
|
||||||
import math
|
import math
|
||||||
import pdb
|
import pdb
|
||||||
import random
|
import random
|
||||||
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
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class World:
|
class World:
|
||||||
@ -15,7 +25,8 @@ class World:
|
|||||||
frame_count: int = 0
|
frame_count: int = 0
|
||||||
|
|
||||||
def init() -> World:
|
def init() -> World:
|
||||||
pass
|
cam = Camera3D(Vec3(0, 10, 10), Vec3(0, 0, 0), Vec3(0, 1, 0), 45, RL.CAMERA_PERSPECTIVE)
|
||||||
|
return World(cam)
|
||||||
|
|
||||||
def player_input(w: World):
|
def player_input(w: World):
|
||||||
pass
|
pass
|
||||||
@ -32,9 +43,7 @@ def draw_2d(w: World):
|
|||||||
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)
|
||||||
|
|
||||||
init()
|
w = init()
|
||||||
cam = Camera3D(Vec3(0, 0, 10), RL.vector3_zero(), Vec3(0, 1, 0), 60, 1)
|
|
||||||
w = World(cam)
|
|
||||||
while not RL.window_should_close():
|
while not RL.window_should_close():
|
||||||
player_input(w)
|
player_input(w)
|
||||||
update(w)
|
update(w)
|
||||||
|
172
triangulation-earclipping.py
Normal file
172
triangulation-earclipping.py
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
import pyray as RL
|
||||||
|
from pyray import (
|
||||||
|
ffi,
|
||||||
|
Rectangle as Rect,
|
||||||
|
Vector2 as Vec2,
|
||||||
|
Vector3 as Vec3,
|
||||||
|
Camera3D,
|
||||||
|
BoundingBox,
|
||||||
|
Mesh,
|
||||||
|
Model
|
||||||
|
)
|
||||||
|
import math
|
||||||
|
import pdb
|
||||||
|
import random
|
||||||
|
from typing import Optional, Tuple, List
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
|
def dump(struct):
|
||||||
|
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_spacing = 0.2
|
||||||
|
vertex_radius = 0.12
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class World:
|
||||||
|
cam: Camera3D
|
||||||
|
floor_bb: BoundingBox
|
||||||
|
rotate_cam: bool = True
|
||||||
|
draw_wireframe: bool = RL.ffi.new('bool *', False)
|
||||||
|
frame_count: int = 0
|
||||||
|
vertices: List[Vec3] = field(default_factory=list)
|
||||||
|
dragging_vert: Vec3 = None
|
||||||
|
convex_hull_points: List[Vec3] = field(default_factory=list)
|
||||||
|
mesh: Mesh = None
|
||||||
|
model: Model = None
|
||||||
|
|
||||||
|
def get_convex_hull(vertices: List[Vec3]):
|
||||||
|
convex_hull_points = []
|
||||||
|
pending = sorted(vertices, key=lambda v: v.x)
|
||||||
|
convex_hull_points.append(pending[0])
|
||||||
|
idx = 0
|
||||||
|
while True:
|
||||||
|
v1 = 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 == convex_hull_points[0]:
|
||||||
|
break
|
||||||
|
convex_hull_points.append(left_most)
|
||||||
|
return convex_hull_points
|
||||||
|
|
||||||
|
def init() -> World:
|
||||||
|
cam = Camera3D(Vec3(0, 10, 10), Vec3(0, 0, 0), Vec3(0, 1, 0), 45, RL.CAMERA_PERSPECTIVE)
|
||||||
|
half_grid = grid_slices * grid_spacing * 0.5
|
||||||
|
floor_bb = BoundingBox(Vec3(-half_grid, -0.01, -half_grid), Vec3(half_grid, 0.01, half_grid))
|
||||||
|
w = World(cam, floor_bb)
|
||||||
|
num_starting_verts = 10
|
||||||
|
radius = 4
|
||||||
|
w.vertices = [
|
||||||
|
Vec3(math.cos(math.pi * 2 / num_starting_verts * i) * radius,
|
||||||
|
0,
|
||||||
|
math.sin(math.pi * 2 / num_starting_verts * i) * radius)
|
||||||
|
for i in range(num_starting_verts)
|
||||||
|
]
|
||||||
|
|
||||||
|
vs = get_convex_hull(w.vertices)
|
||||||
|
def get_points(v: Vec3):
|
||||||
|
return v.x, v.y, v.z
|
||||||
|
vertices = ffi.new("float[]", len(vs) * 3 * 3)
|
||||||
|
# for i,v in enumerate([0,0,0 1,0,2, 2,0,0, 1,0,2, 3,0,2, 2,0,0]):
|
||||||
|
for i,v in enumerate(vs):
|
||||||
|
if i < 2:
|
||||||
|
continue
|
||||||
|
for j,vv in enumerate([*get_points(vs[0]), *get_points(vs[i - 1]), *get_points(vs[i])]):
|
||||||
|
vertices[(i-2)*9+j] = vv
|
||||||
|
|
||||||
|
texcoords = ffi.new("float[]", 0)
|
||||||
|
# for i,c in enumerate([0, 0, 0.5, 1, 1, 0]):
|
||||||
|
# texcoords[i] = c
|
||||||
|
normals = ffi.new("float[]", 0)
|
||||||
|
# for i,c in enumerate([0, 1, 0, 0, 1, 0, 0, 1, 0]):
|
||||||
|
# normals[i] = c
|
||||||
|
texcoords2 = ffi.new("float[]", 0)
|
||||||
|
# for i in range(6):
|
||||||
|
# texcoords[i] = 0
|
||||||
|
|
||||||
|
# mesh = Mesh(6, 2, vertices, texcoords, texcoords2, normals)
|
||||||
|
mesh = Mesh(len(vs) * 3, len(vs), vertices, texcoords, texcoords2, normals)
|
||||||
|
RL.upload_mesh(mesh, False)
|
||||||
|
w.mesh = mesh
|
||||||
|
w.model = RL.load_model_from_mesh(mesh)
|
||||||
|
return w
|
||||||
|
|
||||||
|
def player_input(w: World):
|
||||||
|
if RL.is_key_pressed(RL.KEY_SPACE):
|
||||||
|
w.rotate_cam = not w.rotate_cam
|
||||||
|
if RL.is_key_pressed(RL.KEY_W):
|
||||||
|
w.draw_wireframe = not w.draw_wireframe
|
||||||
|
|
||||||
|
def update(w: World):
|
||||||
|
pass
|
||||||
|
# mesh = Mesh(
|
||||||
|
# vertexCount = len(w.vertices),
|
||||||
|
# triangleCount = len(w.vertices) - 2,
|
||||||
|
# vertices = w.vertices
|
||||||
|
# )
|
||||||
|
# new_mesh = RL.gen_
|
||||||
|
|
||||||
|
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, vertex_radius, RL.GREEN)
|
||||||
|
if w.draw_wireframe[0]:
|
||||||
|
RL.rl_enable_wire_mode()
|
||||||
|
else:
|
||||||
|
RL.rl_disable_wire_mode()
|
||||||
|
RL.draw_model(w.model, RL.vector3_zero(), 1, RL.GREEN)
|
||||||
|
|
||||||
|
def draw_2d(w: World):
|
||||||
|
val = RL.gui_check_box(Rect(10, 30, 50, 50), "Draw Wireframe", w.draw_wireframe)
|
||||||
|
if val != 0:
|
||||||
|
print(val)
|
||||||
|
if val:
|
||||||
|
print('hello')
|
||||||
|
w.draw_wireframe = True
|
||||||
|
|
||||||
|
RL.init_window(screen_width, screen_height, "Starter");
|
||||||
|
RL.set_target_fps(60)
|
||||||
|
|
||||||
|
w = init()
|
||||||
|
while not RL.window_should_close():
|
||||||
|
player_input(w)
|
||||||
|
update(w)
|
||||||
|
|
||||||
|
# Drawing
|
||||||
|
if w.rotate_cam:
|
||||||
|
RL.update_camera(w.cam, RL.CameraMode.CAMERA_ORBITAL)
|
||||||
|
RL.begin_drawing()
|
||||||
|
RL.clear_background(RL.WHITE)
|
||||||
|
|
||||||
|
RL.begin_mode_3d(w.cam)
|
||||||
|
draw_3d(w)
|
||||||
|
RL.end_mode_3d()
|
||||||
|
|
||||||
|
draw_2d(w)
|
||||||
|
|
||||||
|
RL.end_drawing()
|
||||||
|
w.frame_count += 1
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user