mirror of
https://github.com/revarbat/BOSL2.git
synced 2025-08-06 22:16:41 +02:00
Speed improvement for vnf_vertex_array by changing deduplicate
testing. Add "min_edge" style to vnf vertex array. eliminate _skin_core, replace with vnf_vertex_array, add style option to all modules/functions. fix bug in path_normals (not normalized)
This commit is contained in:
@@ -380,7 +380,7 @@ function path_normals(path, tangents, closed=false) =
|
|||||||
dim == 2 ? [tangents[i].y,-tangents[i].x]
|
dim == 2 ? [tangents[i].y,-tangents[i].x]
|
||||||
: let(v=cross(cross(pts[1]-pts[0], pts[2]-pts[0]),tangents[i]))
|
: let(v=cross(cross(pts[1]-pts[0], pts[2]-pts[0]),tangents[i]))
|
||||||
assert(norm(v)>EPSILON, "3D path contains collinear points")
|
assert(norm(v)>EPSILON, "3D path contains collinear points")
|
||||||
v
|
unit(v)
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
115
skin.scad
115
skin.scad
@@ -13,9 +13,9 @@
|
|||||||
|
|
||||||
// Function&Module: skin()
|
// Function&Module: skin()
|
||||||
// Usage: As module:
|
// Usage: As module:
|
||||||
// skin(profiles, slices, <z=>, <refine=>, <method=>, <sampling=>, <caps=>, <closed=>, <convexity=>, <anchor=>,<cp=>,<spin=>,<orient=>,<extent=>) <attachments>;
|
// skin(profiles, slices, <z=>, <refine=>, <method=>, <sampling=>, <caps=>, <closed=>, <style=>, <convexity=>, <anchor=>,<cp=>,<spin=>,<orient=>,<extent=>) <attachments>;
|
||||||
// Usage: As function:
|
// Usage: As function:
|
||||||
// vnf = skin(profiles, slices, <z=>, <refine=>, <method=>, <sampling=>, <caps=>, <closed=>);
|
// vnf = skin(profiles, slices, <z=>, <refine=>, <method=>, <sampling=>, <caps=>, <closed=>, <style=>);
|
||||||
// Description:
|
// Description:
|
||||||
// Given a list of two or more path `profiles` in 3d space, produces faces to skin a surface between
|
// Given a list of two or more path `profiles` in 3d space, produces faces to skin a surface between
|
||||||
// the profiles. Optionally the first and last profiles can have endcaps, or the first and last profiles
|
// the profiles. Optionally the first and last profiles can have endcaps, or the first and last profiles
|
||||||
@@ -152,6 +152,7 @@
|
|||||||
// orient = Vector to rotate top towards after spin (module only)
|
// orient = Vector to rotate top towards after spin (module only)
|
||||||
// extent = use extent method for computing anchors. (module only) Default: false
|
// extent = use extent method for computing anchors. (module only) Default: false
|
||||||
// cp = set centerpoint for anchor computation. (module only) Default: object centroid
|
// cp = set centerpoint for anchor computation. (module only) Default: object centroid
|
||||||
|
// style = vnf_vertex_array style. Default: "min_edge"
|
||||||
// Example:
|
// Example:
|
||||||
// skin([octagon(4), circle($fn=70,r=2)], z=[0,3], slices=10);
|
// skin([octagon(4), circle($fn=70,r=2)], z=[0,3], slices=10);
|
||||||
// Example: Rotating the pentagon place the zero index at different locations, giving a twist
|
// Example: Rotating the pentagon place the zero index at different locations, giving a twist
|
||||||
@@ -376,10 +377,10 @@
|
|||||||
// stroke(zrot(30, p=yscale(0.5, p=circle(d=120))),width=10,closed=true);
|
// stroke(zrot(30, p=yscale(0.5, p=circle(d=120))),width=10,closed=true);
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
module skin(profiles, slices, refine=1, method="direct", sampling, caps, closed=false, z, convexity=10,
|
module skin(profiles, slices, refine=1, method="direct", sampling, caps, closed=false, z, style="min_edge", convexity=10,
|
||||||
anchor="origin",cp,spin=0, orient=UP, extent=false)
|
anchor="origin",cp,spin=0, orient=UP, extent=false)
|
||||||
{
|
{
|
||||||
vnf = skin(profiles, slices, refine, method, sampling, caps, closed, z);
|
vnf = skin(profiles, slices, refine, method, sampling, caps, closed, z, style);
|
||||||
attachable(anchor=anchor, spin=spin, orient=orient, vnf=vnf, extent=extent, cp=is_def(cp) ? cp : vnf_centroid(vnf))
|
attachable(anchor=anchor, spin=spin, orient=orient, vnf=vnf, extent=extent, cp=is_def(cp) ? cp : vnf_centroid(vnf))
|
||||||
{
|
{
|
||||||
vnf_polyhedron(vnf,convexity=convexity);
|
vnf_polyhedron(vnf,convexity=convexity);
|
||||||
@@ -388,7 +389,7 @@ module skin(profiles, slices, refine=1, method="direct", sampling, caps, closed=
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function skin(profiles, slices, refine=1, method="direct", sampling, caps, closed=false, z) =
|
function skin(profiles, slices, refine=1, method="direct", sampling, caps, closed=false, z, style="min_edge") =
|
||||||
assert(is_def(slices),"The slices argument must be specified.")
|
assert(is_def(slices),"The slices argument must be specified.")
|
||||||
assert(is_list(profiles) && len(profiles)>1, "Must provide at least two profiles")
|
assert(is_list(profiles) && len(profiles)>1, "Must provide at least two profiles")
|
||||||
let( bad = [for(i=idx(profiles)) if (!(is_path(profiles[i]) && len(profiles[i])>2)) i])
|
let( bad = [for(i=idx(profiles)) if (!(is_path(profiles[i]) && len(profiles[i])>2)) i])
|
||||||
@@ -483,61 +484,7 @@ function skin(profiles, slices, refine=1, method="direct", sampling, caps, close
|
|||||||
)
|
)
|
||||||
each subdivide_and_slice(pair,slices[i], nsamples, method=sampling)]
|
each subdivide_and_slice(pair,slices[i], nsamples, method=sampling)]
|
||||||
)
|
)
|
||||||
_skin_core(full_list, caps=fullcaps);
|
vnf_vertex_array(full_list, caps=fullcaps, col_wrap=true, style=style);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function _skin_core(profiles, caps) =
|
|
||||||
let(
|
|
||||||
vertices = [for (prof=profiles) each prof],
|
|
||||||
plens = [for (prof=profiles) len(prof)],
|
|
||||||
sidefaces = [
|
|
||||||
for(pidx=idx(profiles,e=-2))
|
|
||||||
let(
|
|
||||||
prof1 = profiles[pidx%len(profiles)],
|
|
||||||
prof2 = profiles[(pidx+1)%len(profiles)],
|
|
||||||
voff = default(sum([for (i=[0:1:pidx-1]) plens[i]]),0),
|
|
||||||
faces = [
|
|
||||||
for(
|
|
||||||
first = true,
|
|
||||||
finishing = false,
|
|
||||||
finished = false,
|
|
||||||
plen1 = len(prof1),
|
|
||||||
plen2 = len(prof2),
|
|
||||||
i=0, j=0, side=0;
|
|
||||||
|
|
||||||
!finished;
|
|
||||||
|
|
||||||
side =
|
|
||||||
let(
|
|
||||||
p1a = prof1[(i+0)%plen1],
|
|
||||||
p1b = prof1[(i+1)%plen1],
|
|
||||||
p2a = prof2[(j+0)%plen2],
|
|
||||||
p2b = prof2[(j+1)%plen2],
|
|
||||||
dist1 = norm(p1a-p2b),
|
|
||||||
dist2 = norm(p1b-p2a)
|
|
||||||
) (i==j) ? (dist1>dist2? 1 : 0) : (i<j ? 1 : 0) ,
|
|
||||||
p1 = voff + (i%plen1),
|
|
||||||
p2 = voff + (j%plen2) + plen1,
|
|
||||||
p3 = voff + (side? ((i+1)%plen1) : (((j+1)%plen2) + plen1)),
|
|
||||||
face = [p1, p3, p2],
|
|
||||||
i = i + (side? 1 : 0),
|
|
||||||
j = j + (side? 0 : 1),
|
|
||||||
first = false,
|
|
||||||
finished = finishing,
|
|
||||||
finishing = i>=plen1 && j>=plen2
|
|
||||||
) if (!first) face
|
|
||||||
]
|
|
||||||
) each faces
|
|
||||||
],
|
|
||||||
firstcap = !caps[0] ? [] : let(
|
|
||||||
prof1 = profiles[0]
|
|
||||||
) [[for (i=idx(prof1)) plens[0]-1-i]],
|
|
||||||
secondcap = !caps[1] ? [] : let(
|
|
||||||
prof2 = last(profiles),
|
|
||||||
eoff = sum(list_head(plens))
|
|
||||||
) [[for (i=idx(prof2)) eoff+i]]
|
|
||||||
) [vertices, concat(sidefaces,firstcap,secondcap)];
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -903,9 +850,9 @@ function associate_vertices(polygons, split, curpoly=0) =
|
|||||||
|
|
||||||
// Function&Module: sweep()
|
// Function&Module: sweep()
|
||||||
// Usage: As Module
|
// Usage: As Module
|
||||||
// sweep(shape, transforms, <closed>, <caps>, <convexity=>, <anchor=>, <spin=>, <orient=>, <extent=>) <attachments>;
|
// sweep(shape, transforms, <closed>, <caps>, <style>, <convexity=>, <anchor=>, <spin=>, <orient=>, <extent=>) <attachments>;
|
||||||
// Usage: As Function
|
// Usage: As Function
|
||||||
// vnf = sweep(shape, transforms, <closed>, <caps>);
|
// vnf = sweep(shape, transforms, <closed>, <caps>, <style>);
|
||||||
// Description:
|
// Description:
|
||||||
// The input `shape` must be a non-self-intersecting 2D polygon or region, and `transforms`
|
// The input `shape` must be a non-self-intersecting 2D polygon or region, and `transforms`
|
||||||
// is a list of 4x4 transformation matrices. The sweep algorithm applies each transformation in sequence
|
// is a list of 4x4 transformation matrices. The sweep algorithm applies each transformation in sequence
|
||||||
@@ -925,6 +872,7 @@ function associate_vertices(polygons, split, curpoly=0) =
|
|||||||
// transforms = list of 4x4 matrices to apply
|
// transforms = list of 4x4 matrices to apply
|
||||||
// closed = set to true to form a closed (torus) model. Default: false
|
// closed = set to true to form a closed (torus) model. Default: false
|
||||||
// caps = true to create endcap faces when closed is false. Can be a singe boolean to specify endcaps at both ends, or a length 2 boolean array. Default is true if closed is false.
|
// caps = true to create endcap faces when closed is false. Can be a singe boolean to specify endcaps at both ends, or a length 2 boolean array. Default is true if closed is false.
|
||||||
|
// style = vnf_vertex_array style. Default: "min_edge"
|
||||||
// ---
|
// ---
|
||||||
// convexity = convexity setting for use with polyhedron. (module only) Default: 10
|
// convexity = convexity setting for use with polyhedron. (module only) Default: 10
|
||||||
// anchor = Translate so anchor point is at the origin. (module only) Default: "origin"
|
// anchor = Translate so anchor point is at the origin. (module only) Default: "origin"
|
||||||
@@ -953,7 +901,7 @@ function associate_vertices(polygons, split, curpoly=0) =
|
|||||||
// inside = [for(i=[24:-1:2]) up(i)*rot(i)*scale(1.2*i/24+1)];
|
// inside = [for(i=[24:-1:2]) up(i)*rot(i)*scale(1.2*i/24+1)];
|
||||||
// sweep(shape, concat(outside,inside));
|
// sweep(shape, concat(outside,inside));
|
||||||
|
|
||||||
function sweep(shape, transforms, closed=false, caps) =
|
function sweep(shape, transforms, closed=false, caps, style="min_edge") =
|
||||||
assert(is_consistent(transforms, ident(4)), "Input transforms must be a list of numeric 4x4 matrices in sweep")
|
assert(is_consistent(transforms, ident(4)), "Input transforms must be a list of numeric 4x4 matrices in sweep")
|
||||||
assert(is_path(shape,2) || is_region(shape), "Input shape must be a 2d path or a region.")
|
assert(is_path(shape,2) || is_region(shape), "Input shape must be a 2d path or a region.")
|
||||||
let(
|
let(
|
||||||
@@ -979,13 +927,14 @@ function sweep(shape, transforms, closed=false, caps) =
|
|||||||
vnf = vnf_merge(vnfs)
|
vnf = vnf_merge(vnfs)
|
||||||
) vnf :
|
) vnf :
|
||||||
assert(len(shape)>=3, "shape must be a path of at least 3 non-colinear points")
|
assert(len(shape)>=3, "shape must be a path of at least 3 non-colinear points")
|
||||||
_skin_core([for(i=[0:len(transforms)-(closed?0:1)]) apply(transforms[i%len(transforms)],path3d(shape))],caps=fullcaps);
|
vnf_vertex_array([for(i=[0:len(transforms)-(closed?0:1)]) apply(transforms[i%len(transforms)],path3d(shape))],
|
||||||
|
caps=fullcaps,col_wrap=true,style=style);
|
||||||
|
|
||||||
|
|
||||||
module sweep(shape, transforms, closed=false, caps, convexity=10,
|
module sweep(shape, transforms, closed=false, caps, style="min_edge", convexity=10,
|
||||||
anchor="origin",cp,spin=0, orient=UP, extent=false)
|
anchor="origin",cp,spin=0, orient=UP, extent=false)
|
||||||
{
|
{
|
||||||
vnf = sweep(shape, transforms, closed, caps);
|
vnf = sweep(shape, transforms, closed, caps, style);
|
||||||
attachable(anchor=anchor, spin=spin, orient=orient, vnf=vnf, extent=extent, cp=is_def(cp) ? cp : vnf_centroid(vnf))
|
attachable(anchor=anchor, spin=spin, orient=orient, vnf=vnf, extent=extent, cp=is_def(cp) ? cp : vnf_centroid(vnf))
|
||||||
{
|
{
|
||||||
vnf_polyhedron(vnf,convexity=convexity);
|
vnf_polyhedron(vnf,convexity=convexity);
|
||||||
@@ -996,8 +945,8 @@ module sweep(shape, transforms, closed=false, caps, convexity=10,
|
|||||||
|
|
||||||
// Function&Module: path_sweep()
|
// Function&Module: path_sweep()
|
||||||
// Usage: As module
|
// Usage: As module
|
||||||
// path_sweep(shape, path, <method>, <normal=>, <closed=>, <twist=>, <twist_by_length=>, <symmetry=>, <last_normal=>, <tangent=>, <relaxed=>, <caps=>, <convexity=>, <transforms=>, <anchor=>, <cp=>, <spin=>, <orient=>, <extent=>) <attachments>;
|
// path_sweep(shape, path, <method>, <normal=>, <closed=>, <twist=>, <twist_by_length=>, <symmetry=>, <last_normal=>, <tangent=>, <relaxed=>, <caps=>, <style=>, <convexity=>, <transforms=>, <anchor=>, <cp=>, <spin=>, <orient=>, <extent=>) <attachments>;
|
||||||
// vnf = path_sweep(shape, path, <method>, <normal=>, <closed=>, <twist=>, <twist_by_length=>, <symmetry=>, <last_normal=>, <tangent=>, <relaxed=>, <caps=>, <convexity=>, <transforms=>);
|
// vnf = path_sweep(shape, path, <method>, <normal=>, <closed=>, <twist=>, <twist_by_length=>, <symmetry=>, <last_normal=>, <tangent=>, <relaxed=>, <caps=>, <style=>, <convexity=>, <transforms=>);
|
||||||
// Description:
|
// Description:
|
||||||
// Takes as input a 2D polygon path, and a 2d or 3d path and constructs a polyhedron by sweeping the shape along the path.
|
// Takes as input a 2D polygon path, and a 2d or 3d path and constructs a polyhedron by sweeping the shape along the path.
|
||||||
// When run as a module returns the polyhedron geometry. When run as a function returns a VNF by default or if you set `transforms=true`
|
// When run as a module returns the polyhedron geometry. When run as a function returns a VNF by default or if you set `transforms=true`
|
||||||
@@ -1058,6 +1007,7 @@ module sweep(shape, transforms, closed=false, caps, convexity=10,
|
|||||||
// tangent = a list of tangent vectors in case you need more accuracy (particularly at the end points of your curve)
|
// tangent = a list of tangent vectors in case you need more accuracy (particularly at the end points of your curve)
|
||||||
// relaxed = set to true with the "manual" method to relax the orthogonality requirement of cross sections to the path tangent. Default: false
|
// relaxed = set to true with the "manual" method to relax the orthogonality requirement of cross sections to the path tangent. Default: false
|
||||||
// caps = Can be a boolean or vector of two booleans. Set to false to disable caps at the two ends. Default: true
|
// caps = Can be a boolean or vector of two booleans. Set to false to disable caps at the two ends. Default: true
|
||||||
|
// style = vnf_vertex_array style. Default: "min_edge"
|
||||||
// transforms = set to true to return transforms instead of a VNF. These transforms can be manipulated and passed to sweep(). Default: false.
|
// transforms = set to true to return transforms instead of a VNF. These transforms can be manipulated and passed to sweep(). Default: false.
|
||||||
// convexity = convexity parameter for polyhedron(). Only accepted by the module version. Default: 10
|
// convexity = convexity parameter for polyhedron(). Only accepted by the module version. Default: 10
|
||||||
// anchor = Translate so anchor point is at the origin. (module only) Default: "origin"
|
// anchor = Translate so anchor point is at the origin. (module only) Default: "origin"
|
||||||
@@ -1291,11 +1241,11 @@ module sweep(shape, transforms, closed=false, caps, convexity=10,
|
|||||||
// circle(r=16,$fn=75),closed=true,
|
// circle(r=16,$fn=75),closed=true,
|
||||||
// twist=360/5*2,symmetry=5);
|
// twist=360/5*2,symmetry=5);
|
||||||
module path_sweep(shape, path, method="incremental", normal, closed=false, twist=0, twist_by_length=true,
|
module path_sweep(shape, path, method="incremental", normal, closed=false, twist=0, twist_by_length=true,
|
||||||
symmetry=1, last_normal, tangent, relaxed=false, caps, convexity=10,
|
symmetry=1, last_normal, tangent, relaxed=false, caps, style="min_edge", convexity=10,
|
||||||
anchor="origin",cp,spin=0, orient=UP, extent=false)
|
anchor="origin",cp,spin=0, orient=UP, extent=false)
|
||||||
{
|
{
|
||||||
vnf = path_sweep(shape, path, method, normal, closed, twist, twist_by_length,
|
vnf = path_sweep(shape, path, method, normal, closed, twist, twist_by_length,
|
||||||
symmetry, last_normal, tangent, relaxed, caps);
|
symmetry, last_normal, tangent, relaxed, caps, style);
|
||||||
attachable(anchor=anchor, spin=spin, orient=orient, vnf=vnf, extent=extent, cp=is_def(cp) ? cp : vnf_centroid(vnf))
|
attachable(anchor=anchor, spin=spin, orient=orient, vnf=vnf, extent=extent, cp=is_def(cp) ? cp : vnf_centroid(vnf))
|
||||||
{
|
{
|
||||||
vnf_polyhedron(vnf,convexity=convexity);
|
vnf_polyhedron(vnf,convexity=convexity);
|
||||||
@@ -1305,7 +1255,7 @@ module path_sweep(shape, path, method="incremental", normal, closed=false, twist
|
|||||||
|
|
||||||
|
|
||||||
function path_sweep(shape, path, method="incremental", normal, closed=false, twist=0, twist_by_length=true,
|
function path_sweep(shape, path, method="incremental", normal, closed=false, twist=0, twist_by_length=true,
|
||||||
symmetry=1, last_normal, tangent, relaxed=false, caps, transforms=false) =
|
symmetry=1, last_normal, tangent, relaxed=false, caps, style="min_edge", transforms=false) =
|
||||||
assert(!closed || twist % (360/symmetry)==0, str("For a closed sweep, twist must be a multiple of 360/symmetry = ",360/symmetry))
|
assert(!closed || twist % (360/symmetry)==0, str("For a closed sweep, twist must be a multiple of 360/symmetry = ",360/symmetry))
|
||||||
assert(closed || symmetry==1, "symmetry must be 1 when closed is false")
|
assert(closed || symmetry==1, "symmetry must be 1 when closed is false")
|
||||||
assert(is_integer(symmetry) && symmetry>0, "symmetry must be a positive integer")
|
assert(is_integer(symmetry) && symmetry>0, "symmetry must be a positive integer")
|
||||||
@@ -1377,6 +1327,7 @@ function path_sweep(shape, path, method="incremental", normal, closed=false, twi
|
|||||||
let (pathnormal = path_normals(path, tangents, closed))
|
let (pathnormal = path_normals(path, tangents, closed))
|
||||||
assert(all_defined(pathnormal),"Natural normal vanishes on your curve, select a different method")
|
assert(all_defined(pathnormal),"Natural normal vanishes on your curve, select a different method")
|
||||||
let( testnormals = [for(i=[0:len(pathnormal)-1-(closed?1:2)]) pathnormal[i]*select(pathnormal,i+2)],
|
let( testnormals = [for(i=[0:len(pathnormal)-1-(closed?1:2)]) pathnormal[i]*select(pathnormal,i+2)],
|
||||||
|
a=[for(i=idx(testnormals)) testnormals[i]<.5 ? echo(str("Big change at index ",i," pn=",pathnormal[i]," pn2= ",select(pathnormal,i+2))):0],
|
||||||
dummy = min(testnormals) < .5 ? echo("WARNING: ***** Abrupt change in normal direction. Consider a different method *****") :0
|
dummy = min(testnormals) < .5 ? echo("WARNING: ***** Abrupt change in normal direction. Consider a different method *****") :0
|
||||||
)
|
)
|
||||||
[for(i=[0:L-(closed?0:1)]) let(
|
[for(i=[0:L-(closed?0:1)]) let(
|
||||||
@@ -1393,14 +1344,14 @@ function path_sweep(shape, path, method="incremental", normal, closed=false, twi
|
|||||||
apply(transform_list[L], rshape)),
|
apply(transform_list[L], rshape)),
|
||||||
dummy = ends_match ? 0 : echo("WARNING: ***** The points do not match when closing the model *****")
|
dummy = ends_match ? 0 : echo("WARNING: ***** The points do not match when closing the model *****")
|
||||||
)
|
)
|
||||||
transforms ? transform_list : sweep(is_path(shape)?clockwise_polygon(shape):shape, transform_list, closed=false, caps=fullcaps);
|
transforms ? transform_list : sweep(is_path(shape)?clockwise_polygon(shape):shape, transform_list, closed=false, caps=fullcaps,style=style);
|
||||||
|
|
||||||
|
|
||||||
// Function&Module: path_sweep2d()
|
// Function&Module: path_sweep2d()
|
||||||
// Usage: as module
|
// Usage: as module
|
||||||
// path_sweep2d(shape, path, <closed>, <caps>, <quality>, <convexity=>, <anchor=>, <spin=>, <orient=>, <extent=>, <cp=>) <attachments>;
|
// path_sweep2d(shape, path, <closed>, <caps>, <quality>, <style>, <convexity=>, <anchor=>, <spin=>, <orient=>, <extent=>, <cp=>) <attachments>;
|
||||||
// Usage: as function
|
// Usage: as function
|
||||||
// vnf = path_sweep2d(shape, path, <closed>, <caps>, <quality>);
|
// vnf = path_sweep2d(shape, path, <closed>, <caps>, <quality>, <style>);
|
||||||
// Description:
|
// Description:
|
||||||
// Takes an input 2D polygon (the shape) and a 2d path and constructs a polyhedron by sweeping the shape along the path.
|
// Takes an input 2D polygon (the shape) and a 2d path and constructs a polyhedron by sweeping the shape along the path.
|
||||||
// When run as a module returns the polyhedron geometry. When run as a function returns a VNF.
|
// When run as a module returns the polyhedron geometry. When run as a function returns a VNF.
|
||||||
@@ -1417,6 +1368,7 @@ function path_sweep(shape, path, method="incremental", normal, closed=false, twi
|
|||||||
// closed = path is a closed loop. Default: false
|
// closed = path is a closed loop. Default: false
|
||||||
// caps = true to create endcap faces when closed is false. Can be a length 2 boolean array. Default is true if closed is false.
|
// caps = true to create endcap faces when closed is false. Can be a length 2 boolean array. Default is true if closed is false.
|
||||||
// quality = quality of offset used in calculation. Default: 1
|
// quality = quality of offset used in calculation. Default: 1
|
||||||
|
// style = vnf_vertex_array style. Default: "min_edge"
|
||||||
// ---
|
// ---
|
||||||
// convexity = convexity parameter for polyhedron (module only) Default: 10
|
// convexity = convexity parameter for polyhedron (module only) Default: 10
|
||||||
// anchor = Translate so anchor point is at the origin. (module only) Default: "origin"
|
// anchor = Translate so anchor point is at the origin. (module only) Default: "origin"
|
||||||
@@ -1440,7 +1392,7 @@ function path_sweep(shape, path, method="incremental", normal, closed=false, twi
|
|||||||
// path_sweep2d(circle(r=3.25, $fn=32), select(ellipse,floor(L*.2),ceil(L*.8)),closed=false);
|
// path_sweep2d(circle(r=3.25, $fn=32), select(ellipse,floor(L*.2),ceil(L*.8)),closed=false);
|
||||||
// path_sweep2d(circle(r=3.25, $fn=32), select(ellipse,floor(L*.7),ceil(L*.3)),closed=false);
|
// path_sweep2d(circle(r=3.25, $fn=32), select(ellipse,floor(L*.7),ceil(L*.3)),closed=false);
|
||||||
|
|
||||||
function path_sweep2d(shape, path, closed=false, caps, quality=1) =
|
function path_sweep2d(shape, path, closed=false, caps, quality=1, style="min_edge") =
|
||||||
let(
|
let(
|
||||||
caps = is_def(caps) ? caps
|
caps = is_def(caps) ? caps
|
||||||
: closed ? false : true,
|
: closed ? false : true,
|
||||||
@@ -1464,15 +1416,16 @@ function path_sweep2d(shape, path, closed=false, caps, quality=1) =
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
_skin_core([
|
vnf_vertex_array([
|
||||||
each proflist,
|
each proflist,
|
||||||
if (closed) proflist[0]
|
if (closed) proflist[0]
|
||||||
],caps=fullcaps);
|
],caps=fullcaps,col_wrap=true,style=style);
|
||||||
|
|
||||||
module path_sweep2d(profile, path, closed=false, caps, quality=1, convexity=10,
|
|
||||||
|
module path_sweep2d(profile, path, closed=false, caps, quality=1, style="min_edge", convexity=10,
|
||||||
anchor="origin", cp, spin=0, orient=UP, extent=false)
|
anchor="origin", cp, spin=0, orient=UP, extent=false)
|
||||||
{
|
{
|
||||||
vnf = path_sweep2d(profile, path, closed, caps, quality);
|
vnf = path_sweep2d(profile, path, closed, caps, quality, style);
|
||||||
attachable(anchor=anchor, spin=spin, orient=orient, vnf=vnf, extent=extent, cp=is_def(cp) ? cp : vnf_centroid(vnf))
|
attachable(anchor=anchor, spin=spin, orient=orient, vnf=vnf, extent=extent, cp=is_def(cp) ? cp : vnf_centroid(vnf))
|
||||||
{
|
{
|
||||||
vnf_polyhedron(vnf,convexity=convexity);
|
vnf_polyhedron(vnf,convexity=convexity);
|
||||||
|
41
vnf.scad
41
vnf.scad
@@ -215,7 +215,12 @@ function vnf_triangulate(vnf) =
|
|||||||
// Creates a VNF structure from a vertex list, by dividing the vertices into columns and rows,
|
// Creates a VNF structure from a 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 first and/or last rows. The style parameter determines how the quadrilaterals are divided into
|
||||||
|
// triangles. The default style is an arbitrary, systematic subdivision in the same direction. The "alt" style
|
||||||
|
// 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
|
||||||
|
// adds a vertex in the center of each quadrilateral and creates four triangles, and the "convex" style
|
||||||
|
// chooses the locally convex subdivision.
|
||||||
// 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.
|
||||||
@@ -224,7 +229,7 @@ function vnf_triangulate(vnf) =
|
|||||||
// 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", "quincunx", and "convex".
|
// style = The style of subdividing the quads into faces. Valid options are "default", "alt", "min_edge", "quincunx", and "convex".
|
||||||
// vnf = If given, add all the vertices and faces to this existing VNF structure.
|
// 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(
|
||||||
@@ -290,7 +295,7 @@ function vnf_vertex_array(
|
|||||||
) =
|
) =
|
||||||
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"]))
|
assert(in_list(style,["default","alt","quincunx", "convex","min_edge"]))
|
||||||
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),
|
||||||
@@ -317,8 +322,9 @@ function vnf_vertex_array(
|
|||||||
mean([pts[i1], pts[i2], pts[i3], pts[i4]])
|
mean([pts[i1], pts[i2], pts[i3], pts[i4]])
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
vnf_merge(cleanup=true, [
|
vnf_merge(cleanup=false, [
|
||||||
vnf, [
|
vnf,
|
||||||
|
[
|
||||||
verts,
|
verts,
|
||||||
[
|
[
|
||||||
for (r = [0:1:rowcnt-1], c=[0:1:colcnt-1])
|
for (r = [0:1:rowcnt-1], c=[0:1:colcnt-1])
|
||||||
@@ -334,6 +340,14 @@ function vnf_vertex_array(
|
|||||||
[[i1,i5,i2],[i2,i5,i3],[i3,i5,i4],[i4,i5,i1]]
|
[[i1,i5,i2],[i2,i5,i3],[i3,i5,i4],[i4,i5,i1]]
|
||||||
: style=="alt"?
|
: style=="alt"?
|
||||||
[[i1,i4,i2],[i2,i4,i3]]
|
[[i1,i4,i2],[i2,i4,i3]]
|
||||||
|
: style=="min_edge"?
|
||||||
|
let(
|
||||||
|
d42=norm(pts[i4]-pts[i2]),
|
||||||
|
d13=norm(pts[i1]-pts[i3]),
|
||||||
|
shortface = d42<=d13 ? [[i1,i4,i2],[i2,i4,i3]]
|
||||||
|
: [[i1,i3,i2],[i1,i4,i3]]
|
||||||
|
)
|
||||||
|
shortface
|
||||||
: style=="convex"?
|
: style=="convex"?
|
||||||
let(
|
let(
|
||||||
fsets = [
|
fsets = [
|
||||||
@@ -347,17 +361,20 @@ function vnf_vertex_array(
|
|||||||
)
|
)
|
||||||
fsets[test?0:1]
|
fsets[test?0:1]
|
||||||
: [[i1,i3,i2],[i1,i4,i3]],
|
: [[i1,i3,i2],[i1,i4,i3]],
|
||||||
rfaces = reverse? [for (face=faces) reverse(face)] : faces,
|
// remove degenerate faces
|
||||||
dfaces = [for (face=rfaces)
|
culled_faces= [for(face=faces)
|
||||||
let(dface = deduplicate_indexed(verts,face,closed=true))
|
if (norm(verts[face[0]]-verts[face[1]])>EPSILON &&
|
||||||
if(len(dface)>=3) dface
|
norm(verts[face[1]]-verts[face[2]])>EPSILON &&
|
||||||
]
|
norm(verts[face[2]]-verts[face[0]])>EPSILON)
|
||||||
|
face
|
||||||
|
],
|
||||||
|
rfaces = reverse? [for (face=culled_faces) reverse(face)] : culled_faces
|
||||||
)
|
)
|
||||||
dfaces,
|
rfaces,
|
||||||
if (cap1) count(cols,reverse=!reverse),
|
if (cap1) count(cols,reverse=!reverse),
|
||||||
if (cap2) count(cols,(rows-1)*cols, reverse=reverse)
|
if (cap2) count(cols,(rows-1)*cols, reverse=reverse)
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user