diff --git a/src/experimental/_impl/_tri_delaunay_impl.scad b/src/experimental/_impl/_tri_delaunay_impl.scad index bd1a283f..a72b3f4d 100644 --- a/src/experimental/_impl/_tri_delaunay_impl.scad +++ b/src/experimental/_impl/_tri_delaunay_impl.scad @@ -1,48 +1,229 @@ use ; +use ; +use ; +use ; +use ; +use ; +use ; +use ; +use ; -// [max, min, min, max] -function _tri_delaunay_boundIndices(points, leng, indices, i = 0) = +function cc_center(cc) = cc[0]; +function cc_rr(cc) = cc[2]; + +function delaunay_init(points) = let( - bounds = i < leng - 1 ? _tri_delaunay_boundIndices(points, leng, indices, i + 1) - : [undef, undef, undef, undef], - p0 = points[indices[0]], - p1 = points[indices[1]], - p2 = points[i], - c_circle = tri_circumcircle([p0, p1, p2]), - r = c_circle[1], - cside = c_circle == [] ? undef : cross(p1 - p0, c_circle[0] - p1), - pside = cross(p1 - p0, p2 - p1), - pdot = (p2 - p0) * (p2 - p1) - ) - pdot < 0 && 0 == pside ? [-1, 1, 1, -1] : - c_circle == [] ? bounds : - pside > 0 && cside > 0 ? [bounds[0], bounds[1], bounds[2], bounds[3] ? min(bounds[3], r) : r] : - pside > 0 && cside <= 0 ? [bounds[0], bounds[1], bounds[2] ? max(bounds[2], r) : r, bounds[3]] : - pside <= 0 && cside > 0 ? [bounds[0], bounds[1] ? max(bounds[1],r) : r, bounds[2], bounds[3]] : - [bounds[0] ? min(bounds[0], r) : r, bounds[1], bounds[2], bounds[3]]; // is_undef(cside) also returns this + xs = [for(p = points) p[0]], + ys = [for(p = points) p[1]], + max_x = max(xs), + min_x = min(xs), + max_y = max(ys), + min_y = min(ys), + center = [max_x + min_x, max_y + min_y] / 2, + halfW = abs(max_x - center[0]) * 2, + halfH = abs(max_y - center[1]) * 2, + coords = [ + center + [-halfW, -halfH], + center + [-halfW, halfH], + center + [ halfW, halfH], + center + [ halfW, -halfH], + ], + t1 = [0, 1, 3], // indices + t2 = [2, 3, 1], + triangles = hashmap([ + [t1, [t2, undef, undef]], + [t2, [t1, undef, undef]] + ] + ), + circles = hashmap([ + [t1, tri_circumcircle([for(i = t1) coords[i]])], + [t2, tri_circumcircle([for(i = t2) coords[i]])] + ] + ) + ) + [coords, triangles, circles]; + +function delaunay_coords(d) = d[0]; +function delaunay_triangles(d) = d[1]; +function delaunay_circles(d) = d[2]; -function _tri_delaunay_try_triangle(points, indices_boundIndices, i) = - let( - indices = indices_boundIndices[0], - bounds = indices_boundIndices[1], - p0 = points[indices[0]], - p1 = points[indices[1]], - p2 = points[i], - c_circle = tri_circumcircle([p0, p1, p2]), - r = c_circle[1], - cside = c_circle == [] ? undef : cross(p1 - p0, c_circle[0] - p1) - ) - c_circle == [] ? undef : - (cside > 1 && (!bounds[2] && (!bounds[1] || r>=bounds[1]) && (!bounds[3] || r<=bounds[3]))) || - (cside <= 1 && (!bounds[1] && (!bounds[2] || r>=bounds[2]) && (!bounds[0] || r<=bounds[0]))) ? concat(indices, [i]) : - undef; - -function _tri_delaunay_triangleIndices(points, leng, indices_boundIndices, triangles, i = 0) = - let( - indices = indices_boundIndices[0], - newtriangle = _tri_delaunay_try_triangle(points, indices_boundIndices, i), - newtriangles = newtriangle ? concat(triangles, [newtriangle]) : triangles - ) - i <= indices[1] ? _tri_delaunay_triangleIndices(points, leng, indices_boundIndices, [], indices[1] + 1) : - i< leng - 1 ? _tri_delaunay_triangleIndices(points, leng, indices_boundIndices, newtriangles,i + 1) : - newtriangles; \ No newline at end of file +function delaunay_addpoint(d, p) = + let( + idx = len(delaunay_coords(d)), + ndelaunay = delaunayAddCoords(d, p), + badTriangles = delaunayBadTriangles(ndelaunay, p), + boundaries = delaunayBoundaries(ndelaunay, badTriangles), + ndelaunay2 = delBadTriangles(ndelaunay, badTriangles), + newTriangles = [ + for(b = boundaries) [ + [idx, b[0][0], b[0][1]], // t + b[0], // edge + b[1] // delaunayTri + ] + ] + ) + adjustNeighbors(ndelaunay2, newTriangles); + +function adjustNeighbors(d, newTriangles) = + let( + coords = delaunay_coords(d), + nts = [ + for(nt = newTriangles) + [nt[0], [nt[2], undef, undef]] + ], + ncs = [ + for(nt = newTriangles) + [nt[0], tri_circumcircle([for(i = nt[0]) coords[i]])] + ], + nd = [ + coords, + hashmap(concat(hashmap_entries(delaunay_triangles(d)), nts)), + hashmap(concat(hashmap_entries(delaunay_circles(d)), ncs)) + ], + leng = len(newTriangles), + aDtrid = _adjustNeighborsDtri(nd, newTriangles, leng) + ) + // aDtrid; + _adjustNeighborsOtri(aDtrid, newTriangles, leng); + +function _adjustNeighborsOtri(d, newTriangles, leng, i = 0) = + i == leng ? d : + let( + t = newTriangles[i][0], + nbr1 = newTriangles[(i + 1) % leng][0], + nbr2 = newTriangles[i > 0 ? i - 1 : leng + i - 1][0], + triangles = delaunay_triangles(d), + entries = hashmap_entries(triangles), + nTriangles = hashmap([for(entry = entries) entry[0] == t ? [t, [entry[1][0], nbr1, nbr2]] : entry]), + nd = [delaunay_coords(d), nTriangles, delaunay_circles(d)] + ) + _adjustNeighborsOtri(nd, newTriangles, leng, i + 1); + + +function _adjustNeighborsDtri(d, newTriangles, leng, i = 0) = + i == leng ? d : + let( + t = newTriangles[i][0], + edge = newTriangles[i][1], + delaunayTri = newTriangles[i][2] + ) + delaunayTri != undef ? + let( + neighbors = hashmap_get(delaunay_triangles(d), delaunayTri), + nbri = find_index(neighbors, function(nbr) nbr != undef && has(nbr, edge[1]) && has(nbr, edge[0])), + nd = nbri == -1 ? d : updateNbrs(d, delaunayTri, concat(slice(neighbors, 0, nbri), [t], slice(neighbors, nbri + 1))) + ) + _adjustNeighborsDtri(nd, newTriangles, leng, i + 1) : + _adjustNeighborsDtri(d, newTriangles, leng, i + 1); + +function updateNbrs(d, delaunayTri, neighbors) = + let( + coords = delaunay_coords(d), + triangles = delaunay_triangles(d), + circles = delaunay_circles(d), + tri_entries = hashmap_entries(triangles), + nTriangles = hashmap([ + for(entry = tri_entries) + entry[0] == delaunayTri ? [delaunayTri, neighbors] : entry + ]) + ) + [coords, nTriangles, circles]; + +function delaunayAddCoords(d, p) = + [ + concat(delaunay_coords(d), [p]), + delaunay_triangles(d), + delaunay_circles(d) + ]; + +function delaunayBadTriangles(d, p) = + let( + triangles = delaunay_triangles(d), + circles = delaunay_circles(d) + ) + [ + for(t = hashmap_keys(triangles)) + if(inCircumcircle(t, p, circles)) + t + ]; + +/* + is p in t? + t: triangle indices + circles: a hashmap +*/ +function inCircumcircle(t, p, circles) = + let( + c = hashmap_get(circles, t), + v = cc_center(c) - p, + rr = v[0] ^ 2 + v[1] ^ 2 + ) + rr <= cc_rr(c); + +function delaunayBoundaries(d, badTriangles) = + let( + boundaries = [], + t = badTriangles[0], + vi = 0 + ) + _delaunayBoundaries(d, badTriangles, boundaries, t, vi); + +function _delaunayBoundaries(d, badTriangles, boundaries, t, vi) = + let( + triangles = delaunay_triangles(d), + opTri = hashmap_get(triangles, t)[vi] + ) + some(badTriangles, function(tri) tri == opTri) ? + let( + i = find_index(hashmap_get(triangles, opTri), function(tri) tri == t), + nvi = (i + 1) % 3, + nt = opTri + ) + _delaunayBoundaries(d, badTriangles, boundaries, nt, nvi) : + let( + nboundaries = concat(boundaries, [[ + [t[(vi + 1) % 3], t[vi > 0 ? vi - 1 : (vi + 2)]], // edge + opTri // delaunayTri + ]]), + nvi = (vi + 1) % 3, + v1 = nboundaries[0][0][0], + v2 = nboundaries[len(nboundaries) - 1][0][1] + ) + v1 == v2 ? nboundaries : _delaunayBoundaries(d, badTriangles, nboundaries, t, nvi); + +function delBadTriangles(d, badTriangles) = + let( + triangles = delaunay_triangles(d), + circles = delaunay_circles(d), + nTriangles = hashmap([ + for(t = hashmap_keys(triangles)) + if(!has(badTriangles, t)) + [t, hashmap_get(triangles, t)] + ]), + nCircles = hashmap([ + for(t = hashmap_keys(circles)) + if(!has(badTriangles, t)) + [t, hashmap_get(circles, t)] + ]) + ) + [delaunay_coords(d), nTriangles, nCircles]; + + + +function _tri_delaunay(d, points, leng, i = 0) = + i == leng ? d : + _tri_delaunay(delaunay_addpoint(d, points[i]), points, leng, i + 1); + +function tri_delaunay_shapes(d) = + let(coords = delaunay_coords(d)) + [ + for(tri = hashmap_keys(delaunay_triangles(d))) + if(tri[0] > 3 && tri[1] > 3 && tri[2] > 3) + [coords[tri[0]], coords[tri[1]], coords[tri[2]]] + ]; + +function tri_delaunay_indices(d) = [ + for(tri = hashmap_keys(delaunay_triangles(d))) + if(tri[0] > 3 && tri[1] > 3 && tri[2] > 3) + [tri[0] - 4, tri[1] - 4, tri[2] - 4] +]; \ No newline at end of file diff --git a/src/experimental/demo/tri_delaunay_demo.scad b/src/experimental/demo/tri_delaunay_demo.scad index e3084be8..45baf7c7 100644 --- a/src/experimental/demo/tri_delaunay_demo.scad +++ b/src/experimental/demo/tri_delaunay_demo.scad @@ -1,16 +1,19 @@ -use ; use ; - -points=[for(i = [0:50]) rands(-20, 20, 2)]; +use ; -for(tri = tri_delaunay(points)) { - hull_polyline2d( - [points[tri[0]], points[tri[1]], points[tri[2]], points[tri[0]]], width = .2 - ); +points = [for(i = [0:20]) rands(-100, 100, 2)]; + +drawTris(tri_delaunay(points)); +module drawTris(pointsOfTriangles) { + #for(t = pointsOfTriangles) { + hull_polyline2d(concat(t, [t[0]])); + } } -color("red") -for(point = points) { - translate(point) - circle(.5); -} \ No newline at end of file +drawTris2(points, tri_delaunay(points, ret = "INDICES")); +module drawTris2(points, indices) { + pointsOfTriangles = [for(i = indices) [points[i[0]], points[i[1]], points[i[2]]]]; + %for(t = pointsOfTriangles) { + hull_polyline2d(concat(t, [t[0]]), 2); + } +} diff --git a/src/experimental/tri_delaunay.scad b/src/experimental/tri_delaunay.scad index 3aec89a7..ea1823df 100644 --- a/src/experimental/tri_delaunay.scad +++ b/src/experimental/tri_delaunay.scad @@ -1,18 +1,8 @@ -use ; -use ; +use; -function tri_delaunay(points)= - let( - leng = len(points), - indices_lt = [for(i=[0:leng - 3]) for(j = [i + 1:leng - 2]) [i, j]], - indices_boundIndices_lt = [ - for(indices = indices_lt) - [indices, _tri_delaunay_boundIndices(points, leng, indices)] - ] - ) - flat( - [ - for(indices_boundIndices = indices_boundIndices_lt) - _tri_delaunay_triangleIndices(points, leng, indices_boundIndices, []) - ] - ); \ No newline at end of file +// ret: "SHAPES", "INDICES", "DELAUNAY" +function tri_delaunay(points, ret = "SHAPES") = + let(d = _tri_delaunay(delaunay_init(points), points, len(points))) + ret == "SHAPES" ? tri_delaunay_shapes(d) : + ret == "INDICES" ? tri_delaunay_indices(d) : + d; // [coords(list), triangles(hashmap), circles(hashmap)] \ No newline at end of file