revamp extruded region attachables and apply to linear_sweep.

This commit is contained in:
Adrian Mariano 2021-11-17 13:38:07 -05:00
parent 2bfb4e39e7
commit 475129fd95
5 changed files with 40 additions and 79 deletions

View file

@ -1515,10 +1515,10 @@ function _attach_transform(anchor, spin, orient, geom, p) =
function _get_cp(geom) =
let(cp=select(geom,-3))
is_vector(cp) ? cp
: let(
f=echo(type=geom[0]),
type = in_list(geom[0],["vnf_extent","vnf_isect"]) ? "vnf"
: in_list(geom[0],["rgn_extent","rgn_isect"]) ? "path"
: in_list(geom[0],["xrgn_extent","xrgn_isect"]) ? "xpath"
@ -1549,20 +1549,22 @@ function _get_cp(geom) =
// anchor = Vector or named anchor string.
// geom = The geometry description of the shape.
function _find_anchor(anchor, geom) =
is_string(anchor)? (
anchor=="origin"? [anchor, CENTER, UP, 0]
: let(
anchors = last(geom),
found = search([anchor], anchors, num_returns_per_match=1)[0]
)
assert(found!=[], str("Unknown anchor: ",anchor))
anchors[found]
) :
let(
cp = _get_cp(geom),
offset_raw = select(geom,-2),
offset = [for (i=[0:2]) anchor[i]==0? 0 : offset_raw[i]], // prevents bad centering.
anchors = last(geom),
type = geom[0]
)
is_string(anchor)? (
anchor=="origin"? [anchor, CENTER, UP, 0]
: let(found = search([anchor], anchors, num_returns_per_match=1)[0])
assert(found!=[], str("Unknown anchor: ",anchor))
anchors[found]
) :
assert(is_vector(anchor),str("anchor=",anchor))
assert(is_vector(anchor),str("Invalid anchor: anchor=",anchor))
let(anchor = point3d(anchor))
anchor==CENTER? [anchor, cp, UP, 0] :
let(
@ -1725,8 +1727,7 @@ function _find_anchor(anchor, geom) =
) : type == "rgn_isect"? ( //region
assert(anchor.z==0, "The Z component of an anchor for a 2D shape must be 0.")
let(
rgn_raw = move(-point2d(cp), p=geom[1]),
rgn = is_region(rgn_raw)? rgn_raw : [rgn_raw],
rgn = force_region(move(-point2d(cp), p=geom[1])),
anchor = point2d(anchor),
isects = [
for (path=rgn, t=triplet(path,true)) let(
@ -1753,68 +1754,27 @@ function _find_anchor(anchor, geom) =
let(
rgn = force_region(geom[1]),
anchor = point2d(anchor),
m = rot(from=anchor, to=RIGHT) * move(-[cp.x, cp.y, 0]),
rpts = apply(m, flatten(rgn)),
rpts = rot(from=anchor, to=RIGHT, p=flatten(rgn)),
maxx = max(column(rpts,0)),
idxs = [for (i = idx(rpts)) if (approx(rpts[i].x, maxx)) i],
miny = min([for (i=idxs) rpts[i].y]),
maxy = max([for (i=idxs) rpts[i].y]),
midy = (miny+maxy)/2,
pos = point2d(cp) + rot(from=RIGHT, to=anchor, p=[maxx,midy])
) [anchor, pos, anchor, 0]
) : type == "xrgn_isect"? ( //region
assert(in_list(anchor.z,[-1,0,1]), "The Z component of an anchor for an extruded 2D shape must be -1, 0, or 1.")
let(
rgn_raw = move(-point2d(cp), p=geom[1]),
l = geom[2],
rgn = is_region(rgn_raw)? rgn_raw : [rgn_raw],
anchor = point3d(anchor),
xyanch = point2d(anchor)
) approx(xyanch,[0,0])? [anchor, [0,0,anchor.z*l/2], unit(anchor,UP), 0] :
let(
isects = [
for (path=rgn, t=triplet(path,true)) let(
seg1 = [t[0],t[1]],
seg2 = [t[1],t[2]],
isect = line_intersection([[0,0],xyanch], seg1, RAY, SEGMENT),
n = is_undef(isect)? [0,1] :
!approx(isect, t[1])? line_normal(seg1) :
unit((line_normal(seg1)+line_normal(seg2))/2,[0,1]),
n2 = vector_angle(xyanch,n)>90? -n : n
)
if(!is_undef(isect) && !approx(isect,t[0]))
[norm(isect), isect, n2]
],
maxidx = max_index(column(isects,0)),
isect = isects[maxidx],
pos = point3d(cp) + point3d(isect[1]) + unit([0,0,anchor.z],CENTER)*l/2,
xyvec = unit(isect[2],[0,1]),
vec = unit((point3d(xyvec)+UP*anchor.z)/2,UP),
oang = approx(xyvec, [0,0])? 0 : atan2(xyvec.y, xyvec.x) + 90
) [anchor, pos, vec, oang]
) : type == "xrgn_extent"? ( //region
assert(in_list(anchor.z,[-1,0,1]), "The Z component of an anchor for an extruded 2D shape must be -1, 0, or 1.")
let(
rgn = force_region(geom[1]),
l = geom[2],
anchor = point3d(anchor),
xyanch = point2d(anchor),
m = (
approx(xyanch,[0,0])? [[1,0,0],[0,1,0],[0,0,1]] :
rot(from=xyanch, to=RIGHT, planar=true)
) * move(-[cp.x, cp.y]),
rpts = apply(m, flatten(rgn)),
maxx = max(column(rpts,0)),
idxs = [for (i = idx(rpts)) if (approx(rpts[i].x, maxx)) i],
ys = [for (i=idxs) rpts[i].y],
ys = [for (pt=rpts) if (approx(pt.x, maxx)) pt.y],
midy = (min(ys)+max(ys))/2,
xypos = point2d(cp) + (
approx(xyanch,[0,0])? [0,0] :
rot(from=RIGHT, to=xyanch, p=[maxx,midy])
),
pos = point3d(xypos) + unit([0,0,anchor.z],CENTER)*l/2,
vec = unit((point3d(xyanch)+UP*anchor.z)/2,UP)
) [anchor, pos, vec, oang]
pos = rot(from=RIGHT, to=anchor, p=[maxx,midy])
) [anchor, pos, unit(anchor), 0]
) : type=="xrgn_extent" || type=="xrgn_isect" ? ( // extruded region
assert(in_list(anchor.z,[-1,0,1]), "The Z component of an anchor for an extruded 2D shape must be -1, 0, or 1.")
let(
anchor_xy = point2d(anchor),
L = geom[2]
)
approx(anchor_xy,[0,0]) ? [anchor, up(anchor.z*L/2,cp), anchor, oang] :
let(
newgeom = list_set(geom, [0,len(geom)-3], [substr(geom[0],1), point2d(cp)]),
result2d = _find_anchor(anchor_xy, newgeom),
pos = point3d(result2d[1], cp.z+anchor.z*L/2),
vec = unit(point3d(result2d[2], anchor.z),UP),
oang = atan2(vec.y,vec.x) + 90
)
[anchor, pos, vec, oang]
) :
assert(false, "Unknown attachment geometry type.");

View file

@ -612,7 +612,7 @@ function region_parts(region) =
// style = The style to use when triangulating the surface of the object. Valid values are `"default"`, `"alt"`, or `"quincunx"`.
// convexity = Max number of surfaces any single ray could pass through. Module use only.
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `"origin"`
// anchor_isect = If true, anchoring it performed by finding where the anchor vector intersects the swept shape. Default: false
// atype = Set to "hull" or "intersect" to select anchor type. Default: "hull"
// cp = Centerpoint for determining intersection anchors or centering the shape. Determintes the base of the anchor vector. Can be "centroid", "mean", "box" or a 3D point. Default: "centroid"
// 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`
@ -637,7 +637,8 @@ function region_parts(region) =
// mrgn = union(rgn1,rgn2);
// orgn = difference(mrgn,rgn3);
// linear_sweep(orgn,height=20,convexity=16) show_anchors();
module linear_sweep(region, height=1, center, twist=0, scale=1, slices, maxseg, style="default", convexity, anchor_isect=false, spin=0, orient=UP, cp="centroid", anchor="origin", atype="hull") {
module linear_sweep(region, height=1, center, twist=0, scale=1, slices, maxseg, style="default", convexity,
spin=0, orient=UP, cp="centroid", anchor="origin", atype="hull") {
region = force_region(region);
dummy=assert(is_region(region),"Input is not a region");
anchor = center ? "zcenter" : anchor;

View file

@ -154,7 +154,7 @@
// spin = Rotate this many degrees around Z axis after anchor. Default: 0
// orient = Vector to rotate top towards after spin
// atype = Select "hull" or "intersect anchor types. Default: "hull"
// cp = set centerpoint for anchor computation. Default: "centroid"
// cp = Centerpoint for determining "intersect" anchors or centering the shape. Determintes the base of the anchor vector. Can be "centroid", "mean", "box" or a 3D point. Default: "centroid"
// style = vnf_vertex_array style. Default: "min_edge"
// Example:
// skin([octagon(4), circle($fn=70,r=2)], z=[0,3], slices=10);
@ -570,7 +570,7 @@ function skin(profiles, slices, refine=1, method="direct", sampling, caps, close
// spin = Rotate this many degrees around Z axis after anchor. Default: 0
// orient = Vector to rotate top towards after spin
// atype = Select "hull" or "intersect" anchor types. Default: "hull"
// cp = set centerpoint for anchor computation. Default: "centroid"
// cp = Centerpoint for determining "intersect" anchors or centering the shape. Determintes the base of the anchor vector. Can be "centroid", "mean", "box" or a 3D point. Default: "centroid"
// Example(2D): We'll use this shape in several examples
// ushape = [[-10, 0],[-10, 10],[ -7, 10],[ -7, 2],[ 7, 2],[ 7, 7],[ 10, 7],[ 10, 0]];
// polygon(ushape);
@ -949,7 +949,7 @@ function path_sweep(shape, path, method="incremental", normal, closed=false, twi
// spin = Rotate this many degrees around Z axis after anchor. Default: 0
// orient = Vector to rotate top towards after spin
// atype = Select "hull" or "intersect" anchor types. Default: "hull"
// cp = set centerpoint for anchor computation. Default: "centroid"
// cp = Centerpoint for determining "intersect" anchors or centering the shape. Determintes the base of the anchor vector. Can be "centroid", "mean", "box" or a 3D point. Default: "centroid"
// Example: Sine wave example with self-intersections at each peak. This would fail with path_sweep().
// sinewave = [for(i=[-30:10:360*2+30]) [i/40,3*sin(i)]];
// path_sweep2d(circle(r=3,$fn=15), sinewave);
@ -1073,7 +1073,7 @@ function _ofs_face_edge(face,firstlen,second=false) =
// spin = Rotate this many degrees around Z axis after anchor. Default: 0
// orient = Vector to rotate top towards after spin (module only)
// atype = Select "hull" or "intersect" anchor types. Default: "hull"
// cp = set centerpoint for anchor computation. Default: "centroid"
// cp = Centerpoint for determining "intersect" anchors or centering the shape. Determintes the base of the anchor vector. Can be "centroid", "mean", "box" or a 3D point. Default: "centroid"
// Example: This is the "sweep-drop" example from list-comprehension-demos.
// function drop(t) = 100 * 0.5 * (1 - cos(180 * t)) * sin(180 * t) + 1;
// function path(t) = [0, 0, 80 + 80 * cos(180 * t)];

View file

@ -17,7 +17,7 @@
// Arguments:
// str = string to operate on
// pos = starting index of substring, or vector of first and last position. Default: 0
// len = length of substring, or omit it to get the rest of the string. If len is less than zero the emptry string is returned.
// len = length of substring, or omit it to get the rest of the string. If len is zero or less then the emptry string is returned.
// Example:
// substr("abcdefg",3,3); // Returns "def"
// substr("abcdefg",2); // Returns "cdefg"

View file

@ -783,7 +783,7 @@ function _slice_3dpolygons(polys, dir, cuts) =
// vnf = A VNF structure, or list of VNF structures.
// convexity = Max number of times a line could intersect a wall of the shape.
// extent = If true, calculate anchors by extents, rather than intersection. Default: true.
// cp = Centerpoint of VNF to use for anchoring when `extent` is false. Default: `[0, 0, 0]`
// cp = Centerpoint for determining intersection anchors or centering the shape. Determintes the base of the anchor vector. Can be "centroid", "mean", "box" or a 3D point. Default: "centroid"
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `"origin"`
// 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`