mirror of
https://github.com/revarbat/BOSL2.git
synced 2025-08-17 22:21:27 +02:00
vnf doc tweaks and cleanup
remove vnf args for chaining vnf_merge pass through if you give just one vnf vnf_vertex_array no longer calls merge vnf_tri_array removes degenerate faces and no longer calls merge (with cleanup)
This commit is contained in:
79
vnf.scad
79
vnf.scad
@@ -16,17 +16,17 @@
|
|||||||
// You can construct a `polyhedron()` in parts by describing each part in a self-contained VNF, then
|
// You can construct a `polyhedron()` in parts by describing each part in a self-contained VNF, then
|
||||||
// merge the various VNFs to get the completed polyhedron vertex list and faces.
|
// merge the various VNFs to get the completed polyhedron vertex list and faces.
|
||||||
|
|
||||||
// Constant: EMPTY_VNF
|
/// Constant: EMPTY_VNF
|
||||||
// Description:
|
/// Description:
|
||||||
// The empty VNF data structure. Equal to `[[],[]]`.
|
/// The empty VNF data structure. Equal to `[[],[]]`.
|
||||||
EMPTY_VNF = [[],[]]; // The standard empty VNF with no vertices or faces.
|
EMPTY_VNF = [[],[]]; // The standard empty VNF with no vertices or faces.
|
||||||
|
|
||||||
|
|
||||||
// Function: vnf_vertex_array()
|
// Function: vnf_vertex_array()
|
||||||
// Usage:
|
// Usage:
|
||||||
// vnf = vnf_vertex_array(points, [caps], [cap1], [cap2], [style], [reverse], [col_wrap], [row_wrap], [vnf]);
|
// vnf = vnf_vertex_array(points, [caps], [cap1], [cap2], [style], [reverse], [col_wrap], [row_wrap]);
|
||||||
// Description:
|
// Description:
|
||||||
// Creates a VNF structure from a vertex list, by dividing the vertices into columns and rows,
|
// Creates a VNF structure from a rectangular vertex list, by dividing the vertices into columns and rows,
|
||||||
// adding faces to tile the surface. You can optionally have faces added to wrap the last column
|
// adding faces to tile the surface. You can optionally have faces added to wrap the last column
|
||||||
// back to the first column, or wrap the last row to the first. Endcaps can be added to either
|
// back to the first column, or wrap the last row to the first. Endcaps can be added to either
|
||||||
// the first and/or last rows. The style parameter determines how the quadrilaterals are divided into
|
// the first and/or last rows. The style parameter determines how the quadrilaterals are divided into
|
||||||
@@ -34,17 +34,18 @@ EMPTY_VNF = [[],[]]; // The standard empty VNF with no vertices or faces.
|
|||||||
// is the uniform subdivision in the other (alternate) direction. The "min_edge" style picks the shorter edge to
|
// is the uniform subdivision in the other (alternate) direction. The "min_edge" style picks the shorter edge to
|
||||||
// subdivide for each quadrilateral, so the division may not be uniform across the shape. The "quincunx" style
|
// subdivide for each quadrilateral, so the division may not be uniform across the shape. The "quincunx" style
|
||||||
// adds a vertex in the center of each quadrilateral and creates four triangles, and the "convex" and "concave" styles
|
// adds a vertex in the center of each quadrilateral and creates four triangles, and the "convex" and "concave" styles
|
||||||
// chooses the locally convex/concave subdivision.
|
// chooses the locally convex/concave subdivision. Degenerate faces
|
||||||
|
// are not included in the output, but if this results in unused vertices they will still appear in the output.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// points = A list of vertices to divide into columns and rows.
|
// points = A list of vertices to divide into columns and rows.
|
||||||
|
// ---
|
||||||
// caps = If true, add endcap faces to the first AND last rows.
|
// caps = If true, add endcap faces to the first AND last rows.
|
||||||
// cap1 = If true, add an endcap face to the first row.
|
// cap1 = If true, add an endcap face to the first row.
|
||||||
// cap2 = If true, add an endcap face to the last row.
|
// cap2 = If true, add an endcap face to the last row.
|
||||||
// col_wrap = If true, add faces to connect the last column to the first.
|
// col_wrap = If true, add faces to connect the last column to the first.
|
||||||
// row_wrap = If true, add faces to connect the last row to the first.
|
// row_wrap = If true, add faces to connect the last row to the first.
|
||||||
// reverse = If true, reverse all face normals.
|
// reverse = If true, reverse all face normals.
|
||||||
// style = The style of subdividing the quads into faces. Valid options are "default", "alt", "min_edge", "quincunx","convex" and "concave".
|
// style = The style of subdividing the quads into faces. Valid options are "default", "alt", "min_edge", "quincunx", "convex" and "concave".
|
||||||
// vnf = If given, add all the vertices and faces to this existing VNF structure.
|
|
||||||
// Example(3D):
|
// Example(3D):
|
||||||
// vnf = vnf_vertex_array(
|
// vnf = vnf_vertex_array(
|
||||||
// points=[
|
// points=[
|
||||||
@@ -104,12 +105,12 @@ function vnf_vertex_array(
|
|||||||
col_wrap=false,
|
col_wrap=false,
|
||||||
row_wrap=false,
|
row_wrap=false,
|
||||||
reverse=false,
|
reverse=false,
|
||||||
style="default",
|
style="default"
|
||||||
vnf=EMPTY_VNF
|
|
||||||
) =
|
) =
|
||||||
assert(!(any([caps,cap1,cap2]) && !col_wrap), "col_wrap must be true if caps are requested")
|
assert(!(any([caps,cap1,cap2]) && !col_wrap), "col_wrap must be true if caps are requested")
|
||||||
assert(!(any([caps,cap1,cap2]) && row_wrap), "Cannot combine caps with row_wrap")
|
assert(!(any([caps,cap1,cap2]) && row_wrap), "Cannot combine caps with row_wrap")
|
||||||
assert(in_list(style,["default","alt","quincunx", "convex","concave", "min_edge"]))
|
assert(in_list(style,["default","alt","quincunx", "convex","concave", "min_edge"]))
|
||||||
|
assert(is_matrix(points[0], n=3),"Point array has the wrong shape or points are not 3d")
|
||||||
assert(is_consistent(points), "Non-rectangular or invalid point array")
|
assert(is_consistent(points), "Non-rectangular or invalid point array")
|
||||||
let(
|
let(
|
||||||
pts = flatten(points),
|
pts = flatten(points),
|
||||||
@@ -117,7 +118,7 @@ function vnf_vertex_array(
|
|||||||
rows = len(points),
|
rows = len(points),
|
||||||
cols = len(points[0])
|
cols = len(points[0])
|
||||||
)
|
)
|
||||||
rows<=1 || cols<=1 ? vnf :
|
rows<=1 || cols<=1 ? EMPTY_VNF :
|
||||||
let(
|
let(
|
||||||
cap1 = first_defined([cap1,caps,false]),
|
cap1 = first_defined([cap1,caps,false]),
|
||||||
cap2 = first_defined([cap2,caps,false]),
|
cap2 = first_defined([cap2,caps,false]),
|
||||||
@@ -134,13 +135,10 @@ function vnf_vertex_array(
|
|||||||
i4 = ((r+0)%rows)*cols + ((c+1)%cols)
|
i4 = ((r+0)%rows)*cols + ((c+1)%cols)
|
||||||
)
|
)
|
||||||
mean([pts[i1], pts[i2], pts[i3], pts[i4]])
|
mean([pts[i1], pts[i2], pts[i3], pts[i4]])
|
||||||
]
|
],
|
||||||
)
|
allfaces = [
|
||||||
vnf_merge(cleanup=false, [
|
if (cap1) count(cols,reverse=!reverse),
|
||||||
vnf,
|
if (cap2) count(cols,(rows-1)*cols, reverse=reverse),
|
||||||
[
|
|
||||||
verts,
|
|
||||||
[
|
|
||||||
for (r = [0:1:rowcnt-1], c=[0:1:colcnt-1])
|
for (r = [0:1:rowcnt-1], c=[0:1:colcnt-1])
|
||||||
each
|
each
|
||||||
let(
|
let(
|
||||||
@@ -189,11 +187,9 @@ function vnf_vertex_array(
|
|||||||
rfaces = reverse? [for (face=culled_faces) reverse(face)] : culled_faces
|
rfaces = reverse? [for (face=culled_faces) reverse(face)] : culled_faces
|
||||||
)
|
)
|
||||||
rfaces,
|
rfaces,
|
||||||
if (cap1) count(cols,reverse=!reverse),
|
|
||||||
if (cap2) count(cols,(rows-1)*cols, reverse=reverse)
|
|
||||||
]
|
]
|
||||||
]
|
)
|
||||||
]);
|
[verts,allfaces];
|
||||||
|
|
||||||
|
|
||||||
// Function: vnf_tri_array()
|
// Function: vnf_tri_array()
|
||||||
@@ -202,7 +198,8 @@ function vnf_vertex_array(
|
|||||||
// Description:
|
// Description:
|
||||||
// Produces a vnf from an array of points where each row length can differ from the adjacent rows by up to 2 in length. This enables
|
// Produces a vnf from an array of points where each row length can differ from the adjacent rows by up to 2 in length. This enables
|
||||||
// the construction of triangular VNF patches. The resulting VNF can be wrapped along the rows by setting `row_wrap` to true.
|
// the construction of triangular VNF patches. The resulting VNF can be wrapped along the rows by setting `row_wrap` to true.
|
||||||
// You cannot wrap columns: if you need to do that you'll need to combine two VNF arrays that share edges.
|
// You cannot wrap columns: if you need to do that you'll need to combine two VNF arrays that share edges. Degenerate faces
|
||||||
|
// are not included in the output, but if this results in unused vertices they will still appear in the output.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// points = List of point lists for each row
|
// points = List of point lists for each row
|
||||||
// row_wrap = If true then add faces connecting the first row and last row. These rows must differ by at most 2 in length.
|
// row_wrap = If true then add faces connecting the first row and last row. These rows must differ by at most 2 in length.
|
||||||
@@ -237,7 +234,7 @@ function vnf_vertex_array(
|
|||||||
// vnf = vnf_tri_array(pts);
|
// vnf = vnf_tri_array(pts);
|
||||||
// vnf_wireframe(vnf,width=0.1);
|
// vnf_wireframe(vnf,width=0.1);
|
||||||
// color("red")move_copies(flatten(pts)) sphere(r=.15,$fn=9);
|
// color("red")move_copies(flatten(pts)) sphere(r=.15,$fn=9);
|
||||||
function vnf_tri_array(points, row_wrap=false, reverse=false, vnf=EMPTY_VNF) =
|
function vnf_tri_array(points, row_wrap=false, reverse=false) =
|
||||||
let(
|
let(
|
||||||
lens = [for(row=points) len(row)],
|
lens = [for(row=points) len(row)],
|
||||||
rowstarts = [0,each cumsum(lens)],
|
rowstarts = [0,each cumsum(lens)],
|
||||||
@@ -273,8 +270,17 @@ function vnf_tri_array(points, row_wrap=false, reverse=false, vnf=EMPTY_VNF) =
|
|||||||
for(j=[count:1:select(lens,i+1)]) reverse ? [ j+nextrow-1, j+rowstart+1, j+rowstart]: [ j+nextrow-1, j+rowstart, j+rowstart+1],
|
for(j=[count:1:select(lens,i+1)]) reverse ? [ j+nextrow-1, j+rowstart+1, j+rowstart]: [ j+nextrow-1, j+rowstart, j+rowstart+1],
|
||||||
] :
|
] :
|
||||||
assert(false,str("Unsupported row length difference of ",delta, " between row ",i," and ",(i+1)%len(points)))
|
assert(false,str("Unsupported row length difference of ",delta, " between row ",i," and ",(i+1)%len(points)))
|
||||||
])
|
],
|
||||||
vnf_merge(cleanup=true, [vnf, [flatten(points), faces]]);
|
verts = flatten(points),
|
||||||
|
culled_faces=
|
||||||
|
[for(face=faces)
|
||||||
|
if (norm(verts[face[0]]-verts[face[1]])>EPSILON &&
|
||||||
|
norm(verts[face[1]]-verts[face[2]])>EPSILON &&
|
||||||
|
norm(verts[face[2]]-verts[face[0]])>EPSILON)
|
||||||
|
face
|
||||||
|
]
|
||||||
|
)
|
||||||
|
[flatten(points), culled_faces];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -292,7 +298,9 @@ function vnf_tri_array(points, row_wrap=false, reverse=false, vnf=EMPTY_VNF) =
|
|||||||
// eps = the tolerance in finding duplicates when cleanup=true. Default: EPSILON
|
// eps = the tolerance in finding duplicates when cleanup=true. Default: EPSILON
|
||||||
function vnf_merge(vnfs, cleanup=false, eps=EPSILON) =
|
function vnf_merge(vnfs, cleanup=false, eps=EPSILON) =
|
||||||
is_vnf(vnfs) ? vnf_merge([vnfs], cleanup, eps) :
|
is_vnf(vnfs) ? vnf_merge([vnfs], cleanup, eps) :
|
||||||
assert( is_vnf_list(vnfs) , "Improper vnf or vnf list")
|
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])
|
||||||
|
:
|
||||||
let (
|
let (
|
||||||
offs = cumsum([ 0, for (vnf = vnfs) len(vnf[0]) ]),
|
offs = cumsum([ 0, for (vnf = vnfs) len(vnf[0]) ]),
|
||||||
verts = [for (vnf=vnfs) each vnf[0]],
|
verts = [for (vnf=vnfs) each vnf[0]],
|
||||||
@@ -307,7 +315,11 @@ function vnf_merge(vnfs, cleanup=false, eps=EPSILON) =
|
|||||||
offs[i] + j ]
|
offs[i] + j ]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
! cleanup ? [verts, faces] :
|
cleanup? _vnf_cleanup(verts,faces,eps) : [verts,faces];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function _vnf_cleanup(verts,faces,eps) =
|
||||||
let(
|
let(
|
||||||
dedup = vector_search(verts,eps,verts), // collect vertex duplicates
|
dedup = vector_search(verts,eps,verts), // collect vertex duplicates
|
||||||
map = [for(i=idx(verts)) min(dedup[i]) ], // remap duplic vertices
|
map = [for(i=idx(verts)) min(dedup[i]) ], // remap duplic vertices
|
||||||
@@ -405,7 +417,7 @@ function _cleave_connected_region(region) =
|
|||||||
|
|
||||||
// Function: vnf_from_region()
|
// Function: vnf_from_region()
|
||||||
// Usage:
|
// Usage:
|
||||||
// vnf = vnf_from_region(region, [transform], [reverse], [vnf]);
|
// vnf = vnf_from_region(region, [transform], [reverse]);
|
||||||
// Description:
|
// Description:
|
||||||
// Given a (two-dimensional) region, applies the given transformation matrix to it and makes a (three-dimensional) triangulated VNF of
|
// Given a (two-dimensional) region, applies the given transformation matrix to it and makes a (three-dimensional) triangulated VNF of
|
||||||
// faces for that region, reversed if desired.
|
// faces for that region, reversed if desired.
|
||||||
@@ -413,7 +425,6 @@ function _cleave_connected_region(region) =
|
|||||||
// region = The region to conver to a vnf.
|
// region = The region to conver to a vnf.
|
||||||
// transform = If given, a transformation matrix to apply to the faces generated from the region. Default: No transformation applied.
|
// transform = If given, a transformation matrix to apply to the faces generated from the region. Default: No transformation applied.
|
||||||
// reverse = If true, reverse the normals of the faces generated from the region. An untransformed region will have face normals pointing `UP`. Default: false
|
// reverse = If true, reverse the normals of the faces generated from the region. An untransformed region will have face normals pointing `UP`. Default: false
|
||||||
// vnf = If given, the faces are added to this VNF. Default: `EMPTY_VNF`
|
|
||||||
// Example(3D):
|
// Example(3D):
|
||||||
// region = [square([20,10],center=true),
|
// region = [square([20,10],center=true),
|
||||||
// right(5,square(4,center=true)),
|
// right(5,square(4,center=true)),
|
||||||
@@ -422,11 +433,10 @@ function _cleave_connected_region(region) =
|
|||||||
// color("gray")down(.125)
|
// color("gray")down(.125)
|
||||||
// linear_extrude(height=.125)region(region);
|
// linear_extrude(height=.125)region(region);
|
||||||
// vnf_wireframe(vnf,width=.25);
|
// vnf_wireframe(vnf,width=.25);
|
||||||
function vnf_from_region(region, transform, reverse=false, vnf=EMPTY_VNF) =
|
function vnf_from_region(region, transform, reverse=false) =
|
||||||
let (
|
let (
|
||||||
regions = region_parts(force_region(region)),
|
regions = region_parts(force_region(region)),
|
||||||
vnfs = [
|
vnfs = [
|
||||||
if (vnf != EMPTY_VNF) vnf,
|
|
||||||
for (rgn = regions) let(
|
for (rgn = regions) let(
|
||||||
cleaved = path3d(_cleave_connected_region(rgn)),
|
cleaved = path3d(_cleave_connected_region(rgn)),
|
||||||
face = is_undef(transform)? cleaved : apply(transform,cleaved),
|
face = is_undef(transform)? cleaved : apply(transform,cleaved),
|
||||||
@@ -684,11 +694,11 @@ module vnf_polyhedron(vnf, convexity=2, extent=true, cp=[0,0,0], anchor="origin"
|
|||||||
|
|
||||||
// Module: vnf_wireframe()
|
// Module: vnf_wireframe()
|
||||||
// Usage:
|
// Usage:
|
||||||
// vnf_wireframe(vnf, <r|d>);
|
// vnf_wireframe(vnf, [width]);
|
||||||
// Description:
|
// Description:
|
||||||
// Given a VNF, creates a wire frame ball-and-stick model of the polyhedron with a cylinder for
|
// Given a VNF, creates a wire frame ball-and-stick model of the polyhedron with a cylinder for
|
||||||
// each edge and a sphere at each vertex. The width parameter specifies the width of the sticks
|
// each edge and a sphere at each vertex. The width parameter specifies the width of the sticks
|
||||||
// that form the wire frame.
|
// that form the wire frame and the diameter of the balls.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// vnf = A vnf structure
|
// vnf = A vnf structure
|
||||||
// width = width of the cylinders forming the wire frame. Default: 1
|
// width = width of the cylinders forming the wire frame. Default: 1
|
||||||
@@ -930,6 +940,7 @@ function _triangulate_planar_convex_polygons(polys) =
|
|||||||
// Arguments:
|
// Arguments:
|
||||||
// vnf = The original VNF to bend.
|
// vnf = The original VNF to bend.
|
||||||
// r = If given, the radius where the size of the original shape is the same as in the original.
|
// r = If given, the radius where the size of the original shape is the same as in the original.
|
||||||
|
// ---
|
||||||
// d = If given, the diameter where the size of the original shape is the same as in the original.
|
// d = If given, the diameter where the size of the original shape is the same as in the original.
|
||||||
// axis = The axis to wrap around. "X", "Y", or "Z". Default: "Z"
|
// axis = The axis to wrap around. "X", "Y", or "Z". Default: "Z"
|
||||||
// Example(3D):
|
// Example(3D):
|
||||||
|
Reference in New Issue
Block a user