Create quickhull.nim
with quickhull
and quickhull_points
functions.
This commit is contained in:
parent
7b54183f31
commit
b60c837c47
88
libs/quickhull/quickhull.nim
Normal file
88
libs/quickhull/quickhull.nim
Normal file
|
@ -0,0 +1,88 @@
|
|||
|
||||
|
||||
import vmath
|
||||
import std/random
|
||||
import std/sets
|
||||
import std/sequtils
|
||||
|
||||
type Face* = object
|
||||
points*: array[3, Vec3]
|
||||
plane*: Vec4
|
||||
|
||||
func plane_from_norm_point(normal, point: Vec3): Vec4 =
|
||||
let n = normal.normalize
|
||||
let p = point
|
||||
vec4(n.x, n.y, n.z, -(n.x*p.x+n.y*p.y+n.z*p.z))
|
||||
|
||||
func face_from_triangle(a,b,c: Vec3): Face =
|
||||
let n = cross(b-a, c-a)
|
||||
Face(points: [a,b,c], plane: plane_from_norm_point(n, a))
|
||||
|
||||
template distance_to_plane(point: Vec3, plane: Vec4): float32 =
|
||||
dot(plane, vec4(point, 1.0))
|
||||
|
||||
proc add_point_to_hull(point: Vec3, hull: var seq[Face]) =
|
||||
var horizon_edges: seq[(Vec3, Vec3)] = @[]
|
||||
var new_faces: seq[Face] = @[]
|
||||
|
||||
for face in hull:
|
||||
if distance_to_plane(point, face.plane) > 0:
|
||||
# Store the edges of the horizon
|
||||
for i in 0 .. 2:
|
||||
let edge = (face.points[i], face.points[(i+1) mod 3])
|
||||
let other = (edge[1], edge[0])
|
||||
let other_pos = horizon_edges.find other
|
||||
if other_pos >= 0:
|
||||
horizon_edges.del other_pos
|
||||
else:
|
||||
horizon_edges.add edge
|
||||
else:
|
||||
new_faces.add face
|
||||
|
||||
for (a, b) in horizon_edges:
|
||||
new_faces.add face_from_triangle(a, b, point)
|
||||
|
||||
hull = new_faces
|
||||
|
||||
proc quickhull*(points: seq[Vec3]): seq[Face] =
|
||||
if points.len <= 4:
|
||||
return
|
||||
var hull: seq[Face]
|
||||
|
||||
var points = points
|
||||
shuffle(points)
|
||||
|
||||
let p0 = points[0]
|
||||
let p1 = points[1]
|
||||
let p2 = points[2]
|
||||
let p3 = points[3]
|
||||
|
||||
let f = face_from_triangle(p0, p1, p2)
|
||||
# Ensure all faces point outwards
|
||||
if distance_to_plane(p3, f.plane) < 0:
|
||||
hull.add f
|
||||
hull.add face_from_triangle(p0, p2, p3)
|
||||
hull.add face_from_triangle(p1, p3, p2)
|
||||
hull.add face_from_triangle(p0, p3, p1)
|
||||
else:
|
||||
hull.add face_from_triangle(p0, p2, p1)
|
||||
hull.add face_from_triangle(p0, p3, p2)
|
||||
hull.add face_from_triangle(p1, p2, p3)
|
||||
hull.add face_from_triangle(p0, p1, p3)
|
||||
|
||||
for i,point in points:
|
||||
if i<4: continue
|
||||
add_point_to_hull(point, hull)
|
||||
|
||||
return hull
|
||||
|
||||
proc quickhull_points*(points: seq[Vec3]): seq[Vec3] =
|
||||
let hull = quickhull(points)
|
||||
if hull.len == 0:
|
||||
return points
|
||||
var s: HashSet[Vec3]
|
||||
for f in hull:
|
||||
for v in f.points:
|
||||
s.incl v
|
||||
return s.toSeq
|
||||
|
Loading…
Reference in a new issue