diff --git a/attachments.scad b/attachments.scad index 82f6007..f47fdce 100644 --- a/attachments.scad +++ b/attachments.scad @@ -67,7 +67,8 @@ function anchorpt(name, pos=[0,0,0], dir=UP, rot=0) = [name, pos, dir, rot]; // shift = The [X,Y] amount to shift the center of the top with respect to the center of the bottom. // geometry = One of "cube", "cylinder", or "sphere" to denote the overall geometry of the shape. Cones are "cylinder", and prismoids are "cube" for this purpose. Default: "cube" // extra_anchors = A list of extra non-standard named anchors. -function find_anchor(anchor, h, size, size2=undef, shift=[0,0], extra_anchors=[], geometry="cube") = +// two_d = If true, object will be treated as 2D. +function find_anchor(anchor, h, size, size2=undef, shift=[0,0], extra_anchors=[], geometry="cube", two_d=false) = is_string(anchor)? ( let(found = search([anchor], extra_anchors, num_returns_per_match=1)[0]) assert(found!=[], str("Unknown anchor: ",anchor)) @@ -78,6 +79,7 @@ function find_anchor(anchor, h, size, size2=undef, shift=[0,0], extra_anchors=[] size2 = (size2!=undef)? point2d(size2) : size, shift = point2d(shift), oang = ( + two_d? 0 : anchor == UP? 0 : anchor == DOWN? 0 : (norm([anchor.x,anchor.y]) < EPSILON)? 0 : @@ -99,15 +101,16 @@ function find_anchor(anchor, h, size, size2=undef, shift=[0,0], extra_anchors=[] botpt = point3d(vmul(size/2,xyal))+DOWN*h/2, toppt = point3d(vmul(size2/2,xyal)+shift)+UP*h/2, pos = lerp(botpt, toppt, (anchor.z+1)/2), - sidevec = rotate_points3d([point3d(xyal)], from=UP, to=toppt-botpt)[0], + sidevec = two_d? point3d(xyal) : rotate_points3d([point3d(xyal)], from=UP, to=toppt-botpt)[0], vec = ( + two_d? sidevec : anchor==CENTER? UP : norm([anchor.x,anchor.y]) < EPSILON? anchor : abs(anchor.z) < EPSILON? sidevec : anchor.z>0? (UP+sidevec)/2 : (DOWN+sidevec)/2 ) - ) [anchor, pos, vec, oang] + ) echo(anchor=anchor, pos=pos, vec=vec, oang=oang) [anchor, pos, vec, oang] ); @@ -148,6 +151,7 @@ function _str_char_split(s,delim,n=0,acc=[],word="") = // orig_anchor = The original anchor of the part. Default: `CENTER`. // geometry = One of "cube", "cylinder", or "sphere" to denote the overall geometry of the shape. Cones are "cylinder", and prismoids are "cube" for this purpose. Default: "cube" // anchors = A list of extra, non-standard optional anchors. +// two_d = If true, object will be treated as 2D. // chain = If true, allow attachable children. // // Side Effects: @@ -168,7 +172,7 @@ module orient_and_anchor( orig_orient=ORIENT_Z, orig_anchor=CENTER, size2=undef, shift=[0,0], anchors=[], chain=false, - geometry="cube" + geometry="cube", two_d=false ) { size2 = point2d(default(size2, size)); shift = point2d(shift); @@ -186,19 +190,21 @@ module orient_and_anchor( ], ($attach_to!=undef)? ( let( - anch = find_anchor($attach_to, size.z, size, size2=size2, shift=shift, geometry=geometry), + anch = find_anchor($attach_to, size.z, size, size2=size2, shift=shift, geometry=geometry, two_d=two_d), ang = vector_angle(anch[2], DOWN), axis = vector_axis(anch[2], DOWN), ang2 = (anch[2]==UP || anch[2]==DOWN)? 0 : 180-anch[3], axis2 = rotate_points3d([axis],[0,0,ang2])[0] - ) [ - matrix4_translate(-anch[1]), - matrix4_zrot(ang2), - matrix4_rot_by_axis(axis2, ang) - ] + ) concat( + [matrix4_translate(-anch[1])], + $attach_norot? [] : [ + matrix4_zrot(ang2), + matrix4_rot_by_axis(axis2, ang) + ] + ) ) : concat( (anchor==CENTER)? [] : [ - let(anch = find_anchor(anchor, size.z, size, size2=size2, shift=shift, extra_anchors=anchors, geometry=geometry)) + let(anch = find_anchor(anchor, size.z, size, size2=size2, shift=shift, extra_anchors=anchors, geometry=geometry, two_d=two_d)) matrix4_translate(-anch[1]) ], (orient==ORIENT_Z)? [] : [ @@ -214,8 +220,9 @@ module orient_and_anchor( $parent_shift = shift; $parent_geom = geometry; $parent_orient = orient; + $parent_2d = two_d; $parent_anchor = anchor; - $parent_anchors = anchors; + $parent_anchors = anchors; tags = _str_char_split($tags, " "); s_tags = $tags_shown; h_tags = $tags_hidden; @@ -254,16 +261,18 @@ module attach(name, to=undef, overlap=undef, norot=false) { assert($parent_size != undef, "No object to attach to!"); overlap = (overlap!=undef)? overlap : $overlap; - anch = find_anchor(name, $parent_size.z, point2d($parent_size), size2=$parent_size2, shift=$parent_shift, extra_anchors=$parent_anchors, geometry=$parent_geom); + anch = find_anchor(name, $parent_size.z, point2d($parent_size), size2=$parent_size2, shift=$parent_shift, extra_anchors=$parent_anchors, geometry=$parent_geom, two_d=$parent_2d); pos = anch[1]; vec = anch[2]; ang = anch[3]; $attach_to = to; $attach_anchor = anch; + $attach_norot = norot; if (norot || (norm(vec-UP)<1e-9 && ang==0)) { translate(pos) translate([0,0,-overlap]) children(); } else { - translate(pos) rot(ang,from=UP,to=vec) translate([0,0,-overlap]) children(); + fromvec = $parent_2d? BACK : UP; + translate(pos) rot(ang,from=fromvec,to=vec) translate([0,0,-overlap]) children(); } } diff --git a/constants.scad b/constants.scad index c1109f9..ffb1fb8 100644 --- a/constants.scad +++ b/constants.scad @@ -308,6 +308,7 @@ $color = undef; $overlap = 0.01; $attach_to = undef; $attach_anchor = [CENTER, CENTER, UP, 0]; +$attach_norot = false; $parent_size = undef; $parent_size2 = undef; $parent_shift = [0,0]; diff --git a/foo.scad b/foo.scad deleted file mode 100644 index 1983f5e..0000000 --- a/foo.scad +++ /dev/null @@ -1,7 +0,0 @@ -include - -cube([20,4,4], anchor=TOP+FRONT) { - attach(FRONT, BACK) cube([20,20,4]); - attach(TOP, BOTTOM) cube([20,4,20]); - attach(TOP+FRONT, norot=true) recolor("green") interior_fillet(l=20, r=10, orient=ORIENT_XNEG); -} diff --git a/primitives.scad b/primitives.scad index 85e8abf..6cf88cb 100644 --- a/primitives.scad +++ b/primitives.scad @@ -38,6 +38,50 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// Section: 2D Primitives + + +// Module: square() +// Usage: +// square(size, [center], [anchor]) +// Description: +// Creates a 2D square of the given size. +// Arguments: +// size = The size of the square to create. If given as a scalar, both X and Y will be the same size. +// center = If given and true, overrides `anchor` to be `CENTER`. If given and false, overrides `anchor` to be `FRONT+LEFT`. +// anchor = The side of the square to center on the origin. Default: `FRONT+LEFT` +module square(size, center=undef, anchor=FRONT+LEFT) { + size = is_num(size)? [size,size] : point2d(size); + s = size/2; + pts = [[-s.x,-s.y], [-s.x,s.y], [s.x,s.y], [s.x,-s.y]]; + orient_and_anchor(point3d(size), ORIENT_Z, anchor, center, noncentered=FRONT+LEFT, two_d=true, chain=true) { + polygon(pts); + children(); + } +} + + +// Module: circle() +// Usage: +// circle(r|d, [anchor]) +// Description: +// Creates a 2D circle of the given size. +// Arguments: +// r = The radius of the circle to create. +// d = The diameter of the circle to create. +// anchor = The side of the circle to center on the origin. Default: `CENTER` +module circle(r=undef, d=undef, anchor=CENTER) { + r = get_radius(r=r, d=d, dflt=1); + sides = segs(r); + pts = [for (a=[0:360/sides:360-EPSILON]) r*[cos(a),sin(a)]]; + orient_and_anchor([2*r,2*r,0], ORIENT_Z, anchor, geometry="cylinder", two_d=true, chain=true) { + polygon(pts); + children(); + } +} + + + // Section: Primitive Shapes