Merge pull request #1670 from adrianVmariano/master

add bot_corner to teardrop2d()
This commit is contained in:
adrianVmariano
2025-05-05 21:22:12 -04:00
committed by GitHub
2 changed files with 88 additions and 30 deletions

View File

@@ -1321,26 +1321,33 @@ module jittered_poly(path, dist=1/512) {
// Section: Curved 2D Shapes
// When called as a module, makes a 2D teardrop shape. Useful for extruding into 3D printable holes as it limits overhang to a desired angle.
// Uses "intersect" style anchoring.
// Function&Module: teardrop2d()
// Synopsis: Creates a 2D teardrop shape.
// SynTags: Geom, Path
// Topics: Shapes (2D), Paths (2D), Path Generators, Attachable
// See Also: teardrop(), onion(), keyhole()
// Description:
// When called as a module, makes a 2D teardrop shape. Useful for extruding into 3D printable holes as it limits overhang to 45 degrees. Uses "intersect" style anchoring.
// The cap_h parameter truncates the top of the teardrop. If cap_h is taller than the untruncated form then
// the result will be the full, untruncated shape. The segments of the bottom section of the teardrop are
// calculated to be the same as a circle or cylinder when rotated 90 degrees. (Note that this agreement is poor when `$fn=6` or `$fn=7`.
// A teardrop shape is a circle that comes to a point at the top. This shape is useful for extruding into 3d printable holes as it
// limits the overhang angle. A bottom point can also help ensure a 3d printable hole. This module can make a teardrop shape
// or produce the path for a teardrop with a point at the top or with the top truncated to create a flat cap. It also provides the option to add a bottom point.
// .
// The default teardrop has a pointed top and round bottom. The `ang` parameter specifies the angle away from vertical of the two flat segments at the
// top of the shape. The cap_h parameter truncates the top of the teardrop at the specified
// distance from the center. If `cap_h` is taller than the untruncated form then
// the result will be the full, untruncated shape. You can set `cap_h` smaller than the radius to produce a truncated circle. The segments of the round section of the teardrop
// are the same as a circle or cylinder with matching `$fn` when rotated 90 degrees. The number of facets in the teardrop is only approximately
// equal to `$fn`, and may also change if you set `realign=true`, which adjusts the facets so the bottom of the teardrop has a flat base.
// If `$fn` is a multiple of four then the teardrop will reach its extremes on all four axes. The circum option
// produces a teardrop that circumscribes the circle; in this case set `realign=true` to get a teardrop that meets its internal extremes
// on the axes.
// When called as a function, returns a 2D path to for a teardrop shape.
//
// produces a teardrop that circumscribes the circle; in this, `realign=true` produces a teardrop that meets its internal extremes
// on the axes. You can add a bottom corner using the `bot_corner` parameter, which specifies the length that the corner protrudes from the ideal circle.
// Usage: As Module
// teardrop2d(r/d=, [ang], [cap_h]) [ATTACHMENTS];
// teardrop2d(r/d=, [ang], [cap_h], [circum=], [realign=], [bot_corner=]) [ATTACHMENTS];
// Usage: As Function
// path = teardrop2d(r|d=, [ang], [cap_h]);
//
// path = teardrop2d(r|d=, [ang], [cap_h], [circum=], [realign=], [bot_corner=]);
// Arguments:
// r = radius of circular part of teardrop. (Default: 1)
// ang = angle of hat walls from the Y axis (half the angle of the peak). (Default: 45 degrees)
@@ -1348,19 +1355,22 @@ module jittered_poly(path, dist=1/512) {
// ---
// d = diameter of circular portion of bottom. (Use instead of r)
// circum = if true, create a circumscribing teardrop. Default: false
// bot_corner = create a bottom corner the specified distance below the given radius. Default: 0
// realign = if true, change whether bottom of teardrop is a point or a flat. Default: false
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
//
// Example(2D): Typical Shape
// teardrop2d(r=30, ang=30);
// Example(2D): Crop Cap
// teardrop2d(r=30, ang=30, cap_h=40);
// Example(2D): Close Crop
// teardrop2d(r=30, ang=30, cap_h=20);
module teardrop2d(r, ang=45, cap_h, d, circum=false, realign=false, anchor=CENTER, spin=0)
// Example(2D): Add bottom corner. Here the bottom corner is quite large. Guidance for 3d printing suggests that `bot_corner` should equal the layer thickness.
// teardrop2d(r=30, cap_h=35, bot_corner=5);
module teardrop2d(r, ang=45, cap_h, d, circum=false, realign=false, bot_corner=0, anchor=CENTER, spin=0)
{
path = teardrop2d(r=r, d=d, ang=ang, circum=circum, realign=realign, cap_h=cap_h);
path = teardrop2d(r=r, d=d, ang=ang, circum=circum, realign=realign, cap_h=cap_h, bot_corner=bot_corner);
attachable(anchor,spin, two_d=true, path=path, extent=false) {
polygon(path);
children();
@@ -1370,9 +1380,32 @@ module teardrop2d(r, ang=45, cap_h, d, circum=false, realign=false, anchor=CENTE
// _extrapt = true causes the point to be duplicated so a teardrop with no cap
// has the same point count as one with a cap.
function teardrop2d(r, ang=45, cap_h, d, circum=false, realign=false, anchor=CENTER, spin=0, _extrapt=false) =
function teardrop2d(r, ang=45, cap_h, d, circum=false, realign=false, anchor=CENTER, spin=0, bot_corner=0, _extrapt=false) =
let(
r = get_radius(r=r, d=d, dflt=1)
)
bot_corner!=0 ?
assert(all_nonnegative([bot_corner]),"bot_corner must be nonnegative")
let(
path = teardrop2d(r=r,ang=ang, cap_h=cap_h, circum=circum, realign=realign),
corner = -r-bot_corner,
alpha = acos(r/corner),
joint = r*[sin(alpha),cos(alpha)],
table = [[0,corner],joint],
halfpath = [for(pt=path) if (pt.x>=0)
let(proj=lookup(pt.x,table))
pt.x>joint.x || pt.y>0 || pt.y<=proj ? pt : [pt.x,proj]],
fullpath = deduplicate(
[
each halfpath,
if (last(halfpath).x>0) [0,corner],
each reverse(xflip(halfpath))
], closed=!_extrapt
)
)
reorient(anchor,spin,two_d=true, path=fullpath, p=fullpath, extent=false)
:
let(
r = get_radius(r=r, d=d, dflt=1),
minheight = r*sin(ang),
maxheight = r/sin(ang), //cos(90-ang),
pointycap = is_undef(cap_h) || cap_h>=maxheight

View File

@@ -3564,19 +3564,21 @@ function torus(
// Topics: Shapes (3D), Attachable, VNF Generators, FDM Optimized
// See Also: onion(), teardrop2d()
// Description:
// Makes a teardrop shape in the XZ plane. Useful for 3D printable holes.
// Makes a teardrop extrusion along the Y axis, which is useful for 3D printable holes.
// Optional chamfers can be added with positive or negative distances. A positive distance
// specifies the amount to inset the chamfer along the front/back faces of the shape.
// The chamfer will extend the same y distance into the shape. If the radii are the same
// then the chamfer will be a 45 degree chamfer, but in other cases it will not.
// Note that with caps, the chamfer must not be so big that it makes the cap height illegal.
//
// With caps, the chamfer must not be so big that it makes the cap height illegal.
// Similarly the chamfer cannot be larger than `bot_corner` if it is set, and if you do
// set chamfer exactly equal to bottom corner, then `$fn` must be even if `realign` is false
// and odd otherwise.
// Usage: Typical
// teardrop(h|l=|length=|height=, r, [ang], [cap_h], [chamfer=], ...) [ATTACHMENTS];
// teardrop(h|l=|length=|height=, d=, [ang=], [cap_h=], [chamfer=], ...) [ATTACHMENTS];
// teardrop(h|l=|length=|height=, r, [ang], [cap_h], [chamfer=], [bot_corner=], ...) [ATTACHMENTS];
// teardrop(h|l=|length=|height=, d=, [ang=], [cap_h=], [chamfer=], [bot_corner=], ...) [ATTACHMENTS];
// Usage: Psuedo-Conical
// teardrop(h|l=|height=|length=, r1=, r2=, [ang=], [cap_h1=], [cap_h2=], ...) [ATTACHMENTS];
// teardrop(h|l=|height=|length=, d1=, d2=, [ang=], [cap_h1=], [cap_h2=], ...) [ATTACHMENTS];
// teardrop(h|l=|height=|length=, r1=, r2=, [ang=], [cap_h1=], [cap_h2=], [bot_corner1=], [bot_corner2=], ...) [ATTACHMENTS];
// teardrop(h|l=|height=|length=, d1=, d2=, [ang=], [cap_h1=], [cap_h2=], [bot_corner1=], [bot_corner2=], ...) [ATTACHMENTS];
// Usage: As Function
// vnf = teardrop(h|l=|height=|length=, r|d=, [ang=], [cap_h=], ...);
// vnf = teardrop(h|l=|height=|length=, r1=|d1=, r2=|d2=, [ang=], [cap_h=], ...);
@@ -3619,6 +3621,8 @@ function torus(
// teardrop(r1=20, r2=30, h=40, cap_h1=25, cap_h2=35);
// Example: Adding chamfers can be useful for a teardrop hole mask
// teardrop(r=10, l=50, chamfer1=2, chamfer2=-1.5);
// Example: This teardrop has a 1 unit clearance at the top and bottom using the cap and the bottom corner:
// teardrop(r=10, l=50, cap_h=11, bot_corner=1);
// Example: Getting a VNF
// vnf = teardrop(r1=25, r2=30, l=20, cap_h1=25, cap_h2=35);
// vnf_polyhedron(vnf);
@@ -3628,9 +3632,22 @@ function torus(
// Example(Spin,VPD=150,Med): Named Conical Connectors
// teardrop(d1=20, d2=30, h=20, cap_h1=11, cap_h2=16)
// show_anchors(std=false);
// Example: Creating holes using attachment
// $fn=32;
// diff()
// cuboid(15)
// attach([FWD,RIGHT],FWD,inside=true, shiftout=.1)
// tag("remove")teardrop(d=4, l=10);
// Example: You can rotate the point using the `spin` option to {{attach()}}. Don't use the `spin` parameter to `teardrop()`.
// $fn=32;
// diff()
// cuboid(15)
// attach(FWD,FWD,align=[TOP,BOT], inset=2,
// inside=true, shiftout=.1, spin=90)
// tag("remove")teardrop(d=4, l=10);
module teardrop(h, r, ang=45, cap_h, r1, r2, d, d1, d2, cap_h1, cap_h2, l, length, height, circum=false, realign=false,
chamfer, chamfer1, chamfer2,anchor=CENTER, spin=0, orient=UP)
chamfer, chamfer1, chamfer2,anchor=CENTER, spin=0, orient=UP, bot_corner1, bot_corner2, bot_corner=0)
{
length = one_defined([l, h, length, height],"l,h,length,height");
dummy=assert(is_finite(length) && length>0, "length must be positive");
@@ -3649,13 +3666,13 @@ module teardrop(h, r, ang=45, cap_h, r1, r2, d, d1, d2, cap_h1, cap_h2, l, lengt
attachable(anchor,spin,orient, r1=r1, r2=r2, l=length, axis=BACK, anchors=anchors)
{
vnf_polyhedron(teardrop(ang=ang,cap_h=cap_h,r1=r1,r2=r2,cap_h1=cap_h1,cap_h2=cap_h2,circum=circum,realign=realign,
length=length, chamfer1=chamfer1,chamfer2=chamfer2,chamfer=chamfer));
length=length, chamfer1=chamfer1,chamfer2=chamfer2,chamfer=chamfer,bot_corner1=bot_corner1, bot_corner2=bot_corner2,bot_corner=bot_corner));
children();
}
}
function teardrop(h, r, ang=45, cap_h, r1, r2, d, d1, d2, cap_h1, cap_h2, chamfer, chamfer1, chamfer2, circum=false, realign=false,
function teardrop(h, r, ang=45, cap_h, r1, r2, d, d1, d2, cap_h1, cap_h2, chamfer, chamfer1, chamfer2, circum=false, realign=false, bot_corner1, bot_corner2, bot_corner=0,
l, length, height, anchor=CENTER, spin=0, orient=UP) =
let(
r1 = get_radius(r=r, r1=r1, d=d, d1=d1, dflt=1),
@@ -3664,11 +3681,13 @@ function teardrop(h, r, ang=45, cap_h, r1, r2, d, d1, d2, cap_h1, cap_h2, chamf
dummy0=assert(is_finite(length) && length>0, "length must be positive"),
cap_h1 = first_defined([cap_h1, cap_h]),
cap_h2 = first_defined([cap_h2, cap_h]),
bot_corner1 = first_defined([bot_corner1, bot_corner]),
bot_corner2 = first_defined([bot_corner2, bot_corner]),
chamfer1 = first_defined([chamfer1,chamfer,0]),
chamfer2 = first_defined([chamfer2,chamfer,0]),
sides = segs(max(r1,r2)),
profile1 = teardrop2d(r=r1, ang=ang, cap_h=cap_h1, $fn=sides, circum=circum, realign=realign,_extrapt=true),
profile2 = teardrop2d(r=r2, ang=ang, cap_h=cap_h2, $fn=sides, circum=circum, realign=realign,_extrapt=true),
profile1 = teardrop2d(r=r1, ang=ang, cap_h=cap_h1, $fn=sides, circum=circum, realign=realign,_extrapt=true, bot_corner=bot_corner1),
profile2 = teardrop2d(r=r2, ang=ang, cap_h=cap_h2, $fn=sides, circum=circum, realign=realign,_extrapt=true, bot_corner=bot_corner2),
tip_y1 = r1/cos(90-ang),
tip_y2 = r2/cos(90-ang),
_cap_h1 = min(default(cap_h1, tip_y1), tip_y1),
@@ -3677,12 +3696,18 @@ function teardrop(h, r, ang=45, cap_h, r1, r2, d, d1, d2, cap_h1, cap_h2, chamf
dummy=
assert(abs(chamfer1)+abs(chamfer2) <= length,"chamfers are too big to fit in the length")
assert(chamfer1<=r1 && chamfer2<=r2, "Chamfers cannot be larger than raduis")
assert(bot_corner1==0 || bot_corner1>=chamfer1, "\nchamfer1 doesn't work with bottom corner: must have chamfer1 <= bot_corner1")
assert(bot_corner2==0 || bot_corner2>=chamfer2, "\nchamfer2 doesn't work with bottom corner: must have chamfer2 <= bot_corner2")
assert(bot_corner1==0 || bot_corner1>chamfer1 || sides%2==(realign?1:0),
str("\nWith chamfer1==bot_corner1 and realign=",realign," must have ",realign?"odd":"even"," number of sides, but sides=",sides))
assert(is_undef(cap_h1) || cap_h1-chamfer1 > r1*sin(ang), "chamfer1 is too big to work with the specified cap_h1")
assert(is_undef(cap_h2) || cap_h2-chamfer2 > r2*sin(ang), "chamfer2 is too big to work with the specified cap_h2"),
cprof1 = r1==chamfer1 ? repeat([0,0],len(profile1))
: teardrop2d(r=r1-chamfer1, ang=ang, cap_h=u_add(cap_h1,-chamfer1), $fn=sides, circum=circum, realign=realign,_extrapt=true),
: teardrop2d(r=r1-chamfer1, ang=ang, cap_h=u_add(cap_h1,-chamfer1), bot_corner=bot_corner1==0?0:bot_corner1-chamfer1,
$fn=sides, circum=circum, realign=realign,_extrapt=true),
cprof2 = r2==chamfer2 ? repeat([0,0],len(profile2))
: teardrop2d(r=r2-chamfer2, ang=ang, cap_h=u_add(cap_h2,-chamfer2), $fn=sides, circum=circum, realign=realign,_extrapt=true),
: teardrop2d(r=r2-chamfer2, ang=ang, cap_h=u_add(cap_h2,-chamfer2), bot_corner=bot_corner2==0?0:bot_corner2-chamfer2,
$fn=sides, circum=circum, realign=realign,_extrapt=true),
anchors = [
named_anchor("cap", [0,0,(_cap_h1+_cap_h2)/2], capvec),
named_anchor("cap_fwd", [0,-length/2,_cap_h1], unit((capvec+FWD)/2)),