diff --git a/shapes.scad b/shapes.scad index f1f2224..03d1a4a 100644 --- a/shapes.scad +++ b/shapes.scad @@ -1036,45 +1036,6 @@ module staggered_sphere(r=undef, d=undef, circum=false, anchor=CENTER, spin=0, o // Section: 3D Printing Shapes -// Module: teardrop2d() -// -// Description: -// Makes a 2D teardrop shape. Useful for extruding into 3D printable holes. -// -// Usage: -// teardrop2d(r|d, [ang], [cap_h]); -// -// Arguments: -// r = radius of circular part of teardrop. (Default: 1) -// d = diameter of spherical portion of bottom. (Use instead of r) -// ang = angle of hat walls from the Y axis. (Default: 45 degrees) -// cap_h = if given, height above center where the shape will be truncated. -// -// 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=1, d=undef, ang=45, cap_h=undef) -{ - eps = 0.01; - r = get_radius(r=r, d=d, dflt=1); - cord = 2 * r * cos(ang); - cord_h = r * sin(ang); - tip_y = (cord/2)/tan(ang); - cap_h = min((!is_undef(cap_h)? cap_h : tip_y+cord_h), tip_y+cord_h); - cap_w = cord * (1 - (cap_h - cord_h)/tip_y); - difference() { - hull() { - zrot(90) circle(r=r); - back(cap_h-eps/2) square([max(eps,cap_w), eps], center=true); - } - back(r+cap_h) square(2*r, center=true); - } -} - - // Module: teardrop() // // Description: diff --git a/shapes2d.scad b/shapes2d.scad index d98613a..0943097 100644 --- a/shapes2d.scad +++ b/shapes2d.scad @@ -189,9 +189,6 @@ module stroke( } -// Section: 2D Shapes - - // Function&Module: arc() // Usage: 2D arc from 0ยบ to `angle` degrees. // arc(N, r|d, angle); @@ -310,363 +307,6 @@ function _normal_segment(p1,p2) = [center, center + norm(p1-p2)/2 * line_normal(p1,p2)]; -// Function&Module: trapezoid() -// Usage: -// trapezoid(h, w1, w2); -// Description: -// When called as a function, returns a 2D path for a trapezoid with parallel front and back sides. -// When called as a module, creates a 2D trapezoid with parallel front and back sides. -// Arguments: -// h = The Y axis height of the trapezoid. -// w1 = The X axis width of the front end of the trapezoid. -// w2 = The X axis width of the back end of the trapezoid. -// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER` -// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0` -// Examples(2D): -// trapezoid(h=30, w1=40, w2=20); -// trapezoid(h=25, w1=20, w2=35); -// trapezoid(h=20, w1=40, w2=0); -// Example(2D): Called as Function -// stroke(closed=true, trapezoid(h=30, w1=40, w2=20)); -function trapezoid(h, w1, w2, anchor=CENTER, spin=0) = - let( - s = anchor.y>0? [w2,h] : anchor.y<0? [w1,h] : [(w1+w2)/2,h], - path = [[w1/2,-h/2], [-w1/2,-h/2], [-w2/2,h/2], [w2/2,h/2]] - ) rot(spin, p=move(-vmul(anchor,s/2), p=path)); - - - -module trapezoid(h, w1, w2, anchor=CENTER, spin=0) - polygon(trapezoid(h=h, w1=w1, w2=w2, anchor=anchor, spin=spin)); - - -// Function&Module: regular_ngon() -// Usage: -// regular_ngon(n, r|d|or|od, [realign]); -// regular_ngon(n, ir|id, [realign]); -// regular_ngon(n, side, [realign]); -// Description: -// When called as a function, returns a 2D path for a regular N-sided polygon. -// When called as a module, creates a 2D regular N-sided polygon. -// Arguments: -// n = The number of sides. -// or = Outside radius, at points. -// r = Same as or -// od = Outside diameter, at points. -// d = Same as od -// ir = Inside radius, at center of sides. -// id = Inside diameter, at center of sides. -// side = Length of each side. -// realign = If false, a tip is aligned with the Y+ axis. If true, the midpoint of a side is aligned with the Y+ axis. Default: false -// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER` -// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0` -// Example(2D): by Outer Size -// regular_ngon(n=5, or=30); -// regular_ngon(n=5, od=60); -// Example(2D): by Inner Size -// regular_ngon(n=5, ir=30); -// regular_ngon(n=5, id=60); -// Example(2D): by Side Length -// regular_ngon(n=8, side=20); -// Example(2D): Realigned -// regular_ngon(n=8, side=20, realign=true); -// Example(2D): Called as Function -// stroke(closed=true, regular_ngon(n=6, or=30)); -function regular_ngon(n=6, r, d, or, od, ir, id, side, realign=false, anchor=CENTER, spin=0) = - let( - sc = 1/cos(180/n), - r = get_radius(r1=ir*sc, r2=or, r=r, d1=id*sc, d2=od, d=d, dflt=side/2/sin(180/n)), - path = circle(r=r, realign=realign, spin=90, $fn=n) - ) rot(spin, p=move(-r*normalize(anchor), p=path)); - - -module regular_ngon(n=6, r, d, or, od, ir, id, side, realign=false, anchor=CENTER, spin=0) { - sc = 1/cos(180/n); - r = get_radius(r1=ir*sc, r2=or, r=r, d1=id*sc, d2=od, d=d, dflt=side/2/sin(180/n)); - orient_and_anchor([2*r,2*r,0], UP, anchor, spin=spin, geometry="cylinder", two_d=true, chain=true) { - polygon(circle(r=r, realign=realign, spin=90, $fn=n)); - children(); - } -} - - -// Function&Module: pentagon() -// Usage: -// pentagon(or|od, [realign]); -// pentagon(ir|id, [realign]; -// pentagon(side, [realign]; -// Description: -// When called as a function, returns a 2D path for a regular pentagon. -// When called as a module, creates a 2D regular pentagon. -// Arguments: -// or = Outside radius, at points. -// r = Same as or. -// od = Outside diameter, at points. -// d = Same as od. -// ir = Inside radius, at center of sides. -// id = Inside diameter, at center of sides. -// side = Length of each side. -// realign = If false, a tip is aligned with the Y+ axis. If true, the midpoint of a side is aligned with the Y+ axis. Default: false -// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER` -// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0` -// Example(2D): by Outer Size -// pentagon(or=30); -// pentagon(od=60); -// Example(2D): by Inner Size -// pentagon(ir=30); -// pentagon(id=60); -// Example(2D): by Side Length -// pentagon(side=20); -// Example(2D): Realigned -// pentagon(side=20, realign=true); -// Example(2D): Called as Function -// stroke(closed=true, pentagon(or=30)); -function pentagon(r, d, or, od, ir, id, side, realign=false, anchor=CENTER, spin=0) = - regular_ngon(n=5, r=r, d=d, or=or, od=od, ir=ir, id=id, side=side, realign=realign, anchor=anchor, spin=spin); - - -module pentagon(r, d, or, od, ir, id, side, realign=false, anchor=CENTER, spin=0) - regular_ngon(n=5, r=r, d=d, or=or, od=od, ir=ir, id=id, side=side, realign=realign, anchor=anchor, spin=spin) children(); - - -// Function&Module: hexagon() -// Usage: -// hexagon(or, od, ir, id, side); -// Description: -// When called as a function, returns a 2D path for a regular hexagon. -// When called as a module, creates a 2D regular hexagon. -// Arguments: -// or = Outside radius, at points. -// r = Same as or -// od = Outside diameter, at points. -// d = Same as od -// ir = Inside radius, at center of sides. -// id = Inside diameter, at center of sides. -// side = Length of each side. -// realign = If false, a tip is aligned with the Y+ axis. If true, the midpoint of a side is aligned with the Y+ axis. Default: false -// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER` -// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0` -// Example(2D): by Outer Size -// hexagon(or=30); -// hexagon(od=60); -// Example(2D): by Inner Size -// hexagon(ir=30); -// hexagon(id=60); -// Example(2D): by Side Length -// hexagon(side=20); -// Example(2D): Realigned -// hexagon(side=20, realign=true); -// Example(2D): Called as Function -// stroke(closed=true, hexagon(or=30)); -function hexagon(r, d, or, od, ir, id, side, realign=false, anchor=CENTER, spin=0) = - regular_ngon(n=6, r=r, d=d, or=or, od=od, ir=ir, id=id, side=side, realign=realign, anchor=anchor, spin=spin); - - -module hexagon(r, d, or, od, ir, id, side, realign=false, anchor=CENTER, spin=0) - regular_ngon(n=6, r=r, d=d, or=or, od=od, ir=ir, id=id, side=side, realign=realign, anchor=anchor, spin=spin) children(); - - -// Function&Module: octagon() -// Usage: -// octagon(or, od, ir, id, side); -// Description: -// When called as a function, returns a 2D path for a regular octagon. -// When called as a module, creates a 2D regular octagon. -// Arguments: -// or = Outside radius, at points. -// r = Same as or -// od = Outside diameter, at points. -// d = Same as od -// ir = Inside radius, at center of sides. -// id = Inside diameter, at center of sides. -// side = Length of each side. -// realign = If false, a tip is aligned with the Y+ axis. If true, the midpoint of a side is aligned with the Y+ axis. Default: false -// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER` -// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0` -// Example(2D): by Outer Size -// octagon(or=30); -// octagon(od=60); -// Example(2D): by Inner Size -// octagon(ir=30); -// octagon(id=60); -// Example(2D): by Side Length -// octagon(side=20); -// Example(2D): Realigned -// octagon(side=20, realign=true); -// Example(2D): Called as Function -// stroke(closed=true, octagon(or=30)); -function octagon(r, d, or, od, ir, id, side, realign=false, anchor=CENTER, spin=0) = - regular_ngon(n=8, r=r, d=d, or=or, od=od, ir=ir, id=id, side=side, realign=realign, anchor=anchor, spin=spin); - - -module octagon(r, d, or, od, ir, id, side, realign=false, anchor=CENTER, spin=0) - regular_ngon(n=8, r=r, d=d, or=or, od=od, ir=ir, id=id, side=side, realign=realign, anchor=anchor, spin=spin) children(); - - -// Function&Module: glued_circles() -// Usage: -// glued_circles(r|d, spread, tangent); -// Description: -// When called as a function, returns a 2D path forming a shape of two circles joined by curved waist. -// When called as a module, creates a 2D shape of two circles joined by curved waist. -// Arguments: -// r = The radius of the end circles. -// d = The diameter of the end circles. -// spread = The distance between the centers of the end circles. -// tangent = The angle in degrees of the tangent point for the joining arcs, measured away from the Y axis. -// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER` -// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0` -// Examples(2D): -// glued_circles(r=15, spread=40, tangent=45); -// glued_circles(d=30, spread=30, tangent=30); -// glued_circles(d=30, spread=30, tangent=15); -// glued_circles(d=30, spread=30, tangent=-30); -// Example(2D): Called as Function -// stroke(closed=true, glued_circles(r=15, spread=40, tangent=45)); -function glued_circles(r, d, spread=10, tangent=30, anchor=CENTER, spin=0) = - let( - r = get_radius(r=r, d=d, dflt=10), - r2 = (spread/2 / sin(tangent)) - r, - cp1 = [spread/2, 0], - cp2 = [0, (r+r2)*cos(tangent)], - sa1 = 90-tangent, - ea1 = 270+tangent, - lobearc = ea1-sa1, - lobesegs = floor(segs(r)*lobearc/360), - lobestep = lobearc / lobesegs, - sa2 = 270-tangent, - ea2 = 270+tangent, - subarc = ea2-sa2, - arcsegs = ceil(segs(r2)*abs(subarc)/360), - arcstep = subarc / arcsegs, - s = [spread/2+r, r], - path = concat( - [for (i=[0:1:lobesegs]) let(a=sa1+i*lobestep) r * [cos(a),sin(a)] - cp1], - tangent==0? [] : [for (i=[0:1:arcsegs]) let(a=ea2-i*arcstep+180) r2 * [cos(a),sin(a)] - cp2], - [for (i=[0:1:lobesegs]) let(a=sa1+i*lobestep+180) r * [cos(a),sin(a)] + cp1], - tangent==0? [] : [for (i=[0:1:arcsegs]) let(a=ea2-i*arcstep) r2 * [cos(a),sin(a)] + cp2] - ) - ) rot(spin, p=move(-vmul(anchor,s), p=path)); - - -module glued_circles(r, d, spread=10, tangent=30, anchor=CENTER, spin=0) - polygon(glued_circles(r=r, d=d, spread=spread, tangent=tangent, anchor=anchor, spin=spin)); - - -// Function&Module: star() -// Usage: -// star(n, r|d|or|od, ir|id|step, [realign]); -// Description: -// When called as a function, returns the path needed to create a star polygon with N points. -// When called as a module, creates a star polygon with N points. -// Arguments: -// n = The number of stellate tips on the star. -// r = The radius to the tips of the star. -// or = Same as r -// d = The diameter to the tips of the star. -// od = Same as d -// ir = The radius to the inner corners of the star. -// id = The diameter to the inner corners of the star. -// step = Calculates the radius of the inner star corners by virtually drawing a straight line `step` tips around the star. 2 <= step < n/2 -// realign = If false, a tip is aligned with the Y+ axis. If true, an inner corner is aligned with the Y+ axis. Default: false -// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER` -// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0` -// Examples(2D): -// star(n=5, r=50, ir=25); -// star(n=5, r=50, step=2); -// star(n=7, r=50, step=2); -// star(n=7, r=50, step=3); -// Example(2D): Realigned -// star(n=7, r=50, step=3, realign=true); -// Example(2D): Called as Function -// stroke(closed=true, star(n=5, r=50, ir=25)); -function star(n, r, d, or, od, ir, id, step, realign=false, anchor=CENTER, spin=0) = - let( - r = get_radius(r1=or, d1=od, r=r, d=d), - count = num_defined([ir,id,step]), - stepOK = is_undef(step) || (step>1 && step0? [w2,h] : anchor.y<0? [w1,h] : [(w1+w2)/2,h], + path = [[w1/2,-h/2], [-w1/2,-h/2], [-w2/2,h/2], [w2/2,h/2]] + ) rot(spin, p=move(-vmul(anchor,s/2), p=path)); + + + +module trapezoid(h, w1, w2, anchor=CENTER, spin=0) + polygon(trapezoid(h=h, w1=w1, w2=w2, anchor=anchor, spin=spin)); + + +// Function&Module: teardrop2d() +// +// Description: +// Makes a 2D teardrop shape. Useful for extruding into 3D printable holes. +// +// Usage: +// teardrop2d(r|d, [ang], [cap_h]); +// +// Arguments: +// r = radius of circular part of teardrop. (Default: 1) +// d = diameter of spherical portion of bottom. (Use instead of r) +// ang = angle of hat walls from the Y axis. (Default: 45 degrees) +// cap_h = if given, height above center where the shape will be truncated. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#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, d, ang=45, cap_h, anchor=CENTER, spin=0) +{ + path = teardrop2d(r=r, d=d, ang=ang, cap_h=cap_h, anchor=anchor, spin=spin); + polygon(path); +} + + +function teardrop2d(r, d, ang=45, cap_h, anchor=CENTER, spin=0) = + let( + r = get_radius(r=r, d=d, dflt=1), + cord = 2 * r * cos(ang), + cord_h = r * sin(ang), + tip_y = (cord/2)/tan(ang), + cap_h = min((!is_undef(cap_h)? cap_h : tip_y+cord_h), tip_y+cord_h), + cap_w = cord * (1 - (cap_h - cord_h)/tip_y), + ang = min(ang,asin(cap_h/r)), + sa = 180 - ang, + ea = 360 + ang, + steps = segs(r)*(ea-sa)/360, + step = (ea-sa)/steps, + path = concat( + [[ cap_w/2,cap_h]], + [for (i=[0:1:steps]) let(a=ea-i*step) r*[cos(a),sin(a)]], + [[-cap_w/2,cap_h]] + ) + ) rot(spin, p=move(-vmul(anchor,[r,cap_h]), p=deduplicate(path,closed=true))); + + + +// Function&Module: glued_circles() +// Usage: +// glued_circles(r|d, spread, tangent); +// Description: +// When called as a function, returns a 2D path forming a shape of two circles joined by curved waist. +// When called as a module, creates a 2D shape of two circles joined by curved waist. +// Arguments: +// r = The radius of the end circles. +// d = The diameter of the end circles. +// spread = The distance between the centers of the end circles. +// tangent = The angle in degrees of the tangent point for the joining arcs, measured away from the Y axis. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0` +// Examples(2D): +// glued_circles(r=15, spread=40, tangent=45); +// glued_circles(d=30, spread=30, tangent=30); +// glued_circles(d=30, spread=30, tangent=15); +// glued_circles(d=30, spread=30, tangent=-30); +// Example(2D): Called as Function +// stroke(closed=true, glued_circles(r=15, spread=40, tangent=45)); +function glued_circles(r, d, spread=10, tangent=30, anchor=CENTER, spin=0) = + let( + r = get_radius(r=r, d=d, dflt=10), + r2 = (spread/2 / sin(tangent)) - r, + cp1 = [spread/2, 0], + cp2 = [0, (r+r2)*cos(tangent)], + sa1 = 90-tangent, + ea1 = 270+tangent, + lobearc = ea1-sa1, + lobesegs = floor(segs(r)*lobearc/360), + lobestep = lobearc / lobesegs, + sa2 = 270-tangent, + ea2 = 270+tangent, + subarc = ea2-sa2, + arcsegs = ceil(segs(r2)*abs(subarc)/360), + arcstep = subarc / arcsegs, + s = [spread/2+r, r], + path = concat( + [for (i=[0:1:lobesegs]) let(a=sa1+i*lobestep) r * [cos(a),sin(a)] - cp1], + tangent==0? [] : [for (i=[0:1:arcsegs]) let(a=ea2-i*arcstep+180) r2 * [cos(a),sin(a)] - cp2], + [for (i=[0:1:lobesegs]) let(a=sa1+i*lobestep+180) r * [cos(a),sin(a)] + cp1], + tangent==0? [] : [for (i=[0:1:arcsegs]) let(a=ea2-i*arcstep) r2 * [cos(a),sin(a)] + cp2] + ) + ) rot(spin, p=move(-vmul(anchor,s), p=path)); + + +module glued_circles(r, d, spread=10, tangent=30, anchor=CENTER, spin=0) + polygon(glued_circles(r=r, d=d, spread=spread, tangent=tangent, anchor=anchor, spin=spin)); + + +// Function&Module: star() +// Usage: +// star(n, r|d|or|od, ir|id|step, [realign]); +// Description: +// When called as a function, returns the path needed to create a star polygon with N points. +// When called as a module, creates a star polygon with N points. +// Arguments: +// n = The number of stellate tips on the star. +// r = The radius to the tips of the star. +// or = Same as r +// d = The diameter to the tips of the star. +// od = Same as d +// ir = The radius to the inner corners of the star. +// id = The diameter to the inner corners of the star. +// step = Calculates the radius of the inner star corners by virtually drawing a straight line `step` tips around the star. 2 <= step < n/2 +// realign = If false, a tip is aligned with the Y+ axis. If true, an inner corner is aligned with the Y+ axis. Default: false +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0` +// Examples(2D): +// star(n=5, r=50, ir=25); +// star(n=5, r=50, step=2); +// star(n=7, r=50, step=2); +// star(n=7, r=50, step=3); +// Example(2D): Realigned +// star(n=7, r=50, step=3, realign=true); +// Example(2D): Called as Function +// stroke(closed=true, star(n=5, r=50, ir=25)); +function star(n, r, d, or, od, ir, id, step, realign=false, anchor=CENTER, spin=0) = + let( + r = get_radius(r1=or, d1=od, r=r, d=d), + count = num_defined([ir,id,step]), + stepOK = is_undef(step) || (step>1 && step