diff --git a/src/triangulate.scad b/src/triangulate.scad new file mode 100644 index 00000000..b4061a33 --- /dev/null +++ b/src/triangulate.scad @@ -0,0 +1,94 @@ + +function _triangulate_in_triangle(p0, p1, p2, p) = + let( + v0 = p0 - p, + v1 = p1 - p, + v2 = p2 - p, + c0 = cross(v0, v1), + c1 = cross(v1, v2), + c2 = cross(v2, v0) + ) + (c0 > 0 && c1 > 0 && c2 > 0) || (c0 < 0 && c1 < 0 && c2 < 0); + +function _triangulate_snipable(shape_pts, u, v, w, n, indices, epsilon = 0.0001) = + let( + a = shape_pts[indices[u]], + b = shape_pts[indices[v]], + c = shape_pts[indices[w]], + ax = a[0], + ay = a[1], + bx = b[0], + by = b[1], + cx = c[0], + cy = c[1] + ) + epsilon > (((bx - ax) * (cy - ay)) - ((by - ay) * (cx - ax))) ? + false : _triangulate_snipable_sub(shape_pts, n, u, v, w, a, b, c, indices); + +function _triangulate_snipable_sub(shape_pts, n, u, v, w, a, b, c, indices, p = 0) = + p == n ? true : ( + ((p == u) || (p == v) || (p == w)) ? _triangulate_snipable_sub(shape_pts, n, u, v, w, a, b, c, indices, p + 1) : ( + _triangulate_in_triangle(a, b, c, shape_pts[indices[p]]) ? + false : _triangulate_snipable_sub(shape_pts, n, u, v, w, a, b, c, indices, p + 1) + ) + ); + +// remove the elem at idx v from indices +function _triangulate_remove_v(indices, v, num_of_vertices) = + let( + nv_minuns_one = num_of_vertices - 1 + ) + v == 0 ? [for(i = [1:nv_minuns_one]) indices[i]] : ( + v == nv_minuns_one ? [for(i = [0:v - 1]) indices[i]] : concat( + [for(i = [0:v - 1]) indices[i]], + [for(i = [v + 1:nv_minuns_one]) indices[i]] + ) + ); + +function _triangulate_zero_or_value(num_of_vertices, value) = + num_of_vertices <= value ? 0 : value; + + +function _triangulate_real_triangulate_sub(shape_pts, collector, indices, v, num_of_vertices, count, epsilon) = + let( + // idxes of three consecutive vertices + u = _triangulate_zero_or_value(num_of_vertices, v), + vi = _triangulate_zero_or_value(num_of_vertices, u + 1), + w = _triangulate_zero_or_value(num_of_vertices, vi + 1) + ) + _triangulate_snipable(shape_pts, u, vi, w, num_of_vertices, indices, epsilon) ? + _triangulate_snip(shape_pts, collector, indices, u, vi, w, num_of_vertices, count, epsilon) : + _triangulate_real_triangulate(shape_pts, collector, indices, vi, num_of_vertices, count, epsilon); + +function _triangulate_snip(shape_pts, collector, indices, u, v, w, num_of_vertices, count, epsilon) = + let( + a = indices[u], + b = indices[v], + c = indices[w], + new_nv = num_of_vertices - 1 + ) + _triangulate_real_triangulate( + shape_pts, + concat(collector, [[a, b, c]]), + _triangulate_remove_v(indices, v, num_of_vertices), + v, + new_nv, + 2 * new_nv, + epsilon + ); + +function _triangulate_real_triangulate(shape_pts, collector, indices, v, num_of_vertices, count, epsilon) = + count <= 0 ? [] : ( + num_of_vertices == 2 ? + collector : _triangulate_real_triangulate_sub(shape_pts, collector, indices, v, num_of_vertices, count - 1, epsilon) + ); + +function triangulate(shape_pts, epsilon = 0.0001) = + let( + num_of_vertices = len(shape_pts), + v = num_of_vertices - 1, + indices = [for(vi = [0:v]) vi], + count = 2 * num_of_vertices + ) + num_of_vertices < 3 ? [] : _triangulate_real_triangulate(shape_pts, [], indices, v, num_of_vertices, count, epsilon); + \ No newline at end of file