diff --git a/debug.scad b/debug.scad index fccc6c9..27f175f 100644 --- a/debug.scad +++ b/debug.scad @@ -149,12 +149,14 @@ module debug_vertices(vertices, size=1, disabled=false) { if (!disabled) { echo(vertices=vertices); color("blue") { - for (i = [0:1:len(vertices)-1]) { - v = vertices[i]; + dups = search_radius(vertices, vertices, 1e-9); + for (ind = dups){ + numstr = str_join([for(i=ind) str(i)],","); + v = vertices[ind[0]]; translate(v) { up(size/8) zrot($vpr[2]) xrot(90) { linear_extrude(height=size/10, center=true, convexity=10) { - text(text=str(i), size=size, halign="center"); + text(text=numstr, size=size, halign="center"); } } sphere(size/10); @@ -239,19 +241,18 @@ module debug_faces(vertices, faces, size=1, disabled=false) { -// Module: debug_polyhedron() +// Module: debug_vnf() // Usage: -// debug_polyhedron(points, faces, , , ); +// debug_vnf(vnfs, , , ); // Description: -// A drop-in module to replace `polyhedron()` and help debug vertices and faces. +// A drop-in module to replace `vnf_polyhedron()` and help debug vertices and faces. // Draws all the vertices at their 3D position, numbered in blue by their -// position in the vertex array. Each face will have their face number drawn +// position in the vertex array. Each face will have its face number drawn // in red, aligned with the center of face. All given faces are drawn with // transparency. All children of this module are drawn with transparency. // Works best with Thrown-Together preview mode, to see reversed faces. // Arguments: -// points = Array of point vertices. -// faces = Array of faces by vertex numbers. +// vnf = vnf to display // --- // convexity = The max number of walls a ray can pass through the given polygon paths. // txtsize = The size of the text used to label the faces and vertices. @@ -259,15 +260,14 @@ module debug_faces(vertices, faces, size=1, disabled=false) { // Example(EdgesMed): // verts = [for (z=[-10,10], a=[0:120:359.9]) [10*cos(a),10*sin(a),z]]; // faces = [[0,1,2], [5,4,3], [0,3,4], [0,4,1], [1,4,5], [1,5,2], [2,5,3], [2,3,0]]; -// debug_polyhedron(points=verts, faces=faces, txtsize=1); -module debug_polyhedron(points, faces, convexity=6, txtsize=1, disabled=false) { - debug_faces(vertices=points, faces=faces, size=txtsize, disabled=disabled) { - polyhedron(points=points, faces=faces, convexity=convexity); +// debug_polyhedron([verts,faces], txtsize=1); +module debug_vnf(vnf, convexity=6, txtsize=1, disabled=false) { + debug_faces(vertices=vnf[0], faces=vnf[1], size=txtsize, disabled=disabled) { + vnf_polyhedron(vnf, convexity=convexity); } } - // Function: standard_anchors() // Usage: // anchs = standard_anchors(); diff --git a/vectors.scad b/vectors.scad index b110fd7..1eaa87e 100644 --- a/vectors.scad +++ b/vectors.scad @@ -260,7 +260,7 @@ function vector_axis(v1,v2=undef,v3=undef) = // leafsize = maximum number of points to store in the tree's leaf nodes. Default: 25 function vp_tree(points, leafsize=25) = assert(is_matrix(points),"points must be a consistent list of data points") - _vp_tree(points, count(len(points)), leafsize); + [points,_vp_tree(points, count(len(points)), leafsize)]; function _vp_tree(ptlist, ind, leafsize) = len(ind)<=leafsize ? [ind] : @@ -304,11 +304,12 @@ function _vp_search(points, tree, p, r) = ]; function vp_search(points, tree, p, r) = - assert(is_list(tree) && (len(tree)==4 || (len(tree)==1 && is_list(tree[0]))), "Vantage point tree not valid") - assert(is_matrix(points), "Parameter points is not a consistent point list") - assert(is_vector(p,len(points[0])), "Query must be a vector whose length matches the point list") - assert(all_positive(r),"Radius r must be a positive number") - _vp_search(points, tree, p, r); +// assert(is_list(tree[1]) && (len(tree[1])==4 || (len(tree[1])==1 && is_list(tree[0]))), "Vantage point tree not valid") +// assert(is_matrix(points), "Parameter points is not a consistent point list") +// assert(is_vector(p,len(points[0])), "Query must be a vector whose length matches the point list") +// assert(all_positive(r),"Radius r must be a positive number") +// _vp_search(points, tree, p, r); + _vp_search(tree[0], tree[1], p, r); // Function: vp_nearest() @@ -355,4 +356,32 @@ function vp_nearest(points, tree, p, k) = subindex(_vp_nearest(points, tree, p, k),0); +// Function: search_radius() +// Usage: +// index_list = search_radius(points, queries, r, ); +// Description: +// Given a list of points and a compatible list of queries, for each query +// search the points list for all points whose distance from the query +// is less than or equal to r. The return value index_list[i] lists the indices +// in points of all matches to query q[i]. This list can be in arbitrary order. +// . +// This function is advantageous to use especially when both `points` and `queries` +// are large sets. The method contructs a vantage point tree and then uses it +// to check all the queries. If you use queries=points and set r to epsilon then +// you can find all of the approximate duplicates in a large list of vectors. +// Example: Finding duplicates in a list of vectors. With exact equality the order of the output is consistent, but with small variations [2,4] could occur in one position and [4,2] in the other one. +// v = array_group(rands(0,10,5*3,seed=9),3); +// points = [v[0],v[1],v[2],v[3],v[2],v[3],v[3],v[4]]; +// echo(search_radius(points,points,1e-9)); // Prints [[0],[1],[2,4],[3,5,6],[2,4],[3,5,6],[3,5,6],[7]] +// +function search_radius(points, queries, r, leafsize=25) = + assert(is_matrix(points),"Invalid points list") + assert(is_matrix(queries),"Invalid query list") + assert(len(points[0])==len(queries[0]), "Query vectors don't match length of points") + let( + vptree = vp_tree(points, leafsize) + ) + [for(q=queries) vp_search(points, vptree, q, r)]; + + // vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap