mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2024-12-29 16:29:40 +00:00
commit
a9e87638b8
5 changed files with 168 additions and 23 deletions
|
@ -3333,7 +3333,7 @@ function _find_anchor(anchor, geom) =
|
|||
) [anchor, pos, vec, oang]
|
||||
) : type == "vnf_isect"? ( //vnf
|
||||
let( vnf=geom[1] )
|
||||
approx(anchor,CTR)? [anchor, [0,0,0], UP, 0] :
|
||||
approx(anchor,CTR)? [anchor, cp, UP, 0] : // CENTER anchors anchor on cp, "origin" anchors on [0,0]
|
||||
vnf==EMPTY_VNF? [anchor, [0,0,0], unit(anchor), 0] :
|
||||
let(
|
||||
eps = 1/2048,
|
||||
|
@ -3383,7 +3383,7 @@ function _find_anchor(anchor, geom) =
|
|||
[anchor, pos, n, oang]
|
||||
) : type == "vnf_extent"? ( //vnf
|
||||
let( vnf=geom[1] )
|
||||
approx(anchor,CTR)? [anchor, [0,0,0], UP, 0] :
|
||||
approx(anchor,CTR)? [anchor, cp, UP, 0] : // CENTER anchors anchor on cp, "origin" anchors on [0,0]
|
||||
vnf==EMPTY_VNF? [anchor, [0,0,0], unit(anchor,UP), 0] :
|
||||
let(
|
||||
rpts = apply(rot(from=anchor, to=RIGHT) * move(point3d(-cp)), vnf[0]),
|
||||
|
@ -3432,7 +3432,7 @@ function _find_anchor(anchor, geom) =
|
|||
anchor = _force_anchor_2d(anchor),
|
||||
rgn = force_region(move(-point2d(cp), p=geom[1]))
|
||||
)
|
||||
approx(anchor,[0,0])? [anchor, [0,0,0], BACK, 0] :
|
||||
approx(anchor,[0,0])? [anchor, cp, BACK, 0] : // CENTER anchors anchor on cp, "origin" anchors on [0,0]
|
||||
let(
|
||||
isects = [
|
||||
for (path=rgn, t=triplet(path,true)) let(
|
||||
|
@ -3456,7 +3456,7 @@ function _find_anchor(anchor, geom) =
|
|||
) [anchor, pos, vec, 0]
|
||||
) : type == "rgn_extent"? ( //region
|
||||
let( anchor = _force_anchor_2d(anchor) )
|
||||
approx(anchor,[0,0])? [anchor, [0,0,0], BACK, 0] :
|
||||
approx(anchor,[0,0])? [anchor, cp, BACK, 0] : // CENTER anchors anchor on cp, "origin" anchors on [0,0]
|
||||
let(
|
||||
rgn = force_region(geom[1]),
|
||||
rpts = rot(from=anchor, to=RIGHT, p=flatten(rgn)),
|
||||
|
|
|
@ -1365,8 +1365,13 @@ module offset_stroke(path, width=1, rounded=true, start, end, check_valid=true,
|
|||
// 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)
|
||||
// atype = Select "hull" or "intersect" anchor types. Default: "hull"
|
||||
// atype = Select "hull", "intersect", "surf_hull" or "surf_intersect" anchor types. Default: "hull"
|
||||
// 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"
|
||||
// Anchor Types:
|
||||
// hull = Anchors to the convex hull of the linear sweep of the path, ignoring any end roundings.
|
||||
// intersect = Anchors to the surface of the linear sweep of the path, ignoring any end roundings.
|
||||
// surf_hull = Anchors to the convex hull of the offset_sweep shape, including end treatments.
|
||||
// surf_intersect = Anchors to the surface of the offset_sweep shape, including any end treatments.
|
||||
// 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);
|
||||
|
@ -1641,12 +1646,21 @@ module offset_sweep(path, height,
|
|||
convexity=10,anchor="origin",cp="centroid",
|
||||
spin=0, orient=UP, atype="hull")
|
||||
{
|
||||
assert(in_list(atype, _ANCHOR_TYPES), "Anchor type must be \"hull\" or \"intersect\"");
|
||||
assert(in_list(atype, ["intersect","hull","surf_hull","surf_intersect"]), "Anchor type must be \"hull\" or \"intersect\"");
|
||||
vnf = offset_sweep(path=path, height=height, h=h, l=l, top=top, bottom=bottom, offset=offset, r=r, steps=steps,
|
||||
quality=quality, check_valid=check_valid, extra=extra, cut=cut, chamfer_width=chamfer_width,
|
||||
chamfer_height=chamfer_height, joint=joint, k=k, angle=angle);
|
||||
vnf_polyhedron(vnf,convexity=convexity,anchor=anchor, spin=spin, orient=orient, atype=atype, cp=cp)
|
||||
children();
|
||||
|
||||
if (in_list(atype,["hull","intersect"])){
|
||||
h=first_defined([h,l,height]);
|
||||
attachable(anchor,spin,orient,region=[path],h=h,extent=atype=="hull",cp=cp){
|
||||
down(h/2)polyhedron(vnf[0],vnf[1],convexity=convexity);
|
||||
children();
|
||||
}
|
||||
}
|
||||
else
|
||||
vnf_polyhedron(vnf,convexity=convexity,anchor=anchor, spin=spin, orient=orient, atype=atype=="surf_hull"?"hull":"intersect", cp=cp)
|
||||
children();
|
||||
}
|
||||
|
||||
|
||||
|
@ -2012,6 +2026,11 @@ function _rp_compute_patches(top, bot, rtop, rsides, ktop, ksides, concave) =
|
|||
// joint_top[1] is negative the shape will flare upward. At least one value must be non-negative. The same rules apply for joint_bot.
|
||||
// The joint_sides parameter must be entirely nonnegative.
|
||||
// .
|
||||
// If the roundings at two adjacent side edges exceed the width of the face then the polyhedron will have self-intersecting faces, so it will be invalid.
|
||||
// Similarly, if the roundings on the top or bottom edges cross the top face and intersect with each other, the resulting polyhedron is invalid:
|
||||
// the top face after the roundings are applied must be a valid, non-degenerate polyhedron. There are two exceptions: it is permissible to
|
||||
// construct a top that is a single point or two points. This means you can completely round a cube by setting the joint to half of
|
||||
// the cube's width.
|
||||
// If you set `debug` to true the module version will display the polyhedron even when it is invalid and it will show the bezier patches at the corners.
|
||||
// This can help troubleshoot problems with your parameters. With the function form setting debug to true causes it to return [patches,vnf] where
|
||||
// patches is a list of the bezier control points for the corner patches.
|
||||
|
@ -2032,7 +2051,7 @@ function _rp_compute_patches(top, bot, rtop, rsides, ktop, ksides, concave) =
|
|||
// k = continuous curvature rounding parameter for all edges. Default: 0.5
|
||||
// k_top = continuous curvature rounding parameter for top
|
||||
// k_bot = continuous curvature rounding parameter for bottom
|
||||
// k_bot = continuous curvature rounding parameter for bottom
|
||||
// k_sides = continuous curvature rounding parameter side edges, a number or vector.
|
||||
// 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
|
||||
|
@ -2196,23 +2215,44 @@ function rounded_prism(bottom, top, joint_bot=0, joint_top=0, joint_sides=0, k_b
|
|||
bot_patch = _rp_compute_patches(bottom, top, joint_bot, joint_sides_vec, k_bot, k_sides_vec, concave),
|
||||
|
||||
vertbad = [for(i=[0:N-1])
|
||||
if (norm(top[i]-top_patch[i][4][2]) + norm(bottom[i]-bot_patch[i][4][2]) > norm(bottom[i]-top[i])) i],
|
||||
if (norm(top[i]-top_patch[i][4][2]) + norm(bottom[i]-bot_patch[i][4][2]) > EPSILON + norm(bottom[i]-top[i])) i],
|
||||
// Check that the patch fits on the polygon edge
|
||||
topbad = [for(i=[0:N-1])
|
||||
if (norm(top_patch[i][2][4]-top_patch[i][2][2]) + norm(select(top_patch,i+1)[2][0]-select(top_patch,i+1)[2][2])
|
||||
> norm(top_patch[i][2][2] - select(top_patch,i+1)[2][2])) [i,(i+1)%N]],
|
||||
> EPSILON + norm(top_patch[i][2][2] - select(top_patch,i+1)[2][2])) [i,(i+1)%N]],
|
||||
botbad = [for(i=[0:N-1])
|
||||
if (norm(bot_patch[i][2][4]-bot_patch[i][2][2]) + norm(select(bot_patch,i+1)[2][0]-select(bot_patch,i+1)[2][2])
|
||||
> norm(bot_patch[i][2][2] - select(bot_patch,i+1)[2][2])) [i,(i+1)%N]],
|
||||
topinbad = [for(i=[0:N-1])
|
||||
> EPSILON + norm(bot_patch[i][2][2] - select(bot_patch,i+1)[2][2])) [i,(i+1)%N]],
|
||||
// If top/bot is L-shaped, check that arms of L from adjacent patches don't cross
|
||||
topLbad = [for(i=[0:N-1])
|
||||
if (norm(top_patch[i][0][2]-top_patch[i][0][4]) + norm(select(top_patch,i+1)[0][0]-select(top_patch,i+1)[0][2])
|
||||
> norm(top_patch[i][0][2]-select(top_patch,i+1)[0][2])) [i,(i+1)%N]],
|
||||
botinbad = [for(i=[0:N-1])
|
||||
> EPSILON + norm(top_patch[i][0][2]-select(top_patch,i+1)[0][2])) [i,(i+1)%N]],
|
||||
botLbad = [for(i=[0:N-1])
|
||||
if (norm(bot_patch[i][0][2]-bot_patch[i][0][4]) + norm(select(bot_patch,i+1)[0][0]-select(bot_patch,i+1)[0][2])
|
||||
> norm(bot_patch[i][0][2]-select(bot_patch,i+1)[0][2])) [i,(i+1)%N]]
|
||||
> EPSILON + norm(bot_patch[i][0][2]-select(bot_patch,i+1)[0][2])) [i,(i+1)%N]],
|
||||
// Check that the inner edges of the patch don't cross
|
||||
topinbad = [for(i=[0:N-1])
|
||||
let(
|
||||
line1 = project_plane(top,[top_patch[i][2][0],top_patch[i][0][0]]),
|
||||
line2 = project_plane(top,[select(top_patch,i+1)[2][4],select(top_patch,i+1)[0][4]])
|
||||
)
|
||||
if (!approx(line1[0],line1[1]) && !approx(line2[0],line2[1]) &&
|
||||
line_intersection(line1,line2, SEGMENT,SEGMENT))
|
||||
[i,(i+1)%N]],
|
||||
botinbad = [for(i=[0:N-1])
|
||||
let(
|
||||
line1 = project_plane(bottom,[bot_patch[i][2][0],bot_patch[i][0][0]]),
|
||||
line2 = project_plane(bottom,[select(bot_patch,i+1)[2][4],select(bot_patch,i+1)[0][4]])
|
||||
)
|
||||
if (!approx(line1[0],line1[1]) && !approx(line2[0],line2[1]) &&
|
||||
line_intersection(line1,line2, SEGMENT,SEGMENT))
|
||||
[i,(i+1)%N]]
|
||||
)
|
||||
assert(debug || vertbad==[], str("Top and bottom joint lengths are too large; they interfere with each other at vertices: ",vertbad))
|
||||
assert(debug || topbad==[], str("Joint lengths too large at top edges: ",topbad))
|
||||
assert(debug || botbad==[], str("Joint lengths too large at bottom edges: ",botbad))
|
||||
assert(debug || topbad==[], str("Joint lengths too large at top or side edges: ",topbad))
|
||||
assert(debug || botbad==[], str("Joint lengths too large at bottom or side edges: ",botbad))
|
||||
assert(debug || topLbad==[], str("Joint length too large on the top face or side at edges: ", topLbad))
|
||||
assert(debug || botLbad==[], str("Joint length too large on the bottom face or side at edges: ", botLbad))
|
||||
assert(debug || topinbad==[], str("Joint length too large on the top face at edges: ", topinbad))
|
||||
assert(debug || botinbad==[], str("Joint length too large on the bottom face at edges: ", botinbad))
|
||||
let(
|
||||
|
@ -2242,8 +2282,12 @@ function rounded_prism(bottom, top, joint_bot=0, joint_top=0, joint_sides=0, k_b
|
|||
top_patch[i][4][4]
|
||||
]
|
||||
],
|
||||
top_simple = is_path_simple(project_plane(faces[0],faces[0]),closed=true),
|
||||
bot_simple = is_path_simple(project_plane(faces[1],faces[1]),closed=true),
|
||||
top_collinear = is_collinear(faces[0]),
|
||||
bot_collinear = is_collinear(faces[1]),
|
||||
top_degen_ok = top_collinear && len(deduplicate(faces[0]))<=2,
|
||||
bot_degen_ok = bot_collinear && len(deduplicate(faces[1]))<=2,
|
||||
top_simple = top_degen_ok || (!top_collinear && is_path_simple(project_plane(faces[0],faces[0]),closed=true)),
|
||||
bot_simple = bot_degen_ok || (!bot_collinear && is_path_simple(project_plane(faces[1],faces[1]),closed=true)),
|
||||
// verify vertical edges
|
||||
verify_vert =
|
||||
[for(i=[0:N-1],j=[0:4])
|
||||
|
|
|
@ -3349,7 +3349,11 @@ module fillet(l=1.0, r, ang=90, overlap=0.01, d, length, h, height, anchor=CENTE
|
|||
arc[0] + polar_to_xy(overlap, 90+ang),
|
||||
each arc
|
||||
];
|
||||
attachable(anchor,spin,orient, size=[2*maxx,2*maxy,l]) {
|
||||
override = function (anchor)
|
||||
anchor.x>=0 && anchor.y>=0 ? undef
|
||||
:
|
||||
[[max(0,anchor.x)*maxx, max(0,anchor.y)*maxy, anchor.z*l/2]];
|
||||
attachable(anchor,spin,orient, size=[2*maxx,2*maxy,l],override=override) {
|
||||
if (l > 0) {
|
||||
linear_extrude(height=l, convexity=4, center=true) {
|
||||
polygon(path);
|
||||
|
|
|
@ -1262,7 +1262,7 @@ module cubic_barbell(s=100, anchor=CENTER, spin=0, orient=UP) {
|
|||
children();
|
||||
}
|
||||
}
|
||||
cubic_barbell(100) show_anchors(30);
|
||||
cubic_barbell(100) show_anchors(60);
|
||||
```
|
||||
|
||||
When the shape is prismoidal, where the top is a different size from the bottom, you can use
|
||||
|
@ -1637,3 +1637,99 @@ sphere_pt = apply(
|
|||
```
|
||||
|
||||
|
||||
## Overriding Standard Anchors
|
||||
|
||||
Sometimes you may want to use the standard anchors but override some
|
||||
of them. Returning to the square barebell example above, the anchors
|
||||
at the right and left sides are on the cubes at each end, but the
|
||||
anchors at x=0 are in floating in space. For prismoidal/cubic anchors
|
||||
in 3D and trapezoidal/rectangular anchors in 2D we can override a single anchor by
|
||||
specifying the override option and giving the anchor that is being
|
||||
overridden, and then the replacement in the form
|
||||
`[position, direction, spin]`. Most often you will only want to
|
||||
override the position. If you omit the other list items then the
|
||||
value drived from the standard anchor will be used. Below we override
|
||||
position of the FWD anchor:
|
||||
|
||||
```
|
||||
module cubic_barbell(s=100, anchor=CENTER, spin=0, orient=UP) {
|
||||
override = [
|
||||
[FWD, [[0,-s/8,0]]]
|
||||
];
|
||||
attachable(anchor,spin,orient, size=[s*3,s,s],override=override) {
|
||||
union() {
|
||||
xcopies(2*s) cube(s, center=true);
|
||||
xcyl(h=2*s, d=s/4);
|
||||
}
|
||||
children();
|
||||
}
|
||||
}
|
||||
cubic_barbell(100) show_anchors(60);
|
||||
```
|
||||
|
||||
Note how the FWD anchor is now rooted on the cylindrical portion. If
|
||||
you wanted to also change its direction and spin you could do it like
|
||||
this:
|
||||
|
||||
```
|
||||
module cubic_barbell(s=100, anchor=CENTER, spin=0, orient=UP) {
|
||||
override = [
|
||||
[FWD, [[0,-s/8,0], FWD+LEFT, 225]]
|
||||
];
|
||||
attachable(anchor,spin,orient, size=[s*3,s,s],override=override) {
|
||||
union() {
|
||||
xcopies(2*s) cube(s, center=true);
|
||||
xcyl(h=2*s, d=s/4);
|
||||
}
|
||||
children();
|
||||
}
|
||||
}
|
||||
cubic_barbell(100) show_anchors(60);
|
||||
```
|
||||
|
||||
In the above example we give three values for the override. As
|
||||
before, the first one places the anchor on the cylinder. We have
|
||||
added the second entry which points the anchor off to the left.
|
||||
The third entry gives a spin override, whose effect is shown by the
|
||||
position of the red flag on the arrow. If you want to override all of
|
||||
the x=0 anchors to be on the cylinder, with their standard directions,
|
||||
you can do that by supplying a list:
|
||||
```
|
||||
module cubic_barbell(s=100, anchor=CENTER, spin=0, orient=UP) {
|
||||
override = [
|
||||
for(j=[-1:1:1], k=[-1:1:1])
|
||||
if ([j,k]!=[0,0]) [[0,j,k], [s/8*unit([0,j,k])]]
|
||||
];
|
||||
attachable(anchor,spin,orient, size=[s*3,s,s],override=override) {
|
||||
union() {
|
||||
xcopies(2*s) cube(s, center=true);
|
||||
xcyl(h=2*s, d=s/4);
|
||||
}
|
||||
children();
|
||||
}
|
||||
}
|
||||
cubic_barbell(100) show_anchors(30);
|
||||
```
|
||||
|
||||
Now all of the anchors in the middle are all rooted to the cylinder. Another
|
||||
way to do the same thing is to use a function literal for override.
|
||||
It will be called with the anchor as its argument and needs to return undef to just use
|
||||
the default, or a `[position, direction, spin]` triple to override the
|
||||
default. As before, you can omit values to keep their default.
|
||||
Here is the same example using a function literal for the override:
|
||||
|
||||
```
|
||||
module cubic_barbell(s=100, anchor=CENTER, spin=0, orient=UP) {
|
||||
override = function (anchor)
|
||||
anchor.x!=0 || anchor==CTR ? undef // Keep these
|
||||
: [s/8*unit(anchor)];
|
||||
attachable(anchor,spin,orient, size=[s*3,s,s],override=override) {
|
||||
union() {
|
||||
xcopies(2*s) cube(s, center=true);
|
||||
xcyl(h=2*s, d=s/4);
|
||||
}
|
||||
children();
|
||||
}
|
||||
}
|
||||
cubic_barbell(100) show_anchors(30);
|
||||
```
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
|
||||
|
||||
|
||||
BOSL_VERSION = [2,0,710];
|
||||
BOSL_VERSION = [2,0,714];
|
||||
|
||||
|
||||
|
||||
// Section: BOSL Library Version Functions
|
||||
|
|
Loading…
Reference in a new issue