Added triangulation support code.

This commit is contained in:
Revar Desmera 2018-09-01 02:38:47 -07:00
parent f9a441dde8
commit 844d2101e5
4 changed files with 164 additions and 3 deletions

View file

@ -71,6 +71,30 @@ function cdr(list) = len(list)>1?[for (i=[1:len(list)-1]) list[i]]:[];
function reverse(list) = [ for (i = [len(list)-1 : -1 : 0]) list[i] ];
// Returns a slice of the given array, wrapping around past the beginning, if end < start
function wrap_range(list, start, end) =
(end<start)?
concat(
[for (i=[start:len(list)-1]) list[i]],
[for (i=[0:end]) list[i]]
)
:
[for (i=[start:end]) list[i]]
;
// Takes an array of arrays and flattens it by one level.
// flatten([[1,2,3], [4,5,[6,7,8]]]) returns [1,2,3,4,5,[6,7,8]]
function flatten(l) = [ for (a = l) for (b = a) b ];
// Returns the sum of all entries in the given array.
// If passed an array of vectors, returns a vector of sums of each part.
// sum([1,2,3]) returns 6.
// sum([[1,2,3], [3,4,5], [5,6,7]]) returns [9, 12, 15]
function sum(v, i=0) = i<len(v)-1 ? v[i] + sum(v, i+1) : v[i];
// Returns the sum of the square of each element of a vector.
function sum_of_squares(v,n=0) = (n>=len(v))? 0 : ((v[n]*v[n]) + sum_of_squares(v,n+1));

View file

@ -33,6 +33,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
include <math.scad>
include <quaternions.scad>
include <triangulation.scad>
// Creates a 2D polygon circle, modulated by one or more superimposed
@ -154,7 +155,8 @@ module extrude_2dpath_along_spiral(polyline, h, r, twist=360) {
[[for (b = [pline_count-1:-1:0]) b+(steps)*pline_count]]
);
polyhedron(points=poly_points, faces=poly_faces, convexity=10);
tri_faces = triangulate_faces(poly_points, poly_faces);
polyhedron(points=poly_points, faces=tri_faces, convexity=10);
}
@ -215,7 +217,8 @@ module extrude_2dpath_along_3dpath(polyline, path, convexity=10) {
[[for (b = [pline_count-1:-1:0]) b+(path_count-1)*pline_count]]
);
polyhedron(points=poly_points, faces=poly_faces, convexity=convexity);
tri_faces = triangulate_faces(poly_points, poly_faces);
polyhedron(points=poly_points, faces=tri_faces, convexity=convexity);
}

View file

@ -448,7 +448,7 @@ module xspread(spacing=1,n=2) for (i=[0:n-1]) right((i-(n-1)/2.0)*spacing) child
// yspread(25,3) sphere(1)
// yspread(25, n=3) sphere(1)
// yspread(spacing=20, n=4) sphere(1)
module yspread(spacing=1,n=2) for (i=[0:n-1]) back((i-(n-1)/2.0)*spacing) children();
module yspread(spacing=1,n=2) for (i=[0:n-1]) back((i-(n-1)/2)*spacing) children();
// Spreads out n copies of the given children along the Z axis.

134
triangulation.scad Normal file
View file

@ -0,0 +1,134 @@
use <math.scad>
function winding_dir(points, face) =
let(count=len(face))
sum(
[
for(i=[0:count-1]) cross(
points[face[(i+1)%count]]-points[face[0]],
points[face[(i+2)%count]]-points[face[(i+1)%count]]
)
],
0
)
;
function find_convex_vertex(dir, points, face, i=0) =
let(count=len(face),
p0=points[face[i]],
p1=points[face[(i+1)%count]],
p2=points[face[(i+2)%count]]
)
(len(face)>i)?
(cross(p1-p0, p2-p1)*dir>0)? (i+1)%count : find_convex_vertex(dir, points, face, i+1)
: //This should never happen since there is at least 1 convex vertex.
undef
;
function point_in_ear(points, face, tests, i=0) =
(i<len(face)-1)?
let(
prev=point_in_ear(points, face, tests, i+1),
test=check_point_in_ear(points[face[i]], tests)
)
(test>prev[0])? [test, i] : prev
:
[check_point_in_ear(points[face[i]], tests), i]
;
function check_point_in_ear(point, tests) =
let(
result=[
(point*tests[0][0])-tests[0][1],
(point*tests[1][0])-tests[1][1],
(point*tests[2][0])-tests[2][1]
]
)
(result[0]>0 && result[1]>0 && result[2]>0)? result[0] : -1
;
function normalize_vertex_perimeter(v) =
(len(v) < 2)? v :
(v[len(v)-1] != v[0])? v :
[for (i=[0:len(v)-2]) v[i]]
;
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
]
;
function is_last_off_a_line(points, facelist, vertex) =
let(
face=wrap_range(facelist, vertex+1, vertex-1),
count=len(face),
dir=winding_dir(points, face)
)
0==sum(
[
for(i=[0:count-1]) norm(
cross(
points[face[(i+1)%count]]-points[face[0]],
points[face[(i+2)%count]]-points[face[(i+1)%count]]
)
)
]
)
;
function triangulate_face(points, face) =
let(count=len(face))
(3==count)?
[face]
:
let(
dir=winding_dir(points, face),
cv=find_convex_vertex(dir, points, face),
pv=(count+cv-1)%count,
nv=(cv+1)%count,
p0=points[face[pv]],
p1=points[face[cv]],
p2=points[face[nv]],
tests=[
[cross(dir, p0-p2), cross(dir, p0-p2)*p0],
[cross(dir, p1-p0), cross(dir, p1-p0)*p1],
[cross(dir, p2-p1), cross(dir, p2-p1)*p2]
],
ear_test=point_in_ear(points, face, tests),
clipable_ear=(ear_test[0]<0),
diagonal_point=ear_test[1]
)
(clipable_ear)? // There is no point inside the ear.
is_last_off_a_line(points, face, cv)?
// In the point&line degeneracy clip to somewhere in the middle of the line.
flatten([
triangulate_face(points, wrap_range(face, cv, (cv+2)%count)),
triangulate_face(points, wrap_range(face, (cv+2)%count, cv))
])
:
// Otherwise the ear is safe to clip.
flatten([
[wrap_range(face, pv, nv)],
triangulate_face(points, wrap_range(face, nv, pv))
])
: // If there is a point inside the ear, make a diagonal and clip along that.
flatten([
triangulate_face(points, wrap_range(face, cv, diagonal_point)),
triangulate_face(points, wrap_range(face, diagonal_point, cv))
])
;
// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap