mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2025-01-06 12:19:47 +00:00
Clarified triangulation code and added docs.
This commit is contained in:
parent
4762d72090
commit
d52a0b7ab4
1 changed files with 55 additions and 30 deletions
|
@ -1,33 +1,44 @@
|
||||||
use <math.scad>
|
use <math.scad>
|
||||||
|
|
||||||
|
|
||||||
function winding_dir(points, face) =
|
// Given an array of vertices (`points`), and a list of indexes into the
|
||||||
|
// vertex array (`face`), returns the normal vector of the face.
|
||||||
|
// points = Array of vertices for the polyhedron.
|
||||||
|
// face = The face, given as a list of indices into the vertex array `points`.
|
||||||
|
function face_normal(points, face) =
|
||||||
let(count=len(face))
|
let(count=len(face))
|
||||||
|
normalize(
|
||||||
sum(
|
sum(
|
||||||
[
|
[
|
||||||
for(i=[0:count-1]) cross(
|
for(i=[0:count-1]) cross(
|
||||||
points[face[(i+1)%count]]-points[face[0]],
|
points[face[(i+1)%count]]-points[face[0]],
|
||||||
points[face[(i+2)%count]]-points[face[(i+1)%count]]
|
points[face[(i+2)%count]]-points[face[(i+1)%count]]
|
||||||
)
|
)
|
||||||
],
|
]
|
||||||
0
|
)
|
||||||
)
|
)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
function find_convex_vertex(dir, points, face, i=0) =
|
// Returns the index of a convex point on the given face.
|
||||||
|
// points = Array of vertices for the polyhedron.
|
||||||
|
// face = The face, given as a list of indices into the vertex array `points`.
|
||||||
|
// facenorm = The normal vector of the face.
|
||||||
|
function find_convex_vertex(points, face, facenorm, i=0) =
|
||||||
let(count=len(face),
|
let(count=len(face),
|
||||||
p0=points[face[i]],
|
p0=points[face[i]],
|
||||||
p1=points[face[(i+1)%count]],
|
p1=points[face[(i+1)%count]],
|
||||||
p2=points[face[(i+2)%count]]
|
p2=points[face[(i+2)%count]]
|
||||||
)
|
)
|
||||||
(len(face)>i)?
|
(len(face)>i)?
|
||||||
(cross(p1-p0, p2-p1)*dir>0)? (i+1)%count : find_convex_vertex(dir, points, face, i+1)
|
(cross(p1-p0, p2-p1)*facenorm>0)? (i+1)%count : find_convex_vertex(points, face, facenorm, i+1)
|
||||||
: //This should never happen since there is at least 1 convex vertex.
|
: //This should never happen since there is at least 1 convex vertex.
|
||||||
undef
|
undef
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
// points = Array of vertices for the polyhedron.
|
||||||
|
// face = The face, given as a list of indices into the vertex array `points`.
|
||||||
function point_in_ear(points, face, tests, i=0) =
|
function point_in_ear(points, face, tests, i=0) =
|
||||||
(i<len(face)-1)?
|
(i<len(face)-1)?
|
||||||
let(
|
let(
|
||||||
|
@ -52,6 +63,8 @@ function check_point_in_ear(point, tests) =
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
// Removes the last item in an array if it is the same as the first item.
|
||||||
|
// v = The array to normalize.
|
||||||
function normalize_vertex_perimeter(v) =
|
function normalize_vertex_perimeter(v) =
|
||||||
(len(v) < 2)? v :
|
(len(v) < 2)? v :
|
||||||
(v[len(v)-1] != v[0])? v :
|
(v[len(v)-1] != v[0])? v :
|
||||||
|
@ -59,21 +72,15 @@ function normalize_vertex_perimeter(v) =
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
function triangulate_faces(points, faces) =
|
// Given a face in a polyhedron, and a vertex in that face, returns true
|
||||||
[
|
// if that vertex is the only non-colinear vertex in the face.
|
||||||
for (i=[0 : len(faces)-1])
|
// points = Array of vertices for the polyhedron.
|
||||||
let(facet = normalize_vertex_perimeter(faces[i]))
|
// facelist = The face, given as a list of indices into the vertex array `points`.
|
||||||
for (face = triangulate_face(points, facet))
|
// vertex = The index into `facelist`, of the vertex to test.
|
||||||
if (face[0]!=face[1] && face[1]!=face[2] && face[2]!=face[0]) face
|
function is_only_noncolinear_vertex(points, facelist, vertex) =
|
||||||
]
|
|
||||||
;
|
|
||||||
|
|
||||||
|
|
||||||
function is_last_off_a_line(points, facelist, vertex) =
|
|
||||||
let(
|
let(
|
||||||
face=wrap_range(facelist, vertex+1, vertex-1),
|
face=wrap_range(facelist, vertex+1, vertex-1),
|
||||||
count=len(face),
|
count=len(face)
|
||||||
dir=winding_dir(points, face)
|
|
||||||
)
|
)
|
||||||
0==sum(
|
0==sum(
|
||||||
[
|
[
|
||||||
|
@ -88,30 +95,34 @@ function is_last_off_a_line(points, facelist, vertex) =
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
// Given a face in a polyhedron, subdivides the face into triangular faces.
|
||||||
|
// Returns an array of faces, where each face is a list of vertex indices.
|
||||||
|
// points = Array of vertices for the polyhedron.
|
||||||
|
// face = The face, given as a list of indices into the vertex array `points`.
|
||||||
function triangulate_face(points, face) =
|
function triangulate_face(points, face) =
|
||||||
let(count=len(face))
|
let(count=len(face))
|
||||||
(3==count)?
|
(3==count)?
|
||||||
[face]
|
[face]
|
||||||
:
|
:
|
||||||
let(
|
let(
|
||||||
dir=winding_dir(points, face),
|
facenorm=face_normal(points, face),
|
||||||
cv=find_convex_vertex(dir, points, face),
|
cv=find_convex_vertex(points, face, facenorm),
|
||||||
pv=(count+cv-1)%count,
|
pv=(count+cv-1)%count,
|
||||||
nv=(cv+1)%count,
|
nv=(cv+1)%count,
|
||||||
p0=points[face[pv]],
|
p0=points[face[pv]],
|
||||||
p1=points[face[cv]],
|
p1=points[face[cv]],
|
||||||
p2=points[face[nv]],
|
p2=points[face[nv]],
|
||||||
tests=[
|
tests=[
|
||||||
[cross(dir, p0-p2), cross(dir, p0-p2)*p0],
|
[cross(facenorm, p0-p2), cross(facenorm, p0-p2)*p0],
|
||||||
[cross(dir, p1-p0), cross(dir, p1-p0)*p1],
|
[cross(facenorm, p1-p0), cross(facenorm, p1-p0)*p1],
|
||||||
[cross(dir, p2-p1), cross(dir, p2-p1)*p2]
|
[cross(facenorm, p2-p1), cross(facenorm, p2-p1)*p2]
|
||||||
],
|
],
|
||||||
ear_test=point_in_ear(points, face, tests),
|
ear_test=point_in_ear(points, face, tests),
|
||||||
clipable_ear=(ear_test[0]<0),
|
clipable_ear=(ear_test[0]<0),
|
||||||
diagonal_point=ear_test[1]
|
diagonal_point=ear_test[1]
|
||||||
)
|
)
|
||||||
(clipable_ear)? // There is no point inside the ear.
|
(clipable_ear)? // There is no point inside the ear.
|
||||||
is_last_off_a_line(points, face, cv)?
|
is_only_noncolinear_vertex(points, face, cv)?
|
||||||
// In the point&line degeneracy clip to somewhere in the middle of the line.
|
// In the point&line degeneracy clip to somewhere in the middle of the line.
|
||||||
flatten([
|
flatten([
|
||||||
triangulate_face(points, wrap_range(face, cv, (cv+2)%count)),
|
triangulate_face(points, wrap_range(face, cv, (cv+2)%count)),
|
||||||
|
@ -131,4 +142,18 @@ function triangulate_face(points, face) =
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
// Subdivides all faces for the given polyhedron that have more than 3 vertices.
|
||||||
|
// Returns an array of faces where each face is a list of 3 vertex array indices.
|
||||||
|
// points = Array of vertices for the polyhedron.
|
||||||
|
// faces = Array of faces for the polyhedron. Each face is a list of 3 or more indices into the `points` array.
|
||||||
|
function triangulate_faces(points, faces) =
|
||||||
|
[
|
||||||
|
for (i=[0 : len(faces)-1])
|
||||||
|
let(facet = normalize_vertex_perimeter(faces[i]))
|
||||||
|
for (face = triangulate_face(points, facet))
|
||||||
|
if (face[0]!=face[1] && face[1]!=face[2] && face[2]!=face[0]) face
|
||||||
|
]
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
||||||
|
|
Loading…
Reference in a new issue