doc tweaks

vnf_merge split
This commit is contained in:
Adrian Mariano 2021-11-11 08:45:30 -05:00
parent d6d086430c
commit 69e8491659
9 changed files with 64 additions and 44 deletions

View file

@ -1170,7 +1170,7 @@ function is_patch(x) =
// // u=0,v=1 u=1,v=1
// ];
// tpatch = translate([-50,-50,50], patch);
// vnf = vnf_merge([
// vnf = vnf_join([
// bezier_patch(tpatch),
// bezier_patch(xrot(90, tpatch)),
// bezier_patch(xrot(-90, tpatch)),
@ -1541,7 +1541,7 @@ function patch_reverse(patch) =
// vnf = bezier_surface(patches=[patch1, patch2], splinesteps=16);
// polyhedron(points=vnf[0], faces=vnf[1]);
function bezier_surface(patches=[], splinesteps=16, style="default") =
vnf_merge([for(patch=patches) bezier_patch(patch, splinesteps=splinesteps, style=style)]);
vnf_join([for(patch=patches) bezier_patch(patch, splinesteps=splinesteps, style=style)]);
// Module: trace_bezier_patches()

View file

@ -40,7 +40,7 @@
// }
// Section: Specifying Faces
// Modules operating on faces accept a list of faces to describe the faces to operate on. Each
// face is given by a vector that points to that face. Attachments of cuboid objects also
// face is given by a vector that points to that face. Attachments of cuboid objects onto their faces also
// work by choosing an attachment face with a single vector in the same manner.
// Figure(3D,Big,NoScales,VPD=275): The six faces of the cube. Some have faces have more than one name.
// ydistribute(50) {
@ -57,8 +57,11 @@
// }
// Section: Specifying Edges
// Modules operating on edges use two arguments to describe the edge set they will use: The `edges` argument
// is a list of edge set descriptors to include in the edge set and the `except` argument is a list of
// edge set descriptors to remove from the edge set. If either argument is just a single edge set
// is a list of edge set descriptors to include in the edge set, and the `except` argument is a list of
// edge set descriptors to remove from the edge set.
// The default value for `edges` is `"ALL"`, the set of all edges.
// The default value for `except` is the empty set, meaning no edges are removed.
// If either argument is just a single edge set
// descriptor it can be passed directly rather than in a singleton list.
// Each edge set descriptor must be one of:
// - A vector pointing towards an edge, indicating that single edge.
@ -79,7 +82,8 @@
// ```
// You can specify edge descriptors directly by giving a vector, or you can use sums of the
// named direction vectors described above. Below we show all of the edge sets you can
// describe with sums of the direction vectors.
// describe with sums of the direction vectors, and then we show some examples of combining
// edge set descriptors.
// Figure(3D,Big,VPD=300,NoScales): Vectors pointing toward an edge select that single edge
// ydistribute(50) {
// xdistribute(30) {
@ -141,7 +145,7 @@
// _show_edges(edges="NONE");
// }
// }
// Figure(3D,Big,VPD=310,NoScales): Next are some examples showing how you can combine edge descriptors to obtain different edge sets. The default value for `edges` is `"ALL"`, the set of all edges. The default value for `except` is the empty set, meaning no edges are removed. You can specify the top front edge with a numerical vector or by combining the named direction vectors. If you combine them as a list you get all the edges around the front or top faces. Adding `except` removes an edge.
// Figure(3D,Big,VPD=310,NoScales): Next are some examples showing how you can combine edge descriptors to obtain different edge sets. You can specify the top front edge with a numerical vector or by combining the named direction vectors. If you combine them as a list you get all the edges around the front or top faces. Adding `except` removes an edge.
// xdistribute(43){
// _show_edges(_edges([0,-1,1]),toplabel=["edges=[0,-1,1]"]);
// _show_edges(_edges(TOP+FRONT),toplabel=["edges=TOP+FRONT"]);
@ -165,7 +169,10 @@
// Section: Specifying Corners
// Modules operating on corners use two arguments to describe the corner set they will use: The `corners` argument
// is a list of corner set descriptors to include in the corner set, and the `except` argument is a list of
// corner set descriptors to remove from the corner set. If either argument is just a single corner set
// corner set descriptors to remove from the corner set.
// The default value for `corners` is `"ALL"`, the set of all corners.
// The default value for `except` is the empty set, meaning no corners are removed.
// If either argument is just a single corner set
// descriptor it can be passed directly rather than in a singleton list.
// Each corner set descriptor must be one of:
// - A vector pointing towards a corner, indicating that corner.
@ -179,7 +186,8 @@
// ```
// You can specify corner descriptors directly by giving a vector, or you can use sums of the
// named direction vectors described above. Below we show all of the corner sets you can
// describe with sums of the direction vectors.
// describe with sums of the direction vectors and then we show some examples of combining
// corner set descriptors.
// Figure(3D,Big,NoScales,VPD=300): Vectors pointing toward a corner select that corner.
// ydistribute(55) {
// xdistribute(35) {
@ -234,7 +242,7 @@
// _show_corners(corners="ALL");
// _show_corners(corners="NONE");
// }
// Figure(3D,Big,NoScales,VPD=300): Next are some examples showing how you can combine corner descriptors to obtain different corner sets. The default value for `corners` is `"ALL"`, the set of all corners. The default value for `except` is the empty set, meaning no corners are removed. You can specify corner sets numerically or by adding together named directions. The third example shows a list of two corner specifications, giving all the corners on the front face or the right face.
// Figure(3D,Big,NoScales,VPD=300): Next are some examples showing how you can combine corner descriptors to obtain different corner sets. You can specify corner sets numerically or by adding together named directions. The third example shows a list of two corner specifications, giving all the corners on the front face or the right face.
// xdistribute(52){
// _show_corners(_corners([1,-1,-1]),toplabel=["corners=[1,-1,-1]"]);
// _show_corners(_corners(BOT+RIGHT+FRONT),toplabel=["corners=BOT+RIGHT+FRONT"]);
@ -425,6 +433,7 @@ function _normalize_edges(v) = [for (ax=v) [for (edge=ax) edge>0? 1 : 0]];
/// See Also: EDGES_NONE, EDGES_ALL
///
function _edges(v, except=[]) =
v==[] ? EDGES_NONE :
(is_string(v) || is_vector(v) || _is_edge_array(v))? _edges([v], except=except) :
(is_string(except) || is_vector(except) || _is_edge_array(except))? _edges(v, except=[except]) :
except==[]? _normalize_edges(sum([for (x=v) _edge_set(x)])) :
@ -559,6 +568,7 @@ function _corner_set(v) =
/// from the returned corners array. If either argument only has a single corner
/// set descriptor, you do not have to pass it in a list.
function _corners(v, except=[]) =
v==[] ? CORNERS_NONE :
(is_string(v) || is_vector(v) || _is_corner_array(v))? _corners([v], except=except) :
(is_string(except) || is_vector(except) || _is_corner_array(except))? _corners(v, except=[except]) :
except==[]? _normalize_corners(sum([for (x=v) _corner_set(x)])) :

View file

@ -980,7 +980,7 @@ function bevel_gear(
[gear_pts, ((i+1)%teeth)*face_pts, (i+1)*face_pts-1]
]
],
vnf1 = vnf_merge([
vnf1 = vnf_join([
[
[each top_verts, [0,0,top_verts[0].z]],
top_faces
@ -1451,7 +1451,7 @@ function worm_gear(
]
],
sides_vnf = vnf_vertex_array(profiles, caps=false, col_wrap=true, style="min_edge"),
vnf1 = vnf_merge([
vnf1 = vnf_join([
[
[each top_verts, [0,0,top_verts[0].z]],
[for (x=top_faces) reverse(x)]

View file

@ -674,7 +674,7 @@ function linear_sweep(region, height=1, center, twist=0, scale=1, slices,
rot(twist, p=scale([scale,scale],p=path))
]
],
vnf = vnf_merge([
vnf = vnf_join([
for (rgn = regions)
for (pathnum = idx(rgn)) let(
p = cleanup_path(rgn[pathnum]),

View file

@ -1962,7 +1962,7 @@ function rounded_prism(bottom, top, joint_bot=0, joint_top=0, joint_sides=0, k_b
"Roundovers interfere with each other on bottom face: either input is self intersecting or top joint length is too large")
assert(debug || (verify_vert==[] && verify_horiz==[]), "Curvature continuity failed")
let(
vnf = vnf_merge([ each column(top_samples,0),
vnf = vnf_join([ each column(top_samples,0),
each column(bot_samples,0),
for(pts=edge_points) vnf_vertex_array(pts),
debug ? vnf_from_polygons(faces)

View file

@ -2486,7 +2486,7 @@ function heightfield(data, size=[100,100], bottom=-20, maxz=100, xrange=[-1:0.04
]
]
],
vnf = vnf_merge([
vnf = vnf_join([
vnf_vertex_array(verts, style=style, reverse=true),
vnf_vertex_array([
verts[0],

View file

@ -492,7 +492,7 @@ function skin(profiles, slices, refine=1, method="direct", sampling, caps, close
)
subdivide_and_slice(pair,slices[i], nsamples, method=sampling)]
)
vnf_merge(cleanup=false,
vnf_join(
[for(i=idx(full_list))
vnf_vertex_array(full_list[i], cap1=i==0 && fullcaps[0], cap2=i==len(full_list)-1 && fullcaps[1],
col_wrap=true, style=style)]);
@ -1120,7 +1120,7 @@ function sweep(shape, transforms, closed=false, caps, style="min_edge") =
if (fullcaps[1]) vnf_from_region(rgn, transform=last(transforms)),
],
],
vnf = vnf_merge(vnfs)
vnf = vnf_join(vnfs)
) vnf :
assert(len(shape)>=3, "shape must be a path of at least 3 non-colinear points")
vnf_vertex_array([for(i=[0:len(transforms)-(closed?0:1)]) apply(transforms[i%len(transforms)],path3d(shape))],

View file

@ -971,7 +971,7 @@ module generic_threaded_rod(
style = higang1>0 || higang2>0 ? "quincunx" : "min_edge";
thread_vnfs = vnf_merge([
thread_vnfs = vnf_join([
// Main thread faces
for (i=[0:1:starts-1])
zrot(i*360/starts, p=vnf_vertex_array(thread_verts, reverse=left_handed, style=style)),

View file

@ -217,14 +217,14 @@ function vnf_vertex_array(
// Example(3D): Merging two VNFs to construct a cone with one point length change between rows.
// pts1 = [for(z=[0:10]) path3d(arc(3+z,r=z/2+1, angle=[0,180]),10-z)];
// pts2 = [for(z=[0:10]) path3d(arc(3+z,r=z/2+1, angle=[180,360]),10-z)];
// vnf = vnf_merge([vnf_tri_array(pts1),
// vnf = vnf_join([vnf_tri_array(pts1),
// vnf_tri_array(pts2)]);
// color("green")vnf_wireframe(vnf,width=0.1);
// vnf_polyhedron(vnf);
// Example(3D): Cone with length change two between rows
// pts1 = [for(z=[0:1:10]) path3d(arc(3+2*z,r=z/2+1, angle=[0,180]),10-z)];
// pts2 = [for(z=[0:1:10]) path3d(arc(3+2*z,r=z/2+1, angle=[180,360]),10-z)];
// vnf = vnf_merge([vnf_tri_array(pts1),
// vnf = vnf_join([vnf_tri_array(pts1),
// vnf_tri_array(pts2)]);
// color("green")vnf_wireframe(vnf,width=0.1);
// vnf_polyhedron(vnf);
@ -284,22 +284,20 @@ function vnf_tri_array(points, row_wrap=false, reverse=false) =
// Function: vnf_merge()
// Function: vnf_join()
// Usage:
// vnf = vnf_merge([VNF, VNF, VNF, ...], [cleanup],[eps]);
// vnf = vnf_join([VNF, VNF, VNF, ...]);
// Description:
// Given a list of VNF structures, merges them all into a single VNF structure.
// When cleanup=true, it consolidates all duplicate vertices with a tolerance `eps`,
// and eliminates any faces with fewer than 3 vertices.
// (Unreferenced vertices of the input VNFs are not dropped.)
// Combines all the points of the input VNFs and labels the faces appropriately.
// All the points in the input VNFs will appear in the output, even if they are
// duplicates of each other. It is valid to repeat points in a VNF, but if you
// with to remove the duplicates that will occur along joined edges, use {{vnf_merge_points()}}.
// Arguments:
// vnfs = a list of the VNFs to merge in one VNF.
// cleanup = when true, consolidates the duplicate vertices of the merge. Default: false
// eps = the tolerance in finding duplicates when cleanup=true. Default: EPSILON
function vnf_merge(vnfs, cleanup=false, eps=EPSILON) =
is_vnf(vnfs) ? vnf_merge([vnfs], cleanup, eps) :
assert( is_vnf_list(vnfs) , "Improper vnf or vnf list")
len(vnfs)==1 ? (cleanup ? _vnf_cleanup(vnfs[0][0],vnfs[0][1],eps) : vnfs[0])
// vnfs = a list of the VNFs to joint into one VNF.
function vnf_join(vnfs) =
assert(is_vnf_list(vnfs) , "Input must be a list of VNFs")
len(vnfs)==1 ? vnfs[0]
:
let (
offs = cumsum([ 0, for (vnf = vnfs) len(vnf[0]) ]),
@ -315,18 +313,30 @@ function vnf_merge(vnfs, cleanup=false, eps=EPSILON) =
offs[i] + j ]
]
)
cleanup? _vnf_cleanup(verts,faces,eps) : [verts,faces];
[verts,faces];
function _vnf_cleanup(verts,faces,eps) =
// Function: vnf_merge_points()
// Usage:
// new_vnf = vnf_merge_points(vnf, [eps]);
// Description:
// Given a VNF, consolidates all duplicate vertices with a tolerance `eps`, relabeling the faces as necessary,
// and eliminating any face with fewer than 3 vertices. Unreferenced vertices of the input VNF are not dropped.
// To remove such vertices uses {{vnf_drop_unused_points()}}.
// Arguments:
// vnf = a VNF to consolidate
// eps = the tolerance in finding duplicates. Default: EPSILON
function vnf_merge_points(vnf,eps=EPSILON) =
let(
verts = vnf[0],
dedup = vector_search(verts,eps,verts), // collect vertex duplicates
map = [for(i=idx(verts)) min(dedup[i]) ], // remap duplic vertices
offset = cumsum([for(i=idx(verts)) map[i]==i ? 0 : 1 ]), // remaping face vertex offsets
map2 = list(idx(verts))-offset, // map old vertex indices to new indices
nverts = [for(i=idx(verts)) if(map[i]==i) verts[i] ], // this doesn't eliminate unreferenced vertices
nfaces =
[ for(face=faces)
[ for(face=vnf[1])
let(
nface = [ for(vi=face) map2[map[vi]] ],
dface = [for (i=idx(nface))
@ -346,7 +356,7 @@ function _vnf_cleanup(verts,faces,eps) =
// Given a list of 3d polygons, produces a VNF containing those polygons.
// It is up to the caller to make sure that the points are in the correct order to make the face
// normals point outwards. No checking for duplicate vertices is done. If you want to
// remove duplicate vertices use vnf_merge with the cleanup option.
// remove duplicate vertices use {{vnf_merge_points()}}.
// Arguments:
// polygons = The list of 3d polygons to turn into a VNF
function vnf_from_polygons(polygons) =
@ -533,7 +543,7 @@ function vnf_from_region(region, transform, reverse=false) =
faceidxs = reverse? [for (i=[len(face)-1:-1:0]) i] : [for (i=[0:1:len(face)-1]) i]
) [face, [faceidxs]]
],
outvnf = vnf_merge(vnfs)
outvnf = vnf_join(vnfs)
)
vnf_triangulate(outvnf);
@ -673,7 +683,7 @@ function vnf_slice(vnf,dir,cuts) =
faces = [for(face=vnf[1]) select(vert,face)],
poly_list = _slice_3dpolygons(faces, dir, cuts)
)
vnf_merge([vnf_from_polygons(poly_list)], cleanup=true);
vnf_merge_points(vnf_from_polygons(poly_list));
function _split_polygon_at_x(poly, x) =
@ -777,7 +787,7 @@ function _slice_3dpolygons(polys, dir, cuts) =
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#orient). Default: `UP`
module vnf_polyhedron(vnf, convexity=2, extent=true, cp=[0,0,0], anchor="origin", spin=0, orient=UP) {
vnf = is_vnf_list(vnf)? vnf_merge(vnf) : vnf;
vnf = is_vnf_list(vnf)? vnf_join(vnf) : vnf;
cp = is_def(cp) ? cp : centroid(vnf);
attachable(anchor,spin,orient, vnf=vnf, extent=extent, cp=cp) {
polyhedron(vnf[0], vnf[1], convexity=convexity);
@ -943,7 +953,7 @@ function vnf_halfspace(plane, vnf, closed=true) =
faceregion = [for(path=newpaths) path2d(apply(M,select(newvert,path)))],
facevnf = vnf_from_region(faceregion,transform=rot_inverse(M),reverse=true)
)
vnf_merge([[newvert, faces_edges_vertices[0]], facevnf]);
vnf_join([[newvert, faces_edges_vertices[0]], facevnf]);
function _assemble_paths(vertices, edges, paths=[],i=0) =
@ -1315,7 +1325,7 @@ module vnf_debug(vnf, faces=true, vertices=true, opacity=0.5, size=1, convexity=
// path3d(square(100,center=true),0),
// path3d(square(100,center=true),100),
// ], slices=0, caps=false);
// vnf = vnf_merge([vnf1, vnf_from_polygons([
// vnf = vnf_join([vnf1, vnf_from_polygons([
// [[-50,-50, 0], [ 50, 50, 0], [-50, 50, 0]],
// [[-50,-50, 0], [ 50,-50, 0], [ 50, 50, 0]],
// [[-50,-50,100], [-50, 50,100], [ 50, 50,100]],
@ -1327,7 +1337,7 @@ module vnf_debug(vnf, faces=true, vertices=true, opacity=0.5, size=1, convexity=
// path3d(square(100,center=true),0),
// path3d(square(100,center=true),100),
// ], slices=0, caps=false);
// vnf = vnf_merge([vnf1, vnf_from_polygons([
// vnf = vnf_join([vnf1, vnf_from_polygons([
// [[-50,-50,0], [50,50,0], [-50,50,0]],
// [[-50,-50,0], [50,-50,0], [50,50,0]],
// [[-50,-50,100], [-50,50,100], [0,50,100]],
@ -1337,7 +1347,7 @@ module vnf_debug(vnf, faces=true, vertices=true, opacity=0.5, size=1, convexity=
// ])]);
// vnf_validate(vnf);
// Example: FACE_ISECT Errors; Faces Intersect
// vnf = vnf_merge([
// vnf = vnf_join([
// vnf_triangulate(linear_sweep(square(100,center=true), height=100)),
// move([75,35,30],p=vnf_triangulate(linear_sweep(square(100,center=true), height=100)))
// ]);
@ -1351,7 +1361,7 @@ module vnf_debug(vnf, faces=true, vertices=true, opacity=0.5, size=1, convexity=
function vnf_validate(vnf, show_warns=true, check_isects=false) =
assert(is_vnf(vnf), "Invalid VNF")
let(
vnf = vnf_merge(vnf, cleanup=true),
vnf = vnf_merge_points(vnf),
varr = vnf[0],
faces = vnf[1],
lvarr = len(varr),