mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2024-12-29 16:29:40 +00:00
Merge branch 'master' into master
This commit is contained in:
commit
26ff57491e
6 changed files with 481 additions and 170 deletions
|
@ -458,10 +458,9 @@ function find_anchor(anchor, geom) =
|
|||
eps = 1/2048,
|
||||
points = vnf[0],
|
||||
faces = vnf[1],
|
||||
rpts = rot(from=anchor, to=RIGHT, p=move(point3d(-cp), p=points)),
|
||||
rpts = apply(rot(from=anchor, to=RIGHT) * move(point3d(-cp)), points),
|
||||
hits = [
|
||||
for (i = idx(faces)) let(
|
||||
face = faces[i],
|
||||
for (face = faces) let(
|
||||
verts = select(rpts, face)
|
||||
) if (
|
||||
max(subindex(verts,0)) >= -eps &&
|
||||
|
@ -470,35 +469,40 @@ function find_anchor(anchor, geom) =
|
|||
min(subindex(verts,1)) <= eps &&
|
||||
min(subindex(verts,2)) <= eps
|
||||
) let(
|
||||
pt = polygon_line_intersection(
|
||||
select(points, face),
|
||||
[CENTER,anchor], eps=eps
|
||||
)
|
||||
) if (!is_undef(pt)) [norm(pt), i, pt]
|
||||
poly = select(points, face),
|
||||
pt = polygon_line_intersection(poly, [cp,cp+anchor], bounded=[true,false], eps=eps)
|
||||
) if (!is_undef(pt)) let(
|
||||
plane = plane_from_polygon(poly),
|
||||
n = unit(plane_normal(plane))
|
||||
)
|
||||
[norm(pt-cp), n, pt]
|
||||
]
|
||||
)
|
||||
assert(len(hits)>0, "Anchor vector does not intersect with the shape. Attachment failed.")
|
||||
let(
|
||||
furthest = max_index(subindex(hits,0)),
|
||||
pos = point3d(cp) + hits[furthest][2],
|
||||
dist = hits[furthest][0],
|
||||
nfaces = [for (hit = hits) if(approx(hit[0],dist,eps=eps)) hit[1]],
|
||||
n = unit(
|
||||
sum([
|
||||
for (i = nfaces) let(
|
||||
faceverts = select(points, faces[i]),
|
||||
faceplane = plane_from_points(faceverts),
|
||||
nrm = plane_normal(faceplane)
|
||||
) nrm
|
||||
]) / len(nfaces),
|
||||
UP
|
||||
)
|
||||
pos = hits[furthest][2],
|
||||
hitnorms = [for (hit = hits) if (approx(hit[0],dist,eps=eps)) hit[1]],
|
||||
unorms = len(hitnorms) > 7
|
||||
? unique([for (nn = hitnorms) quant(nn,1e-9)])
|
||||
: [
|
||||
for (i = idx(hitnorms)) let(
|
||||
nn = hitnorms[i],
|
||||
isdup = [
|
||||
for (j = [i+1:1:len(hitnorms)-1])
|
||||
if (approx(nn, hitnorms[j])) 1
|
||||
] != []
|
||||
) if (!isdup) nn
|
||||
],
|
||||
n = unit(sum(unorms)),
|
||||
oang = approx(point2d(n), [0,0])? 0 : atan2(n.y, n.x) + 90
|
||||
)
|
||||
[anchor, pos, n, oang]
|
||||
) : type == "vnf_extent"? ( //vnf
|
||||
let(
|
||||
vnf=geom[1],
|
||||
rpts = rot(from=anchor, to=RIGHT, p=move(point3d(-cp), p=vnf[0])),
|
||||
rpts = apply(rot(from=anchor, to=RIGHT) * move(point3d(-cp)), vnf[0]),
|
||||
maxx = max(subindex(rpts,0)),
|
||||
idxs = [for (i = idx(rpts)) if (approx(rpts[i].x, maxx)) i],
|
||||
mm = pointlist_bounds(select(rpts,idxs)),
|
||||
|
@ -849,7 +853,7 @@ module attachable(
|
|||
|
||||
// Module: position()
|
||||
// Usage:
|
||||
// position(from, [overlap]) ...
|
||||
// position(from) ...
|
||||
// Description:
|
||||
// Attaches children to a parent object at an anchor point.
|
||||
// Arguments:
|
||||
|
|
240
joiners.scad
240
joiners.scad
|
@ -564,6 +564,7 @@ module dovetail(gender, length, l, width, w, height, h, angle, slope, taper, bac
|
|||
}
|
||||
|
||||
|
||||
// Section: Tension Clips
|
||||
|
||||
// h is total height above 0 of the nub
|
||||
// nub extends below xy plane by distance nub/2
|
||||
|
@ -780,5 +781,244 @@ module snap_pin_socket(size, r, radius, l,length, d,diameter,nub_depth, snap, fi
|
|||
|
||||
|
||||
|
||||
// Module: rabbit_clip()
|
||||
// Usage:
|
||||
// rabbit_clip(type, length, width, snap, thickness, depth, [compression], [clearance], [lock],
|
||||
// [lock_clearance], [splineteps], [anchor], [orient], [spin])
|
||||
// Description:
|
||||
// Creates a clip with two flexible ears to lock into a mating socket, or create a mask to produce the appropriate
|
||||
// mating socket. The clip can be made to insert and release easily, or to hold much better, or it can be
|
||||
// created with locking flanges that will make it very hard or impossible to remove. Unlike the snap pin, this clip
|
||||
// is rectangular and can be made at any height, so a suitable clip could be very thin. It's also possible to get a
|
||||
// solid connection with a short pin.
|
||||
// .
|
||||
// The type parameters specifies whether to make a clip, a socket mask, or a double clip. The length is the
|
||||
// total nominal length of the clip. (The actual length will be very close, but not equal to this.) The width
|
||||
// gives the nominal width of the clip, which is the actual width of the clip at its base. The snap parameter
|
||||
// gives the depth of the clip sides, which controls how easy the clip is to insert and remove. The clip "ears" are
|
||||
// made over-wide by the compression value. A nonzero compression helps make the clip secure in its socket.
|
||||
// The socket's width and length are increased by the clearance value which creates some space and can compensate
|
||||
// for printing inaccuracy. The socket will be slightly longer than the nominal width. The thickness is the thickness
|
||||
// curved line that forms the clip. The clip depth is the amount the basic clip shape is extruded. Be sure that you
|
||||
// make the socket with a larger depth than the clip (try 0.4 mm) to allow ease of insertion of the clip. The clearance
|
||||
// value does not apply to the depth. The splinesteps parameter increases the sampling of the clip curves.
|
||||
// .
|
||||
// By default clips appear with orient=UP and sockets with orient=DOWN.
|
||||
// .
|
||||
// The first figure shows the dimensions of the rabbit clip. The second figure shows the clip in red overlayed on
|
||||
// its socket in yellow. The left clip has a nonzero clearance, so its socket is bigger than the clip all around.
|
||||
// The right hand locking clip has no clearance, but it has a lock clearance, which provides some space behind
|
||||
// the lock to allow the clip to fit. (Note that depending on your printer, this can be set to zero.)
|
||||
//
|
||||
// Figure(2DMed):
|
||||
// snap=1.5;
|
||||
// comp=0.75;
|
||||
// mid = 8.053; // computed in rabbit_clip
|
||||
// tip = [-4.58,18.03];
|
||||
// translate([9,3]){
|
||||
// back_half()
|
||||
// rabbit_clip("pin",width=12, length=18, depth=1, thickness = 1, compression=comp, snap=snap, orient=BACK);
|
||||
// color("blue"){
|
||||
// stroke([[6,0],[6,18]],width=0.1);
|
||||
// stroke([[6+comp, 12], [6+comp, 18]], width=.1);
|
||||
// }
|
||||
// color("red"){
|
||||
// stroke([[6-snap,mid], [6,mid]], endcaps="arrow2",width=0.15);
|
||||
// translate([6+.4,mid-.15])text("snap",size=1,valign="center");
|
||||
// translate([6+comp/2,19.5])text("compression", size=1, halign="center");
|
||||
// stroke([[6+comp/2,19.3], [6+comp/2,17.7]], endcap2="arrow2", width=.15);
|
||||
// fwd(1.1)text("width",size=1,halign="center");
|
||||
// xflip_copy()stroke([[2,-.7], [6,-.7]], endcap2="arrow2", width=.15);
|
||||
// move([-6.7,mid])rot(90)text("length", size=1, halign="center");
|
||||
// stroke([[-7,10.3], [-7,18]], width=.15, endcap2="arrow2");
|
||||
// stroke([[-7,0], [-7,5.8]], width=.15,endcap1="arrow2");
|
||||
// stroke([tip, tip-[0,1]], width=.15);
|
||||
// move([tip.x+2,19.5])text("thickness", halign="center",size=1);
|
||||
// stroke([[tip.x+2, 19.3], tip+[.1,.1]], width=.15, endcap2="arrow2");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Figure(2DMed):
|
||||
// snap=1.5;
|
||||
// comp=0;
|
||||
// translate([29,3]){
|
||||
// back_half()
|
||||
// rabbit_clip("socket", width=12, length=18, depth=1, thickness = 1, compression=comp, snap=snap, orient=BACK,lock=true);
|
||||
// color("red")back_half()
|
||||
// rabbit_clip("pin",width=12, length=18, depth=1, thickness = 1, compression=comp, snap=snap,
|
||||
// orient=BACK,lock=true,lock_clearance=1);
|
||||
// }
|
||||
// translate([9,3]){
|
||||
// back_half()
|
||||
// rabbit_clip("socket", clearance=.5,width=12, length=18, depth=1, thickness = 1,
|
||||
// compression=comp, snap=snap, orient=BACK,lock=false);
|
||||
// color("red")back_half()
|
||||
// rabbit_clip("pin",width=12, length=18, depth=1, thickness = 1, compression=comp, snap=snap,
|
||||
// orient=BACK,lock=false,lock_clearance=1);
|
||||
// }
|
||||
// Arguments:
|
||||
// type = One of "pin", "socket", "male", "female" or "double" to specify what to make.
|
||||
// length = nominal clip length
|
||||
// width = nominal clip width
|
||||
// snap = depth of hollow on the side of the clip
|
||||
// thickness = thickness of the clip "line"
|
||||
// depth = amount to extrude clip (give extra room for the socket, about 0.4mm)
|
||||
// compression = excess width at the "ears" to lock more tightly. Default: 0.1
|
||||
// clearance = extra space in the socket for easier insertion. Default: 0.1
|
||||
// lock = set to true to make a locking clip that may be irreversible. Default: false
|
||||
// lock_clearance = give clearance for the lock. Default: 0
|
||||
// splinesteps = number of samples in the curves of the clip. Default: 8
|
||||
// anchor = anchor point for clip
|
||||
// orient = clip orientation. Default: UP for pins, DOWN for sockets
|
||||
// spin = spin the clip. Default: 0
|
||||
//
|
||||
// Example: Here are several sizes that work printed in PLA on a Prusa MK3, with default clearance of 0.1 and a depth of 5
|
||||
// module test_pair(length, width, snap, thickness, compression, lock=false)
|
||||
// {
|
||||
// depth = 5;
|
||||
// extra_depth = 10;// Change this to 0.4 for closed sockets
|
||||
// cuboid([max(width+5,12),12, depth], chamfer=.5, edges=[FRONT,"Y"], anchor=BOTTOM)
|
||||
// attach(BACK)
|
||||
// rabbit_clip(type="pin",length=length, width=width,snap=snap,thickness=thickness,depth=depth,
|
||||
// compression=compression,lock=lock);
|
||||
// right(width+13)
|
||||
// diff("remove")
|
||||
// cuboid([width+8,max(12,length+2),depth+3], chamfer=.5, edges=[FRONT,"Y"], anchor=BOTTOM)
|
||||
// attach(BACK)
|
||||
// rabbit_clip(type="socket",length=length, width=width,snap=snap,thickness=thickness,depth=depth+extra_depth,
|
||||
// lock=lock,compression=0,$tags="remove");
|
||||
// }
|
||||
// left(37)ydistribute(spacing=28){
|
||||
// test_pair(length=6, width=7, snap=0.25, thickness=0.8, compression=0.1);
|
||||
// test_pair(length=3.5, width=7, snap=0.1, thickness=0.8, compression=0.1); // snap = 0.2 gives a firmer connection
|
||||
// test_pair(length=3.5, width=5, snap=0.1, thickness=0.8, compression=0.1); // hard to take apart
|
||||
// }
|
||||
// right(17)ydistribute(spacing=28){
|
||||
// test_pair(length=12, width=10, snap=1, thickness=1.2, compression=0.2);
|
||||
// test_pair(length=8, width=7, snap=0.75, thickness=0.8, compression=0.2, lock=true); // With lock, very firm and irreversible
|
||||
// test_pair(length=8, width=7, snap=0.75, thickness=0.8, compression=0.2, lock=true); // With lock, very firm and irreversible
|
||||
// }
|
||||
// Example: Double clip to connect two sockets
|
||||
// rabbit_clip("double",length=8, width=7, snap=0.75, thickness=0.8, compression=0.2,depth=5);
|
||||
// Example: A modified version of the clip that acts like a backpack strap clip, where it locks tightly but you can squeeze to release.
|
||||
// cuboid([25,15,5],anchor=BOTTOM)
|
||||
// attach(BACK)rabbit_clip("pin", length=25, width=25, thickness=1.5, snap=2, compression=0, lock=true, depth=5, lock_clearance=3);
|
||||
// left(32)
|
||||
// diff("remove")
|
||||
// cuboid([30,30,11],orient=BACK,anchor=BACK){
|
||||
// attach(BACK)rabbit_clip("socket", length=25, width=25, thickness=1.5, snap=2, compression=0, lock=true, depth=5.5, lock_clearance=3,$tags="remove");
|
||||
// xflip_copy()
|
||||
// position(FRONT+LEFT)
|
||||
// xscale(0.8)
|
||||
// zcyl(l=20,r=13.5, $tags="remove",$fn=64);
|
||||
// }
|
||||
module rabbit_clip(type, length, width, snap, thickness, depth, compression=0.1, clearance=.1, lock=false, lock_clearance=0,
|
||||
splinesteps=8, anchor, orient, spin=0)
|
||||
{
|
||||
assert(is_num(width) && width>0,"Width must be a positive value");
|
||||
assert(is_num(length) && length>0, "Length must be a positive value");
|
||||
assert(is_num(thickness) && thickness>0, "Thickness must be a positive value");
|
||||
assert(is_num(snap) && snap>=0, "Snap must be a non-negative value");
|
||||
assert(is_num(depth) && depth>0, "Depth must be a positive value");
|
||||
assert(is_num(compression) && compression >= 0, "Compression must be a nonnegative value");
|
||||
assert(is_bool(lock));
|
||||
assert(is_num(lock_clearance));
|
||||
legal_types = ["pin","socket","male","female","double"];
|
||||
assert(in_list(type,legal_types),str("type must be one of ",legal_types));
|
||||
|
||||
if (type=="double") {
|
||||
attachable(size=[width+2*compression, depth, 2*length], anchor=default(anchor,BACK), spin=spin, orient=default(orient,BACK)){
|
||||
union(){
|
||||
rabbit_clip("pin", length=length, width=width, snap=snap, thickness=thickness, depth=depth, compression=compression,
|
||||
lock=lock, anchor=BOTTOM, orient=UP);
|
||||
rabbit_clip("pin", length=length, width=width, snap=snap, thickness=thickness, depth=depth, compression=compression,
|
||||
lock=lock, anchor=BOTTOM, orient=DOWN);
|
||||
cuboid([width-thickness, depth, thickness]);
|
||||
}
|
||||
children();
|
||||
}
|
||||
} else {
|
||||
anchor = default(anchor,BOTTOM);
|
||||
is_pin = in_list(type,["pin","male"]);
|
||||
default_overlap = 0.01 * (is_pin?1:-1); // Shift by this much to undo default overlap
|
||||
extra = 0.02; // Amount of extension below nominal based position for the socket, must exceed default overlap of 0.01
|
||||
clearance = is_pin ? 0 : clearance;
|
||||
compression = is_pin ? compression : 0;
|
||||
orient = is_def(orient) ? orient
|
||||
: is_pin ? UP
|
||||
: DOWN;
|
||||
earwidth = 2*thickness+snap;
|
||||
point_length = earwidth/2.15;
|
||||
// The adjustment is using cos(theta)*earwidth/2 and sin(theta)*point_length, but the computation
|
||||
// is obscured because theta is atan(length/2/snap)
|
||||
scaled_len = length - 0.5 * (earwidth * snap + point_length * length) / sqrt(sqr(snap)+sqr(length/2));
|
||||
bottom_pt = [0,max(scaled_len*0.15+thickness, 2*thickness)];
|
||||
ctr = [width/2,scaled_len] + line_normal([width/2-snap, scaled_len/2], [width/2, scaled_len]) * earwidth/2;
|
||||
inside_pt = circle_circle_tangents(bottom_pt, 0, ctr, earwidth/2)[0][1];
|
||||
sidepath =[
|
||||
[width/2,0],
|
||||
[width/2-snap,scaled_len/2],
|
||||
[width/2+(is_pin?compression:0), scaled_len],
|
||||
ctr - point_length * line_normal([width/2,scaled_len], inside_pt),
|
||||
inside_pt
|
||||
];
|
||||
fullpath = concat(
|
||||
sidepath,
|
||||
[bottom_pt],
|
||||
reverse(apply(xflip(),sidepath))
|
||||
);
|
||||
assert(fullpath[4].y < fullpath[3].y, "Pin is too wide for its length");
|
||||
|
||||
snapmargin = -snap + select(sidepath,-1).x;// - compression;
|
||||
if (is_pin){
|
||||
if (snapmargin<0) echo("WARNING: The snap is too large for the clip to squeeze to fit its socket")
|
||||
echo(snapmargin=snapmargin);
|
||||
}
|
||||
// Force tangent to be vertical at the outer edge of the clip to avoid overshoot
|
||||
fulltangent = list_set(path_tangents(fullpath, uniform=false),[2,8], [[0,1],[0,-1]]);
|
||||
|
||||
subset = is_pin ? [0:10] : [0,1,2,3, 7,8,9,10]; // Remove internal points from the socket
|
||||
tangent = select(fulltangent, subset);
|
||||
path = select(fullpath, subset);
|
||||
|
||||
socket_smooth = .04;
|
||||
pin_smooth = [.075, .075, .15, .12, .06];
|
||||
smoothing = is_pin
|
||||
? concat(pin_smooth, reverse(pin_smooth))
|
||||
: let(side_smooth=select(pin_smooth, 0, 2))
|
||||
concat(side_smooth, [socket_smooth], reverse(side_smooth));
|
||||
bez = path_to_bezier(path,relsize=smoothing,tangents=tangent);
|
||||
rounded = bezier_polyline(bez,splinesteps=splinesteps);
|
||||
bounds = pointlist_bounds(rounded);
|
||||
kk = search([bounds[1].y], subindex(rounded,1));
|
||||
echo(rounded[kk[0]]);
|
||||
extrapt = is_pin ? [] : [rounded[0] - [0,extra]];
|
||||
finalpath = is_pin ? rounded
|
||||
: let(withclearance=offset(rounded, r=-clearance))
|
||||
concat( [[withclearance[0].x,-extra]],
|
||||
withclearance,
|
||||
[[-withclearance[0].x,-extra]]);
|
||||
attachable(size=[bounds[1].x-bounds[0].x, depth, bounds[1].y-bounds[0].y], anchor=anchor, spin=spin, orient=orient){
|
||||
xrot(90)
|
||||
translate([0,-(bounds[1].y-bounds[0].y)/2+default_overlap,-depth/2])
|
||||
linear_extrude(height=depth, convexity=10) {
|
||||
if (lock)
|
||||
xflip_copy()
|
||||
right(clearance)
|
||||
polygon([sidepath[1]+[-thickness/10,lock_clearance],
|
||||
sidepath[2],
|
||||
[sidepath[2].x,sidepath[1].y+lock_clearance]]);
|
||||
if (is_pin)
|
||||
offset_stroke(finalpath, width=[thickness,0]);
|
||||
else
|
||||
polygon(finalpath);
|
||||
}
|
||||
children();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
||||
|
|
294
rounding.scad
294
rounding.scad
|
@ -458,10 +458,10 @@ function smooth_path(path, tangents, size, relsize, splinesteps=10, uniform=fals
|
|||
|
||||
|
||||
|
||||
// Module: offset_sweep()
|
||||
// Function&Module: offset_sweep()
|
||||
//
|
||||
// Description:
|
||||
// Takes a 2d path as input and extrudes it upwards and/or downward. Each layer in the extrusion is produced using `offset()` to expand or shrink the previous layer.
|
||||
// Takes a 2d path as input and extrudes it upwards and/or downward. Each layer in the extrusion is produced using `offset()` to expand or shrink the previous layer. When invoked as a function returns a VNF; when invoked as a module produces geometry.
|
||||
// You can specify a sequence of offsets values, or you can use several built-in offset profiles that are designed to provide end treatments such as roundovers.
|
||||
// The path is shifted by `offset()` multiple times in sequence
|
||||
// to produce the final shape (not multiple shifts from one parent), so coarse definition of the input path will degrade
|
||||
|
@ -543,8 +543,12 @@ function smooth_path(path, tangents, size, relsize, splinesteps=10, uniform=fals
|
|||
// angle = default angle for chamfers. Default: 45
|
||||
// joint = default joint value for smooth roundover.
|
||||
// k = default curvature parameter value for "smooth" roundover
|
||||
// convexity = convexity setting for use with polyhedron. 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"
|
||||
// spin = Rotate this many degrees around Z axis after anchor. (module only) Default: 0
|
||||
// orient = Vector to rotate top towards after spin (module only)
|
||||
// extent = use extent method for computing anchors. (module only) Default: false
|
||||
// cp = set centerpoint for anchor computation. (module only) Default: object centroid
|
||||
// Example: Rounding a star shaped prism with postive radius values
|
||||
// star = star(5, r=22, ir=13);
|
||||
// rounded_star = round_corners(star, cut=flatten(repeat([.5,0],5)), $fn=24);
|
||||
|
@ -650,118 +654,118 @@ function smooth_path(path, tangents, size, relsize, splinesteps=10, uniform=fals
|
|||
// up(1)
|
||||
// offset_sweep(offset(rhex,r=-1), height=9.5, bottom=os_circle(r=2), top=os_teardrop(r=-4));
|
||||
// }
|
||||
module offset_sweep(
|
||||
path, height, h, l,
|
||||
top=[], bottom=[],
|
||||
offset="round", r=0, steps=16,
|
||||
quality=1, check_valid=true,
|
||||
offset_maxstep=1, extra=0,
|
||||
cut=undef, chamfer_width=undef, chamfer_height=undef,
|
||||
joint=undef, k=0.75, angle=45,
|
||||
convexity=10
|
||||
) {
|
||||
// This function does the actual work of repeatedly calling offset() and concatenating the resulting face and vertex lists to produce
|
||||
// the inputs for the polyhedron module.
|
||||
function make_polyhedron(path,offsets, offset_type, flip_faces, quality, check_valid, maxstep, offsetind=0, vertexcount=0, vertices=[], faces=[] )=
|
||||
offsetind==len(offsets)? (
|
||||
let(
|
||||
bottom = list_range(n=len(path),s=vertexcount),
|
||||
oriented_bottom = !flip_faces? bottom : reverse(bottom)
|
||||
) [vertices, concat(faces,[oriented_bottom])]
|
||||
) : (
|
||||
let(
|
||||
this_offset = offsetind==0? offsets[0][0] : offsets[offsetind][0] - offsets[offsetind-1][0],
|
||||
delta = offset_type=="delta" || offset_type=="chamfer" ? this_offset : undef,
|
||||
r = offset_type=="round"? this_offset : undef,
|
||||
do_chamfer = offset_type == "chamfer"
|
||||
|
||||
|
||||
// This function does the actual work of repeatedly calling offset() and concatenating the resulting face and vertex lists to produce
|
||||
// the inputs for the polyhedron module.
|
||||
function _make_offset_polyhedron(path,offsets, offset_type, flip_faces, quality, check_valid, maxstep, offsetind=0,
|
||||
vertexcount=0, vertices=[], faces=[] )=
|
||||
offsetind==len(offsets)? (
|
||||
let(
|
||||
bottom = list_range(n=len(path),s=vertexcount),
|
||||
oriented_bottom = !flip_faces? bottom : reverse(bottom)
|
||||
) [vertices, concat(faces,[oriented_bottom])]
|
||||
) : (
|
||||
let(
|
||||
this_offset = offsetind==0? offsets[0][0] : offsets[offsetind][0] - offsets[offsetind-1][0],
|
||||
delta = offset_type=="delta" || offset_type=="chamfer" ? this_offset : undef,
|
||||
r = offset_type=="round"? this_offset : undef,
|
||||
do_chamfer = offset_type == "chamfer"
|
||||
)
|
||||
let(
|
||||
vertices_faces = offset(
|
||||
path, r=r, delta=delta, chamfer = do_chamfer, closed=true,
|
||||
check_valid=check_valid, quality=quality,
|
||||
maxstep=maxstep, return_faces=true,
|
||||
firstface_index=vertexcount,
|
||||
flip_faces=flip_faces
|
||||
)
|
||||
assert(num_defined([r,delta])==1,str("Must set `offset` to ",round," or ",delta)
|
||||
let(
|
||||
vertices_faces = offset(
|
||||
path, r=r, delta=delta, chamfer = do_chamfer, closed=true,
|
||||
check_valid=check_valid, quality=quality,
|
||||
maxstep=maxstep, return_faces=true,
|
||||
firstface_index=vertexcount,
|
||||
flip_faces=flip_faces
|
||||
)
|
||||
)
|
||||
make_polyhedron(
|
||||
vertices_faces[0], offsets, offset_type,
|
||||
flip_faces, quality, check_valid, maxstep,
|
||||
offsetind+1, vertexcount+len(path),
|
||||
vertices=concat(
|
||||
vertices,
|
||||
zip(vertices_faces[0],repeat(offsets[offsetind][1],len(vertices_faces[0])))
|
||||
),
|
||||
faces=concat(faces, vertices_faces[1])
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
argspec = [
|
||||
["r",r],
|
||||
["extra",extra],
|
||||
["type","circle"],
|
||||
["check_valid",check_valid],
|
||||
["quality",quality],
|
||||
["offset_maxstep", offset_maxstep],
|
||||
["steps",steps],
|
||||
["offset",offset],
|
||||
["chamfer_width",chamfer_width],
|
||||
["chamfer_height",chamfer_height],
|
||||
["angle",angle],
|
||||
["cut",cut],
|
||||
["joint",joint],
|
||||
["k", k],
|
||||
["points", []],
|
||||
];
|
||||
|
||||
path = check_and_fix_path(path, [2], closed=true);
|
||||
clockwise = polygon_is_clockwise(path);
|
||||
|
||||
top = struct_set(argspec, top, grow=false);
|
||||
bottom = struct_set(argspec, bottom, grow=false);
|
||||
|
||||
// This code does not work. It hits the error in make_polyhedron from offset being wrong
|
||||
// before this code executes. Had to move the test into make_polyhedron, which is ugly since it's in the loop
|
||||
//offsetsok = in_list(struct_val(top, "offset"),["round","delta"]) &&
|
||||
// in_list(struct_val(bottom, "offset"),["round","delta"]);
|
||||
//assert(offsetsok,"Offsets must be one of \"round\" or \"delta\"");
|
||||
|
||||
|
||||
offsets_bot = _rounding_offsets(bottom, -1);
|
||||
offsets_top = _rounding_offsets(top, 1);
|
||||
|
||||
if (offset == "chamfer" && (len(offsets_bot)>5 || len(offsets_top)>5)) {
|
||||
echo("WARNING: You have selected offset=\"chamfer\", which leads to exponential growth in the vertex count and requested many layers. This can be slow or run out of recursion depth.");
|
||||
}
|
||||
// "Extra" height enlarges the result beyond the requested height, so subtract it
|
||||
bottom_height = len(offsets_bot)==0 ? 0 : abs(select(offsets_bot,-1)[1]) - struct_val(bottom,"extra");
|
||||
top_height = len(offsets_top)==0 ? 0 : abs(select(offsets_top,-1)[1]) - struct_val(top,"extra");
|
||||
|
||||
height = get_height(l=l,h=h,height=height,dflt=bottom_height+top_height);
|
||||
assert(height>=0, "Height must be nonnegative");
|
||||
|
||||
middle = height-bottom_height-top_height;
|
||||
assert(
|
||||
middle>=0, str(
|
||||
"Specified end treatments (bottom height = ",bottom_height,
|
||||
" top_height = ",top_height,") are too large for extrusion height (",height,")"
|
||||
)
|
||||
_make_offset_polyhedron(
|
||||
vertices_faces[0], offsets, offset_type,
|
||||
flip_faces, quality, check_valid, maxstep,
|
||||
offsetind+1, vertexcount+len(path),
|
||||
vertices=concat(
|
||||
vertices,
|
||||
zip(vertices_faces[0],repeat(offsets[offsetind][1],len(vertices_faces[0])))
|
||||
),
|
||||
faces=concat(faces, vertices_faces[1])
|
||||
)
|
||||
);
|
||||
initial_vertices_bot = path3d(path);
|
||||
|
||||
vertices_faces_bot = make_polyhedron(
|
||||
|
||||
function offset_sweep(
|
||||
path, height, h, l,
|
||||
top=[], bottom=[],
|
||||
offset="round", r=0, steps=16,
|
||||
quality=1, check_valid=true,
|
||||
offset_maxstep=1, extra=0,
|
||||
cut=undef, chamfer_width=undef, chamfer_height=undef,
|
||||
joint=undef, k=0.75, angle=45
|
||||
) =
|
||||
let(
|
||||
argspec = [
|
||||
["r",r],
|
||||
["extra",extra],
|
||||
["type","circle"],
|
||||
["check_valid",check_valid],
|
||||
["quality",quality],
|
||||
["offset_maxstep", offset_maxstep],
|
||||
["steps",steps],
|
||||
["offset",offset],
|
||||
["chamfer_width",chamfer_width],
|
||||
["chamfer_height",chamfer_height],
|
||||
["angle",angle],
|
||||
["cut",cut],
|
||||
["joint",joint],
|
||||
["k", k],
|
||||
["points", []],
|
||||
],
|
||||
path = check_and_fix_path(path, [2], closed=true),
|
||||
clockwise = polygon_is_clockwise(path),
|
||||
|
||||
top = struct_set(argspec, top, grow=false),
|
||||
bottom = struct_set(argspec, bottom, grow=false),
|
||||
|
||||
// This code does not work. It hits the error in _make_offset_polyhedron from offset being wrong
|
||||
// before this code executes. Had to move the test into _make_offset_polyhedron, which is ugly since it's in the loop
|
||||
offsetsok = in_list(struct_val(top, "offset"),["round","delta"])
|
||||
&& in_list(struct_val(bottom, "offset"),["round","delta"])
|
||||
)
|
||||
assert(offsetsok,"Offsets must be one of \"round\" or \"delta\"")
|
||||
let(
|
||||
offsets_bot = _rounding_offsets(bottom, -1),
|
||||
offsets_top = _rounding_offsets(top, 1),
|
||||
dummy = offset == "chamfer" && (len(offsets_bot)>5 || len(offsets_top)>5)
|
||||
? echo("WARNING: You have selected offset=\"chamfer\", which leads to exponential growth in the vertex count and requested more than 5 layers. This can be slow or run out of recursion depth.")
|
||||
: 0,
|
||||
|
||||
// "Extra" height enlarges the result beyond the requested height, so subtract it
|
||||
bottom_height = len(offsets_bot)==0 ? 0 : abs(select(offsets_bot,-1)[1]) - struct_val(bottom,"extra"),
|
||||
top_height = len(offsets_top)==0 ? 0 : abs(select(offsets_top,-1)[1]) - struct_val(top,"extra"),
|
||||
|
||||
height = get_height(l=l,h=h,height=height,dflt=bottom_height+top_height),
|
||||
middle = height-bottom_height-top_height
|
||||
)
|
||||
assert(height>=0, "Height must be nonnegative")
|
||||
assert(middle>=0, str("Specified end treatments (bottom height = ",bottom_height,
|
||||
" top_height = ",top_height,") are too large for extrusion height (",height,")"
|
||||
)
|
||||
)
|
||||
let(
|
||||
initial_vertices_bot = path3d(path),
|
||||
|
||||
vertices_faces_bot = _make_offset_polyhedron(
|
||||
path, offsets_bot, struct_val(bottom,"offset"), clockwise,
|
||||
struct_val(bottom,"quality"),
|
||||
struct_val(bottom,"check_valid"),
|
||||
struct_val(bottom,"offset_maxstep"),
|
||||
vertices=initial_vertices_bot
|
||||
);
|
||||
),
|
||||
|
||||
top_start_ind = len(vertices_faces_bot[0]);
|
||||
initial_vertices_top = zip(path, repeat(middle,len(path)));
|
||||
vertices_faces_top = make_polyhedron(
|
||||
top_start_ind = len(vertices_faces_bot[0]),
|
||||
initial_vertices_top = zip(path, repeat(middle,len(path))),
|
||||
vertices_faces_top = _make_offset_polyhedron(
|
||||
path, move(p=offsets_top,[0,middle]),
|
||||
struct_val(top,"offset"), !clockwise,
|
||||
struct_val(top,"quality"),
|
||||
|
@ -769,20 +773,39 @@ module offset_sweep(
|
|||
struct_val(top,"offset_maxstep"),
|
||||
vertexcount=top_start_ind,
|
||||
vertices=initial_vertices_top
|
||||
);
|
||||
),
|
||||
middle_faces = middle==0 ? [] : [
|
||||
for(i=[0:len(path)-1]) let(
|
||||
oneface=[i, (i+1)%len(path), top_start_ind+(i+1)%len(path), top_start_ind+i]
|
||||
) !clockwise ? reverse(oneface) : oneface
|
||||
];
|
||||
up(bottom_height) {
|
||||
polyhedron(
|
||||
concat(vertices_faces_bot[0],vertices_faces_top[0]),
|
||||
faces=concat(vertices_faces_bot[1], vertices_faces_top[1], middle_faces),
|
||||
convexity=convexity
|
||||
);
|
||||
}
|
||||
}
|
||||
]
|
||||
)
|
||||
[up(bottom_height, concat(vertices_faces_bot[0],vertices_faces_top[0])), // Vertices
|
||||
concat(vertices_faces_bot[1], vertices_faces_top[1], middle_faces)]; // Faces
|
||||
|
||||
|
||||
module offset_sweep(path, height, h, l,
|
||||
top=[], bottom=[],
|
||||
offset="round", r=0, steps=16,
|
||||
quality=1, check_valid=true,
|
||||
offset_maxstep=1, extra=0,
|
||||
cut=undef, chamfer_width=undef, chamfer_height=undef,
|
||||
joint=undef, k=0.75, angle=45,
|
||||
convexity=10,anchor="origin",cp,
|
||||
spin=0, orient=UP, extent=false)
|
||||
{
|
||||
vnf = offset_sweep(path=path, height=height, h=h, l=l, top=top, bottom=bottom, offset=offset, r=0, steps=steps,
|
||||
quality=quality, check_valid=true, offset_maxstep=1, extra=0, cut=cut, chamfer_width=chamfer_width,
|
||||
chamfer_height=chamfer_height, joint=joint, k=k, angle=angle);
|
||||
|
||||
attachable(anchor=anchor, spin=spin, orient=orient, vnf=vnf, extent=extent, cp=is_def(cp) ? cp : vnf_centroid(vnf))
|
||||
{
|
||||
vnf_polyhedron(vnf,convexity=convexity);
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function os_circle(r,cut,extra,check_valid, quality,steps, offset_maxstep, offset) =
|
||||
assert(num_defined([r,cut])==1, "Must define exactly one of `r` and `cut`")
|
||||
|
@ -924,7 +947,6 @@ function os_profile(points, extra,check_valid, quality, offset_maxstep, offset)
|
|||
// joint = default joint value for smooth roundover.
|
||||
// k = default curvature parameter value for "smooth" roundover
|
||||
// convexity = convexity setting for use with polyhedron. Default: 10
|
||||
//
|
||||
// Example: Chamfered elliptical prism. If you stretch a chamfered cylinder the chamfer will be uneven.
|
||||
// convex_offset_extrude(bottom = os_chamfer(height=-2), top=os_chamfer(height=1), height=7)
|
||||
// xscale(4)circle(r=6,$fn=64);
|
||||
|
@ -1364,8 +1386,6 @@ module offset_stroke(path, width=1, rounded=true, start, end, check_valid=true,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function _rp_compute_patches(top, bot, rtop, rsides, ktop, ksides, concave) =
|
||||
let(
|
||||
N = len(top),
|
||||
|
@ -1395,8 +1415,8 @@ function _rp_compute_patches(top, bot, rtop, rsides, ktop, ksides, concave) =
|
|||
let(
|
||||
prev_corner = prev_offset + abs(rtop_in)*in_prev,
|
||||
next_corner = next_offset + abs(rtop_in)*in_next,
|
||||
prev_degenerate = is_undef(ray_intersection([far_corner, far_corner+prev], [prev_offset, prev_offset+in_prev])),
|
||||
next_degenerate = is_undef(ray_intersection([far_corner, far_corner+next], [next_offset, next_offset+in_next]))
|
||||
prev_degenerate = is_undef(ray_intersection(path2d([far_corner, far_corner+prev]), path2d([prev_offset, prev_offset+in_prev]))),
|
||||
next_degenerate = is_undef(ray_intersection(path2d([far_corner, far_corner+next]), path2d([next_offset, next_offset+in_next])))
|
||||
)
|
||||
[ prev_degenerate ? far_corner : prev_corner,
|
||||
far_corner,
|
||||
|
@ -1452,6 +1472,11 @@ function _rp_compute_patches(top, bot, rtop, rsides, ktop, ksides, concave) =
|
|||
// splinesteps = number of segments to use for curved patches. Default: 16
|
||||
// debug = turn on debug mode which displays illegal polyhedra and shows the bezier corner patches for troubleshooting purposes. Default: False
|
||||
// convexity = convexity parameter for polyhedron(), only for module version. Default: 10
|
||||
// anchor = Translate so anchor point is at the origin. (module only) Default: "origin"
|
||||
// spin = Rotate this many degrees around Z axis after anchor. (module only) Default: 0
|
||||
// orient = Vector to rotate top towards after spin (module only)
|
||||
// extent = use extent method for computing anchors. (module only) Default: false
|
||||
// cp = set centerpoint for anchor computation. (module only) Default: object centroid
|
||||
// Example: Uniformly rounded pentagonal prism
|
||||
// rounded_prism(pentagon(3), height=3, joint_top=0.5, joint_bot=0.5, joint_sides=0.5);
|
||||
// Example: Maximum possible rounding.
|
||||
|
@ -1500,15 +1525,21 @@ function _rp_compute_patches(top, bot, rtop, rsides, ktop, ksides, concave) =
|
|||
// rounded_prism(apply(yrot(95),path3d(hexagon(3))), apply(yrot(95), path3d(hexagon(3),3)), joint_top=2, joint_bot=1, joint_sides=1);
|
||||
|
||||
module rounded_prism(bottom, top, joint_bot, joint_top, joint_sides, k_bot, k_top, k_sides,
|
||||
k=0.5, splinesteps=16, h, length, l, height, convexity=10, debug=false)
|
||||
k=0.5, splinesteps=16, h, length, l, height, convexity=10, debug=false,
|
||||
anchor="origin",cp,spin=0, orient=UP, extent=false)
|
||||
{
|
||||
result = rounded_prism(bottom=bottom, top=top, joint_bot=joint_bot, joint_top=joint_top, joint_sides=joint_sides,
|
||||
k_bot=k_bot, k_top=k_top, k_sides=k_sides, k=k, splinesteps=splinesteps, h=h, length=length, height=height, l=l,debug=debug);
|
||||
if (debug){
|
||||
vnf_polyhedron(result[1], convexity=convexity);
|
||||
trace_bezier_patches(result[0], showcps=true, splinesteps=splinesteps, $fn=16, showdots=false, showpatch=false);
|
||||
vnf = debug ? result[1] : result;
|
||||
attachable(anchor=anchor, spin=spin, orient=orient, vnf=vnf, extent=extent, cp=is_def(cp) ? cp : vnf_centroid(vnf))
|
||||
{
|
||||
if (debug){
|
||||
vnf_polyhedron(vnf, convexity=convexity);
|
||||
trace_bezier_patches(result[0], showcps=true, splinesteps=splinesteps, $fn=16, showdots=false, showpatch=false);
|
||||
}
|
||||
else vnf_polyhedron(vnf,convexity=convexity);
|
||||
children();
|
||||
}
|
||||
else vnf_polyhedron(result,convexity=convexity);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1555,8 +1586,8 @@ function rounded_prism(bottom, top, joint_bot, joint_top, joint_sides, k_bot, k_
|
|||
k_sides_vec = is_num(k_sides) ? repeat(k_sides, N) : k_sides,
|
||||
kbad = [for(i=[0:N-1]) if (k_sides_vec[i]<0 || k_sides_vec[i]>1) i],
|
||||
joint_sides_vec = jssingleok ? repeat(joint_sides,N) : joint_sides,
|
||||
top_collinear = [for(i=[0:N-1]) if (points_are_collinear(select(top,i-1,i+1))) i],
|
||||
bot_collinear = [for(i=[0:N-1]) if (points_are_collinear(select(bottom,i-1,i+1))) i]
|
||||
top_collinear = [for(i=[0:N-1]) if (collinear(select(top,i-1,i+1))) i],
|
||||
bot_collinear = [for(i=[0:N-1]) if (collinear(select(bottom,i-1,i+1))) i]
|
||||
)
|
||||
assert(non_coplanar==[], str("Side faces are non-coplanar at edges: ",non_coplanar))
|
||||
assert(top_collinear==[], str("Top has collinear or duplicated points at indices: ",top_collinear))
|
||||
|
@ -1622,14 +1653,14 @@ function rounded_prism(bottom, top, joint_bot, joint_top, joint_sides, k_bot, k_
|
|||
vline = concat(select(subindex(top_patch[i],j),2,4),
|
||||
select(subindex(bot_patch[i],j),2,4))
|
||||
)
|
||||
if (!points_are_collinear(vline)) [i,j]],
|
||||
if (!collinear(vline)) [i,j]],
|
||||
//verify horiz edges
|
||||
verify_horiz=[for(i=[0:N-1], j=[0:4])
|
||||
let(
|
||||
hline_top = concat(select(top_patch[i][j],2,4), select(select(top_patch, i+1)[j],0,2)),
|
||||
hline_bot = concat(select(bot_patch[i][j],2,4), select(select(bot_patch, i+1)[j],0,2))
|
||||
)
|
||||
if (!points_are_collinear(hline_top) || !points_are_collinear(hline_bot)) [i,j]]
|
||||
if (!collinear(hline_top) || !collinear(hline_bot)) [i,j]]
|
||||
)
|
||||
assert(debug || top_intersections==[],
|
||||
"Roundovers interfere with each other on top face: either input is self intersecting or top joint length is too large")
|
||||
|
@ -1880,7 +1911,7 @@ function _circle_mask(r) =
|
|||
// $fn=128;
|
||||
// difference(){
|
||||
// tube(or=r, wall=2, h=45);
|
||||
// bent_cutout_mask(r-1, 2.1, apply(back(15),subdivide_path(round_corners(star(n=7,ir=5,or=10), cut=flatten(repeat([0.5,0],7))),14*15,closed=true)));
|
||||
// bent_cutout_mask(r-1, 2.1, apply(back(15),subdivide_path(round_corners(star(n=7,ir=5,or=10), cut=flatten(repeat([0.5,0],7)),$fn=32),14*15,closed=true)));
|
||||
// }
|
||||
// }
|
||||
// Example(2D): Cutting a slot in a cylinder is tricky if you want rounded corners at the top. This slot profile has slightly angled top edges to blend into the top edge of the cylinder.
|
||||
|
@ -1944,6 +1975,7 @@ function _circle_mask(r) =
|
|||
|
||||
module bent_cutout_mask(r, thickness, path, convexity=10)
|
||||
{
|
||||
no_children($children);
|
||||
assert(is_path(path,2),"Input path must be a 2d path")
|
||||
assert(r-thickness>0, "Thickness too large for radius");
|
||||
assert(thickness>0, "Thickness must be positive");
|
||||
|
|
|
@ -102,8 +102,8 @@ module cuboid(
|
|||
if (edges == EDGES_ALL && trimcorners) {
|
||||
if (chamfer<0) {
|
||||
cube(size, center=true) {
|
||||
attach(TOP) prismoid([size.x,size.y], [size.x-2*chamfer,size.y-2*chamfer], h=-chamfer, anchor=TOP);
|
||||
attach(BOT) prismoid([size.x,size.y], [size.x-2*chamfer,size.y-2*chamfer], h=-chamfer, anchor=TOP);
|
||||
attach(TOP,overlap=0) prismoid([size.x,size.y], [size.x-2*chamfer,size.y-2*chamfer], h=-chamfer, anchor=TOP);
|
||||
attach(BOT,overlap=0) prismoid([size.x,size.y], [size.x-2*chamfer,size.y-2*chamfer], h=-chamfer, anchor=TOP);
|
||||
}
|
||||
} else {
|
||||
isize = [for (v = size) max(0.001, v-2*chamfer)];
|
||||
|
|
63
skin.scad
63
skin.scad
|
@ -16,7 +16,8 @@ include <vnf.scad>
|
|||
|
||||
// Function&Module: skin()
|
||||
// Usage: As module:
|
||||
// skin(profiles, [slices], [refine], [method], [sampling], [caps], [closed], [z]);
|
||||
// skin(profiles, [slices], [refine], [method], [sampling], [caps], [closed], [z], [convexity],
|
||||
// [anchor],[cp],[spin],[orient],[extent]);
|
||||
// Usage: As function:
|
||||
// vnf = skin(profiles, [slices], [refine], [method], [sampling], [caps], [closed], [z]);
|
||||
// Description:
|
||||
|
@ -117,6 +118,12 @@ include <vnf.scad>
|
|||
// caps = true to create endcap faces when closed is false. Can be a length 2 boolean array. Default is true if closed is false.
|
||||
// method = method for connecting profiles, one of "distance", "tangent", "direct" or "reindex". Default: "direct".
|
||||
// z = array of height values for each profile if the profiles are 2d
|
||||
// convexity = convexity setting for use with polyhedron. (module only) Default: 10
|
||||
// anchor = Translate so anchor point is at the origin. (module only) Default: "origin"
|
||||
// spin = Rotate this many degrees around Z axis after anchor. (module only) Default: 0
|
||||
// orient = Vector to rotate top towards after spin (module only)
|
||||
// extent = use extent method for computing anchors. (module only) Default: false
|
||||
// cp = set centerpoint for anchor computation. (module only) Default: object centroid
|
||||
// Example:
|
||||
// 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
|
||||
|
@ -315,11 +322,15 @@ include <vnf.scad>
|
|||
// 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, convexity=10,
|
||||
anchor="origin",cp,spin=0, orient=UP, extent=false)
|
||||
{
|
||||
vnf_polyhedron(skin(profiles, slices, refine, method, sampling, caps, closed, z), convexity=convexity);
|
||||
vnf = skin(profiles, slices, refine, method, sampling, caps, closed, z);
|
||||
attachable(anchor=anchor, spin=spin, orient=orient, vnf=vnf, extent=extent, cp=is_def(cp) ? cp : vnf_centroid(vnf))
|
||||
{
|
||||
vnf_polyhedron(vnf,convexity=convexity);
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -803,6 +814,12 @@ function associate_vertices(polygons, split, curpoly=0) =
|
|||
// transformations = list of 4x4 matrices to apply
|
||||
// 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.
|
||||
// convexity = convexity setting for use with polyhedron. (module only) Default: 10
|
||||
// anchor = Translate so anchor point is at the origin. (module only) Default: "origin"
|
||||
// spin = Rotate this many degrees around Z axis after anchor. (module only) Default: 0
|
||||
// orient = Vector to rotate top towards after spin (module only)
|
||||
// extent = use extent method for computing anchors. (module only) Default: false
|
||||
// cp = set centerpoint for anchor computation. (module only) Default: object 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)];
|
||||
|
@ -839,9 +856,16 @@ function sweep(shape, transformations, closed=false, caps) =
|
|||
assert(!closed || !caps, "Cannot make closed shape with caps")
|
||||
_skin_core([for(i=[0:len(transformations)-(closed?0:1)]) apply(transformations[i%len(transformations)],path3d(shape))],caps=fullcaps);
|
||||
|
||||
module sweep(shape, transformations, closed=false, caps, convexity=10) {
|
||||
vnf_polyhedron(sweep(shape, transformations, closed, caps), convexity=convexity);
|
||||
}
|
||||
module sweep(shape, transformations, closed=false, caps, convexity=10,
|
||||
anchor="origin",cp,spin=0, orient=UP, extent=false)
|
||||
{
|
||||
vnf = sweep(shape, transformations, closed, caps);
|
||||
attachable(anchor=anchor, spin=spin, orient=orient, vnf=vnf, extent=extent, cp=is_def(cp) ? cp : vnf_centroid(vnf))
|
||||
{
|
||||
vnf_polyhedron(vnf,convexity=convexity);
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Function&Module: path_sweep()
|
||||
|
@ -906,8 +930,13 @@ module sweep(shape, transformations, 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)
|
||||
// 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
|
||||
// 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
|
||||
// transforms = set to true to return transforms instead of a VNF. These transforms can be manipulated and passed to sweep(). Default: false.
|
||||
// anchor = Translate so anchor point is at the origin. (module only) Default: "origin"
|
||||
// spin = Rotate this many degrees around Z axis after anchor. (module only) Default: 0
|
||||
// orient = Vector to rotate top towards after spin (module only)
|
||||
// extent = use extent method for computing anchors. (module only) Default: false
|
||||
// cp = set centerpoint for anchor computation. (module only) Default: object 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]];
|
||||
|
@ -1121,13 +1150,19 @@ module sweep(shape, transformations, closed=false, caps, convexity=10) {
|
|||
// outside = [for(i=[0:len(trans)-1]) trans[i]*scale(lerp(1,1.5,i/(len(trans)-1)))];
|
||||
// inside = [for(i=[len(trans)-1:-1:0]) trans[i]*scale(lerp(1.1,1.4,i/(len(trans)-1)))];
|
||||
// sweep(shape, concat(outside,inside),closed=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, convexity=10,
|
||||
anchor="origin",cp,spin=0, orient=UP, extent=false)
|
||||
{
|
||||
vnf_polyhedron(path_sweep(shape, path, method, normal, closed, twist, twist_by_length,
|
||||
symmetry, last_normal, tangent, relaxed, caps), convexity=convexity);
|
||||
}
|
||||
vnf = path_sweep(shape, path, method, normal, closed, twist, twist_by_length,
|
||||
symmetry, last_normal, tangent, relaxed, caps);
|
||||
attachable(anchor=anchor, spin=spin, orient=orient, vnf=vnf, extent=extent, cp=is_def(cp) ? cp : vnf_centroid(vnf))
|
||||
{
|
||||
vnf_polyhedron(vnf,convexity=convexity);
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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) =
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
BOSL_VERSION = [2,0,402];
|
||||
BOSL_VERSION = [2,0,405];
|
||||
|
||||
|
||||
// Section: BOSL Library Version Functions
|
||||
|
|
Loading…
Reference in a new issue