mirror of
https://github.com/revarbat/BOSL2.git
synced 2025-08-12 16:24:16 +02:00
Merge pull request #1724 from adrianVmariano/master
add named anchors to linear_sweep
This commit is contained in:
@@ -4145,7 +4145,9 @@ function _prism_fillet_prism(name, basepoly, bot, top, d, k, N, overlap, uniform
|
||||
// The prism will connect anchor points described by the two descriptions you supply. The supported object
|
||||
// types are prismoids, VNFs, cylinders, spheres, and linear sweeps. For prismoids and VNFs you can use any anchor on a face
|
||||
// or edge anchors that include edge geometry. For spheres you can use any anchor. In the case of cylinders and linear sweeps you can
|
||||
// attach to the flat top or bottom in any case, but for side attachments, the shape must not have scaling (so it cannot
|
||||
// attach to the flat top or bottom, or to named face anchors in any case. When you do this, the attachment is treated as an infinite plane.
|
||||
// You can attach to the side of the extrusion and follow the shape of the extrusion using the standard anchors only, but the
|
||||
// shape must not have scaling (so it cannot
|
||||
// be conical) and it must not have any shift. Only right angle cylinders and extrusions are supported.
|
||||
// Anchors on the top and bottom edges are also not supported. When connecting to an extrusion the selected anchor
|
||||
// point must lie on the surface of the shape. This may requires setting `atype="intersect"` when creating the extrusion.
|
||||
@@ -4479,7 +4481,7 @@ function _get_obj_type(ind,geom,anchor,prof) =
|
||||
)
|
||||
[[x,-y],[0,0], [x,y]]
|
||||
: starts_with(geom[0], "extrusion") ?
|
||||
anchor==UP || anchor==DOWN ? "plane"
|
||||
anchor==UP || anchor==DOWN || starts_with(anchor,"face") ? "plane"
|
||||
:
|
||||
assert(geom[3]==0, str("Extrusion in desc", ind, " has nonzero twist, which is not supported."))
|
||||
assert(geom[5]==[0,0], str("Extrusion in desc", ind, " has nonzero shift, which is not supported."))
|
||||
|
@@ -851,8 +851,7 @@ function prismoid(
|
||||
// being located at the bottom of the shape, so confirm anchor positions before use.
|
||||
// Additional named face and edge anchors are located on the side faces and vertical edges of the prism.
|
||||
// You can use `EDGE(i)`, `EDGE(TOP,i)` and `EDGE(BOT,i)` as a shorthand for accessing the named edge anchors, and `FACE(i)` for the face anchors.
|
||||
// When you use `shift`, which moves the top face of the prism, the spin for the side face and edges anchors will align
|
||||
// the child with the edge or face direction. The "edge0" anchor identifies an edge located along the X+ axis, and then edges
|
||||
// The "edge0" anchor identifies an edge located along the X+ axis, and then edges
|
||||
// are labeled counting up in the clockwise direction. Similarly "face0" is the face immediately clockwise from "edge0", and face
|
||||
// labeling proceeds clockwise. The top and bottom edge anchors label edges directly above and below the face with the same label.
|
||||
// If you set `realign=true` then "face0" is oriented in the X+ direction.
|
||||
|
218
skin.scad
218
skin.scad
@@ -541,6 +541,15 @@ function skin(profiles, slices, refine=1, method="direct", sampling, caps, close
|
||||
// correct only for twisted objects, and corner anchors may point in unexpected directions in some cases. These anchors also ignore any applied texture.
|
||||
// If you need anchors directly computed from the surface you can pass the vnf from linear_sweep
|
||||
// to {{vnf_polyhedron()}}, which computes anchors directly from the full VNF.
|
||||
// Additional named face and edge anchors are located on the side faces and vertical edges of the prism.
|
||||
// When you sweep a polygon you can use `EDGE(i)`, `EDGE(TOP,i)` and `EDGE(BOT,i)` as a shorthand for
|
||||
// accessing the named edge anchors, and `FACE(i)` for the face anchors.
|
||||
// The "edge0" anchor identifies an edge located along the X+ axis, and then edges
|
||||
// are labeled counting up in the clockwise direction. Similarly "face0" is the face immediately clockwise from "edge0", and face
|
||||
// labeling proceeds clockwise. The top and bottom edge anchors label edges directly above and below the face with the same label.
|
||||
// When you sweep a region, the region is decomposed using {{region_parts()}} and the anchors are generated for the region components
|
||||
// in the order produced by the decomposition, working entirely through each component and then on to the next component.
|
||||
// The anchors for twisted shapes may be inaccurate.
|
||||
// Arguments:
|
||||
// region = The 2D [Region](regions.scad) or polygon that is to be extruded.
|
||||
// h / height / l / length = The height to extrude the region. Default: 1
|
||||
@@ -574,6 +583,12 @@ function skin(profiles, slices, refine=1, method="direct", sampling, caps, close
|
||||
// "origin" = Centers the extruded shape vertically only, but keeps the original path positions in the X and Y. Oriented UP.
|
||||
// "original_base" = Keeps the original path positions in the X and Y, but at the bottom of the extrusion. Oriented DOWN.
|
||||
// "original_top" = Keeps the original path positions in the X and Y, but at the top of the extrusion. Oriented UP.
|
||||
// "edge0", "edge1", etc. = Center of each side edge, spin pointing up along the edge. Can access with EDGE(i)
|
||||
// "face0", "face1", etc. = Center of each side face, spin pointing up. Can access with FACE(i)
|
||||
// "top_edge0", "top_edge1", etc = Center of each top edge, spin pointing clockwise (from top). Can access with EDGE(TOP,i)
|
||||
// "bot_edge0", "bot_edge1", etc = Center of each bottom edge, spin pointing clockwise (from bottom). Can access with EDGE(BOT,i)
|
||||
// "top_corner0", "top_corner1", etc = Top corner, pointing in direction of associated edge anchor, spin up along associated edge
|
||||
// "bot_corner0", "bot_corner1", etc = Bottom corner, pointing in direction of associated edge anchor, spin up along associated edge
|
||||
// Example: Extruding a Compound Region.
|
||||
// rgn1 = [for (d=[10:10:60]) circle(d=d,$fn=8)];
|
||||
// rgn2 = [square(30,center=false)];
|
||||
@@ -743,7 +758,7 @@ module linear_sweep(
|
||||
anchor = center==true? "origin" :
|
||||
center == false? "original_base" :
|
||||
default(anchor, "original_base");
|
||||
vnf = linear_sweep(
|
||||
vnf_geom = linear_sweep(
|
||||
region, height=h, style=style, caps=caps,
|
||||
twist=twist, scale=scale, shift=shift,
|
||||
texture=texture,
|
||||
@@ -755,31 +770,73 @@ module linear_sweep(
|
||||
tex_depth=tex_depth,
|
||||
tex_samples=tex_samples,
|
||||
slices=slices,
|
||||
maxseg=maxseg,
|
||||
anchor="origin"
|
||||
maxseg=maxseg, atype=atype,
|
||||
anchor="origin", _return_geom=true
|
||||
);
|
||||
anchors = [
|
||||
named_anchor("original_base", [0,0,-h/2], DOWN),
|
||||
named_anchor("original_top", [0,0,h/2], UP),
|
||||
];
|
||||
cp = default(cp, "centroid");
|
||||
geom = atype=="hull"? attach_geom(cp=cp, region=region, h=h, extent=true, shift=shift, scale=scale, twist=twist, anchors=anchors) :
|
||||
atype=="intersect"? attach_geom(cp=cp, region=region, h=h, extent=false, shift=shift, scale=scale, twist=twist, anchors=anchors) :
|
||||
atype=="bbox"?
|
||||
let(
|
||||
bounds = pointlist_bounds(flatten(region)),
|
||||
size = bounds[1] - bounds[0],
|
||||
midpt = (bounds[0] + bounds[1])/2
|
||||
)
|
||||
attach_geom(cp=[0,0,0], size=point3d(size,h), offset=point3d(midpt), shift=shift, scale=scale, twist=twist, anchors=anchors) :
|
||||
assert(in_list(atype, ["hull","intersect","bbox"]), "\nAnchor type must be \"hull\", \"intersect\", or \"bbox\".");
|
||||
attachable(anchor,spin,orient, geom=geom) {
|
||||
vnf_polyhedron(vnf, convexity=convexity);
|
||||
attachable(anchor,spin,orient, geom=vnf_geom[1]) {
|
||||
vnf_polyhedron(vnf_geom[0], convexity=convexity);
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function _make_all_prism_anchors(bot, top, startind=0) =
|
||||
let(
|
||||
facenormal= [
|
||||
for(i=idx(bot))
|
||||
let(
|
||||
edge0 = [top[i],bot[i]], // vertical edge at i
|
||||
edge1 = [select(top,i+1),select(bot,i+1)], // vertical edge at i+1
|
||||
facenormal = unit(unit(cross(edge1[1]-edge0[0], edge0[1]-edge0[0]))+
|
||||
unit(cross(edge0[0]-edge1[1], edge1[0]-edge1[1])))
|
||||
)
|
||||
facenormal
|
||||
],
|
||||
anchors = [for(i=idx(bot))
|
||||
let(
|
||||
|
||||
edge1 = [top[i],bot[i]], // vertical edge at i
|
||||
edge2 = [select(top,i+1),select(bot,i+1)], // vertical edge at i+1
|
||||
|
||||
facecenter = mean(concat(edge1,edge2)),
|
||||
facespin = _compute_spin(facenormal[i], UP),
|
||||
|
||||
side_edge_center = mean(edge1),
|
||||
side_edge_dir = top[i]-bot[i],
|
||||
side_edge_normal = unit(vector_bisect(facenormal[i],select(facenormal,i-1))),
|
||||
side_edge_spin = _compute_spin(side_edge_normal, side_edge_dir),
|
||||
side_edge_angle = 180-vector_angle(facenormal[i], select(facenormal,i-1)),
|
||||
side_edge_len = norm(side_edge_dir),
|
||||
|
||||
top_edge_center = (edge2[0]+edge1[0])/2,
|
||||
top_edge_dir = edge2[0]-edge1[0],
|
||||
bot_edge_center = (edge1[1]+edge2[1])/2,
|
||||
bot_edge_dir = edge1[1]-edge2[1],
|
||||
topnormal = unit(facenormal[i]+UP),
|
||||
botnormal = unit(facenormal[i]+DOWN),
|
||||
topedgespin = _compute_spin(topnormal, top_edge_dir),
|
||||
botedgespin = _compute_spin(botnormal, bot_edge_dir),
|
||||
topedgeangle = 180-vector_angle(UP,facenormal[i])
|
||||
)
|
||||
each [
|
||||
named_anchor(str("face",i+startind), facecenter, facenormal[i], facespin),
|
||||
named_anchor(str("edge",i+startind), side_edge_center, side_edge_normal, side_edge_spin,
|
||||
info=[["edge_angle",side_edge_angle], ["edge_length",side_edge_len]]),
|
||||
named_anchor(str("top_edge",i+startind), top_edge_center, topnormal, topedgespin,
|
||||
info=[["edge_angle",topedgeangle],["edge_length",norm(top_edge_dir)]]),
|
||||
named_anchor(str("bot_edge",i+startind), bot_edge_center, botnormal, botedgespin,
|
||||
info=[["edge_angle",180-topedgeangle],["edge_length",norm(bot_edge_dir)]]),
|
||||
named_anchor(str("top_corner",i+startind), top[i], unit(side_edge_normal+UP),
|
||||
_compute_spin(unit(side_edge_normal+UP),side_edge_dir)),
|
||||
named_anchor(str("bot_corner",i+startind), bot[i], unit(side_edge_normal+DOWN),
|
||||
_compute_spin(unit(side_edge_normal+DOWN),side_edge_dir))
|
||||
]
|
||||
]
|
||||
)
|
||||
anchors;
|
||||
|
||||
|
||||
|
||||
function linear_sweep(
|
||||
region, height, center,
|
||||
twist=0, scale=1, shift=[0,0],
|
||||
@@ -788,7 +845,7 @@ function linear_sweep(
|
||||
texture, tex_size=[5,5], tex_reps, tex_counts,
|
||||
tex_inset=false, tex_rot=0,
|
||||
tex_scale, tex_depth, tex_samples, h, l, length,
|
||||
anchor, spin=0, orient=UP
|
||||
anchor, spin=0, orient=UP, _return_geom=false
|
||||
) =
|
||||
assert(num_defined([tex_reps,tex_counts])<2, "\nIn linear_sweep() the 'tex_counts' parameter has been replaced by 'tex_reps'. You cannot give both.")
|
||||
assert(num_defined([tex_scale,tex_depth])<2, "\nIn linear_sweep() the 'tex_scale' parameter has been replaced by 'tex_depth'. You cannot give both.")
|
||||
@@ -804,63 +861,74 @@ function linear_sweep(
|
||||
assert(is_vector(shift, 2), str(shift))
|
||||
assert(is_bool(caps) || is_bool_list(caps,2), "\ncaps must be boolean or a list of two booleans.")
|
||||
let(
|
||||
h = one_defined([h, height,l,length],"h,height,l,length",dflt=1)
|
||||
)
|
||||
!is_undef(texture)? _textured_linear_sweep(
|
||||
region, h=h, caps=caps,
|
||||
texture=texture, tex_size=tex_size,
|
||||
counts=tex_reps, inset=tex_inset,
|
||||
rot=tex_rot, tex_scale=tex_depth,
|
||||
twist=twist, scale=scale, shift=shift,
|
||||
style=style, samples=tex_samples,
|
||||
anchor=anchor, spin=spin, orient=orient
|
||||
) :
|
||||
let(
|
||||
caps = is_bool(caps) ? [caps,caps] : caps,
|
||||
anchor = center==true? "origin" :
|
||||
center == false? "original_base" :
|
||||
default(anchor, "original_base"),
|
||||
h = one_defined([h, height,l,length],"h,height,l,length",dflt=1),
|
||||
regions = region_parts(region),
|
||||
slices = default(slices, max(1,ceil(abs(twist)/5))),
|
||||
scale = is_num(scale)? [scale,scale] : point2d(scale),
|
||||
topmat = move(shift) * scale(scale) * rot(-twist),
|
||||
trgns = [
|
||||
for (rgn = regions) [
|
||||
for (path = rgn) let(
|
||||
p = list_unwrap(path),
|
||||
path = is_undef(maxseg)? p : [
|
||||
for (seg = pair(p,true)) each
|
||||
let( steps = ceil(norm(seg.y - seg.x) / maxseg) )
|
||||
lerpn(seg.x, seg.y, steps, false)
|
||||
]
|
||||
) apply(topmat, path)
|
||||
]
|
||||
],
|
||||
vnf = vnf_join([
|
||||
for (rgn = regions)
|
||||
for (pathnum = idx(rgn)) let(
|
||||
p = list_unwrap(rgn[pathnum]),
|
||||
path = is_undef(maxseg)? p : [
|
||||
for (seg=pair(p,true)) each
|
||||
let(steps=ceil(norm(seg.y-seg.x)/maxseg))
|
||||
lerpn(seg.x, seg.y, steps, false)
|
||||
],
|
||||
verts = [
|
||||
for (i=[0:1:slices]) let(
|
||||
u = i / slices,
|
||||
scl = lerp([1,1], scale, u),
|
||||
ang = lerp(0, -twist, u),
|
||||
off = lerp([0,0,-h/2], point3d(shift,h/2), u),
|
||||
m = move(off) * scale(scl) * rot(ang)
|
||||
) apply(m, path3d(path))
|
||||
]
|
||||
) vnf_vertex_array(verts, caps=false, col_wrap=true, style=style),
|
||||
if (caps[0]) for (rgn = regions) vnf_from_region(rgn, down(h/2), reverse=true),
|
||||
if (caps[1]) for (rgn = trgns) vnf_from_region(rgn, up(h/2), reverse=false)
|
||||
]),
|
||||
vnf = !is_undef(texture)?
|
||||
_textured_linear_sweep(
|
||||
region, h=h, caps=caps,
|
||||
texture=texture, tex_size=tex_size,
|
||||
counts=tex_reps, inset=tex_inset,
|
||||
rot=tex_rot, tex_scale=tex_depth,
|
||||
twist=twist, scale=scale, shift=shift,
|
||||
style=style, samples=tex_samples)
|
||||
: let(
|
||||
caps = is_bool(caps) ? [caps,caps] : caps,
|
||||
anchor = center==true? "origin" :
|
||||
center == false? "original_base" :
|
||||
default(anchor, "original_base"),
|
||||
slices = default(slices, max(1,ceil(abs(twist)/5))),
|
||||
scale = is_num(scale)? [scale,scale] : point2d(scale),
|
||||
topmat = move(shift) * scale(scale) * rot(-twist),
|
||||
trgns = [
|
||||
for (rgn = regions) [
|
||||
for (path = rgn) let(
|
||||
p = list_unwrap(path),
|
||||
path = is_undef(maxseg)? p : [
|
||||
for (seg = pair(p,true)) each
|
||||
let( steps = ceil(norm(seg.y - seg.x) / maxseg) )
|
||||
lerpn(seg.x, seg.y, steps, false)
|
||||
]
|
||||
) apply(topmat, path)
|
||||
]
|
||||
],
|
||||
vnf = vnf_join([
|
||||
for (rgn = regions)
|
||||
for (pathnum = idx(rgn)) let(
|
||||
p = list_unwrap(rgn[pathnum]),
|
||||
path = is_undef(maxseg)? p : [
|
||||
for (seg=pair(p,true)) each
|
||||
let(steps=ceil(norm(seg.y-seg.x)/maxseg))
|
||||
lerpn(seg.x, seg.y, steps, false)
|
||||
],
|
||||
verts = [
|
||||
for (i=[0:1:slices]) let(
|
||||
u = i / slices,
|
||||
scl = lerp([1,1], scale, u),
|
||||
ang = lerp(0, -twist, u),
|
||||
off = lerp([0,0,-h/2], point3d(shift,h/2), u),
|
||||
m = move(off) * scale(scl) * rot(ang)
|
||||
) apply(m, path3d(path))
|
||||
]
|
||||
) vnf_vertex_array(verts, caps=false, col_wrap=true, style=style),
|
||||
if (caps[0]) for (rgn = regions) vnf_from_region(rgn, down(h/2), reverse=true),
|
||||
if (caps[1]) for (rgn = trgns) vnf_from_region(rgn, up(h/2), reverse=false)
|
||||
])
|
||||
)
|
||||
vnf,
|
||||
regparts = flatten(regions),
|
||||
sizes = [0,each cumsum([for(entry=regparts) len(entry)])],
|
||||
ganchors = [
|
||||
for(i=idx(regparts))
|
||||
let(
|
||||
bot = path3d(regparts[i],-h/2),
|
||||
top = path3d(move(shift,scale(scale, zrot(-twist, regparts[i]))),h/2)
|
||||
)
|
||||
each _make_all_prism_anchors(bot,top, startind=sizes[i])
|
||||
],
|
||||
anchors = [
|
||||
named_anchor("original_base", [0,0,-h/2], DOWN),
|
||||
named_anchor("original_top", [0,0,h/2], UP),
|
||||
each ganchors
|
||||
],
|
||||
cp = default(cp, "centroid"),
|
||||
geom = atype=="hull"? attach_geom(cp=cp, region=region, h=h, extent=true, shift=shift, scale=scale, twist=twist, anchors=anchors) :
|
||||
@@ -873,7 +941,7 @@ function linear_sweep(
|
||||
)
|
||||
attach_geom(cp=[0,0,0], size=point3d(size,h), offset=point3d(midpt), shift=shift, scale=scale, twist=twist, anchors=anchors) :
|
||||
assert(in_list(atype, ["hull","intersect","bbox"]), "\nAnchor type must be \"hull\", \"intersect\", or \"bbox\".")
|
||||
) reorient(anchor,spin,orient, geom=geom, p=vnf);
|
||||
) _return_geom ? [vnf,geom] : reorient(anchor,spin,orient, geom=geom, p=vnf);
|
||||
|
||||
|
||||
// Function&Module: rotate_sweep()
|
||||
|
Reference in New Issue
Block a user