diff --git a/affine.scad b/affine.scad index 2b319ee..6be072f 100644 --- a/affine.scad +++ b/affine.scad @@ -221,6 +221,28 @@ function affine3d_rot_by_axis(u, ang) = let( ]; +// Function: affine3d_rot_from_to() +// Usage: +// affine3d_rot_from_to(from, to); +// Description: +// Returns the 4x4 affine3d matrix to perform a rotation of a 3D vector from one vector direction to another. +// Arguments: +// from = 3D axis vector to rotate from. +// to = 3D axis vector to rotate to. +function affine3d_rot_from_to(from, to) = let( + u = vector_axis(from,to), + ang = vector_angle(from,to), + c = cos(ang), + c2 = 1-c, + s = sin(ang) +) [ + [u[0]*u[0]*c2+c , u[0]*u[1]*c2-u[2]*s, u[0]*u[2]*c2+u[1]*s, 0], + [u[1]*u[0]*c2+u[2]*s, u[1]*u[1]*c2+c , u[1]*u[2]*c2-u[0]*s, 0], + [u[2]*u[0]*c2-u[1]*s, u[2]*u[1]*c2+u[0]*s, u[2]*u[2]*c2+c , 0], + [ 0, 0, 0, 1] +]; + + // Function: affine3d_skew_xy() // Usage: // affine3d_skew_xy(xa, ya) diff --git a/attachments.scad b/attachments.scad index d7a82eb..030f02b 100644 --- a/attachments.scad +++ b/attachments.scad @@ -9,20 +9,83 @@ // Default values for attachment code. -$color = undef; +$slop = 0.20; +$tags = ""; $overlap = 0.01; +$color = undef; + $attach_to = undef; $attach_anchor = [CENTER, CENTER, UP, 0]; $attach_norot = false; + $parent_size = undef; $parent_size2 = undef; $parent_shift = [0,0]; -$parent_orient = ORIENT_Z; -$parent_anchor = CENTER; $parent_anchors = []; +$parent_anchor = BOTTOM; +$parent_orient = UP; + $tags_shown = []; $tags_hidden = []; -$tags = ""; + + +// Section: Anchors, Spin, and Orientation +// This library adds the concept of anchoring, spin and orientation to the `cube()`, `cylinder()` +// and `sphere()` builtins, as well as to most of the shapes provided by this library itself. +// * An anchor is a place on an object which you can align the object to, or attach other objects +// to using `attach()` or `position()`. An anchor has a position, a direction, and a spin. +// The direction and spin are used to orient other objects to match when using `attach()`. +// * Spin is a simple rotation around the Z axis. +// * Orientation is rotating an object so that its top is pointed towards a given vector. +// An object will first be translated to its anchor position, then spun, then oriented. + +// Section: Anchor +// Anchoring is specified with the `anchor` argument in most shape modules. +// Specifying `anchor` when creating an object will translate the object so +// that the anchor point is at the origin (0,0,0). Anchoring always occurs +// before spin and orientation are applied. +// +// An anchor can be referred to in one of two ways; as a directional vector, +// or as a named anchor string. +// +// When given as a vector, it points, in a general way, towards the face, edge, or +// corner of the object that you want the anchor for, relative to the center of +// the object. There are directional constants named `TOP`, `BOTTOM`, `FRONT`, `BACK`, +// `LEFT`, and `RIGHT` that you can add together to specify an anchor point. +// For example: +// - `[0,0,1]` is the same as `TOP` and refers to the center of the top face. +// - `[-1,0,1]` is the same as `TOP+LEFT`, and refers to the center of the top-left edge. +// - `[1,1,-1]` is the same as `BOTTOM+BACK+RIGHT`, and refers to the bottom-back-right corner. +// +// The components of the directional vector should all be `1`, `0`, or `-1`. +// When the object is cylindrical, conical, or spherical in nature, the anchors will be +// located around the surface of the cylinder, cone, or sphere, relative to the center. +// The direction of a face anchor will be perpendicular to the face, pointing outward. +// The direction of a edge anchor will be the average of the anchor directions of the +// two faces the edge is between. The direction of a corner anchor will be the average +// of the anchor directions of the three faces the corner is on. The spin of all standard +// anchors is 0. +// +// Some more complex objects, like screws and stepper motors, have named anchors +// to refer to places on the object that are not at one of the standard faces, edges +// or corners. For example, stepper motors have anchors for `"screw1"`, `"screw2"`, +// etc. to refer to the various screwholes on the stepper motor shape. The names, +// positions, directions, and spins of these anchors will be specific to the object, +// and will be documented when they exist. + +// Section: Spin +// Spin is specified with the `spin` argument in most shape modules. Specifying `spin` +// when creating an object will rotate the object counter-clockwise around the Z axis +// by the given number of degrees. Spin is always applied after anchoring, and before +// orientation. + +// Section: Orient +// Orientation is specified with the `orient` argument in most shape modules. Specifying +// `orient` when creating an object will rotate the object such that the top of the +// object will be pointed at the vector direction given in the `orient` argument. +// Orientation is always applied after anchoring and spin. The constants `UP`, `DOWN`, +// `FRONT`, `BACK`, `LEFT`, and `RIGHT` can be added together to form the directional +// vector for this. ie: `LEFT+BACK` // Section: Functions @@ -36,9 +99,9 @@ $tags = ""; // Arguments: // name = The string name of the anchor. Lowercase. Words separated by single dashes. No spaces. // pos = The [X,Y,Z] position of the anchor. -// dir = A vector pointing in the direction parts should project from the anchor position. -// rot = If needed, the angle to rotate the part around the direction vector. -function anchorpt(name, pos=[0,0,0], dir=UP, rot=0) = [name, pos, dir, rot]; +// orient = A vector pointing in the direction parts should project from the anchor position. +// spin = If needed, the angle to rotate the part around the direction vector. +function anchorpt(name, pos=[0,0,0], orient=UP, spin=0) = [name, pos, orient, spin]; @@ -54,14 +117,15 @@ function anchorpt(name, pos=[0,0,0], dir=UP, rot=0) = [name, pos, dir, rot]; // size2 = The [X,Y] size of the top of the cubical region. // 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. +// anchors = A list of extra non-standard named anchors. // 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) = +function find_anchor(anchor, h, size, size2=undef, shift=[0,0], anchors=[], geometry="cube", two_d=false) = is_string(anchor)? ( - let(found = search([anchor], extra_anchors, num_returns_per_match=1)[0]) + let(found = search([anchor], anchors, num_returns_per_match=1)[0]) assert(found!=[], str("Unknown anchor: ",anchor)) - extra_anchors[found] + anchors[found] ) : ( + assert(is_vector(anchor),str("anchor=",anchor)) let( size = point2d(size), size2 = (size2!=undef)? point2d(size2) : size, @@ -118,30 +182,42 @@ function _str_char_split(s,delim,n=0,acc=[],word="") = // Module: orient_and_anchor() // // Description: -// Takes a vertically oriented shape, and re-orients and anchors it. +// Takes a vertically oriented part and anchors, spins and orients it. // This is useful for making a custom shape available in various -// orientations and anchor without extra translate()s and rotate()s. +// orientations and anchorings without extra translate()s and rotate()s. // Children should be vertically (Z-axis) oriented, and centered. // Non-vector anchor points should be named via the `anchors` arg. -// Named anchors are translated pre-rotation. +// +// If this is *not* run as a child of `attach()` with the `to` argument +// given, then the following transformations are performed in order: +// * Translates so the `anchor` point is at the origin (0,0,0). +// * Rotates around the Z axis by `spin` degrees counter-clockwise. +// * Rotates so the top of the part points towards the vector `orient`. +// +// If this is called as a child of `attach(from,to)`, then the info +// for the anchor points referred to by `from` and `to` are fetched, +// which will include position, direction, and spin. With that info, +// the following transformations are performed: +// * Translates this part so it's anchor position matches the parent's anchor position. +// * Rotates this part so it's anchor direction vector exactly opposes the parent's anchor direction vector. +// * Rotates this part so it's anchor spin matches the parent's anchor spin. // // Usage: -// orient_and_anchor(size, [orient], [anchor], [center], [noncentered], [orig_orient], [orig_anchor], [anchors], [chain]) ... +// orient_and_anchor(size, [anchor], [spin], [orient], [center], [noncentered], [anchors], [chain]) ... // // Arguments: // size = The [X,Y,Z] size of the part. // size2 = The [X,Y] size of the top of the part. // shift = The [X,Y] offset of the top of the part, compared to the bottom of the part. -// orient = The axis to orient to. Use `ORIENT_` constants from `constants.scad`. -// anchor = The side of the part that will be anchored to the origin. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // center = If given, overrides `anchor`. If true, centers vertically. If false, `anchor` will be set to the value in `noncentered`. // noncentered = The value to set `anchor` to if `center` == `false`. Default: `BOTTOM`. -// orig_orient = The original orientation of the part. Default: `ORIENT_Z`. -// 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. +// two_d = If true, object will be treated as 2D. // // Side Effects: // `$parent_size` is set to the parent object's cubical region size. @@ -153,100 +229,118 @@ function _str_char_split(s,delim,n=0,acc=[],word="") = // `$parent_anchors` is set to the parent object's list of non-standard extra anchors. // `$parent_2d` is set to the parent object's `two_d` value. // -// Example: -// #cylinder(d=5, h=10); -// orient_and_anchor([5,5,10], orient=ORIENT_Y, anchor=BACK, orig_anchor=BOTTOM) -// cylinder(d=5, h=10); +// Example(Med): +// #cylinder(d1=50, d2=30, h=60); +// orient_and_anchor(size=[50,50,60], size2=[30,30], anchor=RIGHT, orient=FWD) +// cylinder(d1=50, d2=30, h=60); module orient_and_anchor( - size=undef, orient=ORIENT_Z, anchor=CENTER, - center=undef, noncentered=BOTTOM, - orig_orient=ORIENT_Z, orig_anchor=CENTER, - size2=undef, shift=[0,0], - anchors=[], chain=false, - geometry="cube", two_d=false + size=undef, + orient=UP, + anchor=CENTER, + center=undef, + noncentered=BOTTOM, + spin=0, + size2=undef, + shift=[0,0], + geometry="cube", + anchors=[], + chain=false, + two_d=false ) { size2 = point2d(default(size2, size)); shift = point2d(shift); - anchor = !is_undef(center)? (center? CENTER : noncentered) : anchor; - m = affine3d_chain(concat( - (orig_anchor==CENTER)? [] : [ - // If original anchor is not centered, center it. - let(anch = find_anchor(orig_anchor, size.z, size, size2=size2, shift=shift, geometry=geometry, two_d=two_d)) - affine3d_translate(anch[1]) - ], - (orig_orient==ORIENT_Z)? [] : [ - // If original orientation is not upright, rotate it upright. - affine3d_zrot(-orig_orient.z), - affine3d_yrot(-orig_orient.y), - affine3d_xrot(-orig_orient.x) - ], - ($attach_to!=undef)? ( - let( - 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] - ) concat( - [affine3d_translate(-anch[1])], - $attach_norot? [] : [ - affine3d_zrot(ang2), - affine3d_rot_by_axis(axis2, ang) - ] - ) - ) : concat( - (orient==ORIENT_Z)? [] : [ - affine3d_xrot(orient.x), - affine3d_yrot(orient.y), - affine3d_zrot(orient.z) - ], - (anchor==CENTER)? [] : [ - let( - anchr = is_vector(anchor)? rotate_points3d([anchor], orient, reverse=true)[0] : anchor, - anch = find_anchor( - anchr, size.z, size, size2=size2, - shift=shift, extra_anchors=anchors, - geometry=geometry, two_d=two_d - ) - ) - affine3d_translate(rotate_points3d([-anch[1]],orient)[0]) - ] - ) - )); - $attach_to = undef; + anchr = is_undef(center)? anchor : (center? CENTER : noncentered); + pos = find_anchor(anchr, size.z, size, size2=size2, shift=shift, anchors=anchors, geometry=geometry, two_d=two_d)[1]; + $parent_size = size; $parent_size2 = size2; $parent_shift = shift; $parent_geom = geometry; $parent_orient = orient; $parent_2d = two_d; - $parent_anchor = anchor; + $parent_anchor = anchr; $parent_anchors = anchors; + tags = _str_char_split($tags, " "); s_tags = $tags_shown; h_tags = $tags_hidden; shown = !s_tags || any([for (tag=tags) in_list(tag, s_tags)]); hidden = any([for (tag=tags) in_list(tag, h_tags)]); - multmatrix(m) { - if ($children>1 && chain) { - if(shown && !hidden) color($color) for (i=[0:$children-2]) children(i); - children($children-1); - } else { - if(shown && !hidden) color($color) children(); + if ($attach_to != undef) { + anch = find_anchor($attach_to, size.z, size, size2=size2, shift=shift, anchors=anchors, 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]; + $attach_to = undef; + + rot(ang, v=axis2) + rotate(ang2+spin) + translate(-anch[1]) + { + if ($children>1 && chain) { + if(shown && !hidden) { + color($color) for (i=[0:$children-2]) children(i); + } + children($children-1); + } else { + if(shown && !hidden) color($color) children(); + } + } + } else { + rot(from=UP,to=orient) + rotate(spin) + translate(-pos) + { + if ($children>1 && chain) { + if(shown && !hidden) { + color($color) for (i=[0:$children-2]) children(i); + } + children($children-1); + } else { + if(shown && !hidden) color($color) children(); + } } } } +// Module: position() +// Usage: +// position(from, [overlap]) ... +// Description: +// Attaches children to a parent object at an anchor point. +// Arguments: +// from = The vector, or name of the parent anchor point to attach to. +// Example: +// spheroid(d=20) { +// position(TOP) cyl(l=10, d1=10, d2=5, anchor=BOTTOM); +// position(RIGHT) cyl(l=10, d1=10, d2=5, anchor=BOTTOM); +// position(FRONT) cyl(l=10, d1=10, d2=5, anchor=BOTTOM); +// } +module position(from, overlap=undef, norot=false) +{ + assert($parent_size != undef, "No object to attach to!"); + anchors = (is_vector(from)||is_string(from))? [from] : from; + for (anchr = anchors) { + anch = find_anchor(anchr, $parent_size.z, point2d($parent_size), size2=$parent_size2, shift=$parent_shift, anchors=$parent_anchors, geometry=$parent_geom, two_d=$parent_2d); + $attach_to = undef; + $attach_anchor = anch; + $attach_norot = true; + translate(anch[1]) children(); + } +} + + // Module: attach() // Usage: -// attach(name, [overlap], [norot]) ... -// attach(name, to, [overlap]) ... +// attach(from, [overlap]) ... +// attach(from, to, [overlap]) ... // Description: // Attaches children to a parent object at an anchor point and orientation. // Arguments: -// name = The name of the parent anchor point to attach to. +// from = The vector, or name of the parent anchor point to attach to. // to = Optional name of the child anchor point. If given, orients the child such that the named anchors align together rotationally. // overlap = Amount to sink child into the parent. Equivalent to `down(X)` after the attach. // norot = If true, don't rotate children when attaching to the anchor point. Only translate to the anchor point. @@ -256,22 +350,22 @@ module orient_and_anchor( // attach(RIGHT, BOTTOM) down(1.5) cyl(l=11.5, d1=10, d2=5); // attach(FRONT, BOTTOM, overlap=1.5) cyl(l=11.5, d1=10, d2=5); // } -module attach(name, to=undef, overlap=undef, norot=false) +module attach(from, 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, 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 { - fromvec = $parent_2d? BACK : UP; - translate(pos) rot(ang,from=fromvec,to=vec) translate([0,0,-overlap]) children(); + anchors = (is_vector(from)||is_string(from))? [from] : from; + for (anchr = anchors) { + anch = find_anchor(anchr, $parent_size.z, point2d($parent_size), size2=$parent_size2, shift=$parent_shift, anchors=$parent_anchors, geometry=$parent_geom, two_d=$parent_2d); + $attach_to = to; + $attach_anchor = anch; + $attach_norot = norot; + if (norot || (norm(anch[2]-UP)<1e-9 && anch[3]==0)) { + translate(anch[1]) translate([0,0,-overlap]) children(); + } else { + fromvec = $parent_2d? BACK : UP; + translate(anch[1]) rot(anch[3],from=fromvec,to=anch[2]) translate([0,0,-overlap]) children(); + } } } @@ -362,6 +456,18 @@ module show(tags="") // attach(CENTER) xcyl(d=40, h=120, $tags="axle"); // attach(CENTER) cube([40,120,100], anchor=CENTER, $tags="neg"); // } +// Example: Masking +// diff("mask") +// cube([80,90,100], center=true) { +// let(p = $parent_size*1.01, $tags="mask") { +// position([for (y=[-1,1],z=[-1,1]) [0,y,z]]) +// rounding_mask_x(l=p.x, r=25); +// position([for (x=[-1,1],z=[-1,1]) [x,0,z]]) +// rounding_mask_y(l=p.y, r=20); +// position([for (x=[-1,1],y=[-1,1]) [x,y,0]]) +// rounding_mask_z(l=p.z, r=25); +// } +// } module diff(neg, pos=undef, keep=undef) { difference() { diff --git a/beziers.scad b/beziers.scad index 3bc8cc8..00b50fd 100644 --- a/beziers.scad +++ b/beziers.scad @@ -414,8 +414,9 @@ module bezier_polygon(bezier, splinesteps=16, N=3) { // scale = Relative size of top of extrusion to the bottom. default=1.0 // slices = Number of vertical slices to use for twisted extrusion. default=20 // center = If true, the extruded solid is centered vertically at z=0. -// orient = Orientation of the extrusion. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the extrusion. Use the constants from `constants.scad`. Default: `UP`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example: // bez = [ // [-10, 0], [-15, -5], @@ -425,13 +426,14 @@ module bezier_polygon(bezier, splinesteps=16, N=3) { // [ 25, -15], [-10, 0] // ]; // linear_extrude_bezier(bez, height=20, splinesteps=32); -module linear_extrude_bezier(bezier, height=100, splinesteps=16, N=3, center=undef, convexity=undef, twist=undef, slices=undef, scale=undef, orient=ORIENT_Z, anchor=UP) { +module linear_extrude_bezier(bezier, height=100, splinesteps=16, N=3, center=undef, convexity=undef, twist=undef, slices=undef, scale=undef, anchor=UP, spin=0, orient=UP) { maxx = max([for (pt = bezier) abs(pt[0])]); maxy = max([for (pt = bezier) abs(pt[1])]); - orient_and_anchor([maxx*2,maxy*2,height], orient, anchor) { + orient_and_anchor([maxx*2,maxy*2,height], orient, anchor, spin=spin, chain=true) { linear_extrude(height=height, center=true, convexity=convexity, twist=twist, slices=slices, scale=scale) { bezier_polygon(bezier, splinesteps=splinesteps, N=N); } + children(); } } @@ -447,8 +449,9 @@ module linear_extrude_bezier(bezier, height=100, splinesteps=16, N=3, center=und // N = number of points in each bezier segment. default=3 (cubic) // convexity = max number of walls a line could pass through, for preview. default=10 // angle = Degrees of sweep to make. Default: 360 -// orient = Orientation of the extrusion. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_X`. -// anchor = Alignment of the extrusion. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example(FlatSpin): // path = [ // [ 0, 10], [ 50, 0], [ 50, 40], @@ -458,11 +461,11 @@ module linear_extrude_bezier(bezier, height=100, splinesteps=16, N=3, center=und // [ 0, 10] // ]; // revolve_bezier(path, splinesteps=32, $fn=180); -module revolve_bezier(bezier, splinesteps=16, N=3, convexity=10, angle=360, orient=ORIENT_X, anchor=CENTER) +module revolve_bezier(bezier, splinesteps=16, N=3, convexity=10, angle=360, anchor=CENTER, spin=0, orient=RIGHT) { maxx = max([for (pt = bezier) abs(pt[0])]); maxy = max([for (pt = bezier) abs(pt[1])]); - orient_and_anchor([maxx*2,maxx*2,maxy*2], orient, anchor) { + orient_and_anchor([maxx*2,maxx*2,maxy*2], orient, anchor, spin=spin, geometry="cylinder", chain=true) { rotate_extrude(convexity=convexity, angle=angle) { xrot(180) zrot(-90) bezier_polygon(bezier, splinesteps, N); } @@ -483,8 +486,9 @@ module revolve_bezier(bezier, splinesteps=16, N=3, convexity=10, angle=360, orie // N = number of points in each bezier segment. default=3 (cubic) // convexity = max number of walls a line could pass through, for preview. default=10 // angle = Degrees of sweep to make. Default: 360 -// orient = Orientation of the extrusion. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the extrusion. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example(Spin): // path = [ // [ 0, 10], [ 50, 0], [ 50, 40], @@ -494,11 +498,11 @@ module revolve_bezier(bezier, splinesteps=16, N=3, convexity=10, angle=360, orie // [ 0, 10] // ]; // rotate_extrude_bezier(path, splinesteps=32, $fn=180); -module rotate_extrude_bezier(bezier, splinesteps=16, N=3, convexity=10, angle=360, orient=ORIENT_Z, anchor=CENTER) +module rotate_extrude_bezier(bezier, splinesteps=16, N=3, convexity=10, angle=360, anchor=CENTER, spin=0, orient=UP) { maxx = max([for (pt = bezier) abs(pt[0])]); maxy = max([for (pt = bezier) abs(pt[1])]); - orient_and_anchor([maxx*2,maxx*2,0], orient, anchor) { + orient_and_anchor([maxx*2,maxx*2,0], orient, anchor, spin=spin, geometry="cylinder", chain=true) { rotate_extrude(convexity=convexity, angle=angle) { bezier_polygon(bezier, splinesteps, N); } @@ -518,13 +522,14 @@ module rotate_extrude_bezier(bezier, splinesteps=16, N=3, convexity=10, angle=36 // N = number of points in each bezier segment. default=3 (cubic) // convexity = max number of walls a line could pass through, for preview. default=10 // angle = Degrees of sweep to make. Default: 360 -// orient = Orientation of the extrusion. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_X`. -// anchor = Alignment of the extrusion. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example(FlatSpin): // path = [ [0, 10], [33, 10], [66, 40], [100, 40] ]; // revolve_bezier_solid_to_axis(path, splinesteps=32, $fn=72); -module revolve_bezier_solid_to_axis(bezier, splinesteps=16, N=3, convexity=10, angle=360, orient=ORIENT_X, anchor=CENTER) { - revolve_bezier(bezier=bezier_close_to_axis(bezier), splinesteps=splinesteps, N=N, convexity=convexity, angle=angle, orient=orient, anchor=anchor); +module revolve_bezier_solid_to_axis(bezier, splinesteps=16, N=3, convexity=10, angle=360, anchor=CENTER, spin=0, orient=RIGHT) { + revolve_bezier(bezier=bezier_close_to_axis(bezier), splinesteps=splinesteps, N=N, convexity=convexity, angle=angle, anchor=anchor, spin=spin, orient=orient); } @@ -540,13 +545,14 @@ module revolve_bezier_solid_to_axis(bezier, splinesteps=16, N=3, convexity=10, a // N = number of points in each bezier segment. default=3 (cubic) // convexity = max number of walls a line could pass through, for preview. default=10 // angle = degrees of sweep to make. Default: 360 -// orient = Orientation of the extrusion. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_X`. -// anchor = Alignment of the extrusion. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `RIGHT` // Example(FlatSpin): // path = [ [0, 10], [33, 10], [66, 40], [100, 40] ]; // revolve_bezier_offset_shell(path, offset=1, splinesteps=32, $fn=72); -module revolve_bezier_offset_shell(bezier, offset=1, splinesteps=16, N=3, convexity=10, angle=360, orient=ORIENT_X, anchor=CENTER) { - revolve_bezier(bezier=bezier_offset(offset, bezier), splinesteps=splinesteps, N=N, orient=orient, anchor=anchor); +module revolve_bezier_offset_shell(bezier, offset=1, splinesteps=16, N=3, convexity=10, angle=360, anchor=CENTER, spin=0, orient=RIGHT) { + revolve_bezier(bezier=bezier_offset(offset, bezier), splinesteps=splinesteps, N=N, anchor=anchor, spin=spin, orient=orient); } @@ -799,17 +805,17 @@ function bezier_triangle(tri, splinesteps=16, vertices=[], faces=[]) = // Arguments: // size = 2D XY size of the patch. // N = Degree of the patch to generate. Since this is flat, a degree of 1 should usually be sufficient. -// orient = The orientation to rotate the edge patch into. Use the `ORIENT` constants in `constants.scad`. +// orient = The orientation to rotate the edge patch into. Given as an [X,Y,Z] rotation angle list. // trans = Amount to translate patch, after rotating to `orient`. // Example(3D): // patch = bezier_patch_flat(size=[100,100], N=3); // trace_bezier_patches([patch], size=1, showcps=true); -function bezier_patch_flat(size=[100,100], N=4, orient=ORIENT_Z, trans=[0,0,0]) = +function bezier_patch_flat(size=[100,100], N=4, spin=0, orient=UP, trans=[0,0,0]) = let( patch = [for (x=[0:N]) [for (y=[0:N]) vmul(point3d(size),[x/N-0.5, 0.5-y/N, 0])]] ) [for (row=patch) translate_points(v=trans, - rotate_points3d(a=orient,row) + rotate_points3d(a=spin, from=UP, to=orient, row) ) ]; diff --git a/constants.scad b/constants.scad index 7ca0418..872ab6f 100644 --- a/constants.scad +++ b/constants.scad @@ -75,6 +75,7 @@ CENTER = [ 0, 0, 0]; // Centered zero vector. // Section: Vector Aliases // Useful aliases for use with `anchor`. +CTR = CENTER; // Zero vector, `[0,0,0]`. Alias to `CENTER`. UP = TOP; // Vector pointing up, alias to `TOP`. DOWN = BOTTOM; // Vector pointing down, alias to `BOTTOM`. BTM = BOTTOM; // Vector pointing down, alias to `BOTTOM`. @@ -86,14 +87,8 @@ FORWARD = FRONT; // Vector pointing forward, alias to `FRONT`. // CommonCode: // orientations = [ -// ORIENT_X, ORIENT_Y, ORIENT_Z, -// ORIENT_XNEG, ORIENT_YNEG, ORIENT_ZNEG, -// ORIENT_X_90, ORIENT_Y_90, ORIENT_Z_90, -// ORIENT_XNEG_90, ORIENT_YNEG_90, ORIENT_ZNEG_90, -// ORIENT_X_180, ORIENT_Y_180, ORIENT_Z_180, -// ORIENT_XNEG_180, ORIENT_YNEG_180, ORIENT_ZNEG_180, -// ORIENT_X_270, ORIENT_Y_270, ORIENT_Z_270, -// ORIENT_XNEG_270, ORIENT_YNEG_270, ORIENT_ZNEG_270 +// RIGHT, BACK, UP, +// LEFT, FWD, DOWN, // ]; // axiscolors = ["red", "forestgreen", "dodgerblue"]; // module text3d(text, h=0.01, size=3) { @@ -107,8 +102,8 @@ FORWARD = FRONT; // Vector pointing forward, alias to `FRONT`. // color(axiscolors.y) up ((20-1)/2+0.01) right((20-1)/2+0.01) cube([1,18,1], center=true); // color(axiscolors.z) back((20-1)/2+0.01) right((20-1)/2+0.01) cube([1,1,18], center=true); // for (axis=[0:2], neg=[0:1]) { -// idx = axis + 3*neg + 6*ang/90; -// rotate(orientations[idx]) { +// idx = axis + 3*neg; +// rot(ang, from=UP, to=orientations[idx]) { // up(10) { // fwd(4) color("black") text3d(text=str(ang), size=4); // back(4) color(axiscolors[axis]) text3d(text=str(["X","Y","Z"][axis], ["+","NEG"][neg]), size=4); @@ -118,60 +113,5 @@ FORWARD = FRONT; // Vector pointing forward, alias to `FRONT`. // } -// Section: Standard Orientations -// Orientations for `cyl()`, `prismoid()`, etc. They take the form of standard [X,Y,Z] -// rotation angles for rotating a vertical shape into the given orientations. -// Figure(Spin): Standard Orientations -// orient_cube(0); - -ORIENT_X = [ 90, 0, 90]; // Orient along the X axis. -ORIENT_Y = [ 90, 0, 180]; // Orient along the Y axis. -ORIENT_Z = [ 0, 0, 0]; // Orient along the Z axis. -ORIENT_XNEG = [ 90, 0, -90]; // Orient reversed along the X axis. -ORIENT_YNEG = [ 90, 0, 0]; // Orient reversed along the Y axis. -ORIENT_ZNEG = [ 0, 180, 0]; // Orient reversed along the Z axis. - - -// Section: Orientations Rotated 90º -// Orientations for `cyl()`, `prismoid()`, etc. They take the form of standard [X,Y,Z] -// rotation angles for rotating a vertical shape into the given orientations. -// Figure(Spin): Orientations Rotated 90º -// orient_cube(90); - -ORIENT_X_90 = [ 90, -90, 90]; // Orient along the X axis, then rotate 90 degrees counter-clockwise on that axis, as seen when facing the origin from that axis orientation. -ORIENT_Y_90 = [ 90, -90, 180]; // Orient along the Y axis, then rotate 90 degrees counter-clockwise on that axis, as seen when facing the origin from that axis orientation. -ORIENT_Z_90 = [ 0, 0, 90]; // Orient along the Z axis, then rotate 90 degrees counter-clockwise on that axis, as seen when facing the origin from that axis orientation. -ORIENT_XNEG_90 = [ 0, -90, 0]; // Orient reversed along the X axis, then rotate 90 degrees counter-clockwise on that axis, as seen when facing the origin from that axis orientation. -ORIENT_YNEG_90 = [ 90, -90, 0]; // Orient reversed along the Y axis, then rotate 90 degrees counter-clockwise on that axis, as seen when facing the origin from that axis orientation. -ORIENT_ZNEG_90 = [ 0, 180, -90]; // Orient reversed along the Z axis, then rotate 90 degrees counter-clockwise on that axis, as seen when facing the origin from that axis orientation. - - -// Section: Orientations Rotated 180º -// Orientations for `cyl()`, `prismoid()`, etc. They take the form of standard [X,Y,Z] -// rotation angles for rotating a vertical shape into the given orientations. -// Figure(Spin): Orientations Rotated 180º -// orient_cube(180); - -ORIENT_X_180 = [-90, 0, -90]; // Orient along the X axis, then rotate 180 degrees counter-clockwise on that axis, as seen when facing the origin from that axis orientation. -ORIENT_Y_180 = [-90, 0, 0]; // Orient along the Y axis, then rotate 180 degrees counter-clockwise on that axis, as seen when facing the origin from that axis orientation. -ORIENT_Z_180 = [ 0, 0, 180]; // Orient along the Z axis, then rotate 180 degrees counter-clockwise on that axis, as seen when facing the origin from that axis orientation. -ORIENT_XNEG_180 = [-90, 0, 90]; // Orient reversed along the X axis, then rotate 180 degrees counter-clockwise on that axis, as seen when facing the origin from that axis orientation. -ORIENT_YNEG_180 = [-90, 0, 180]; // Orient reversed along the Y axis, then rotate 180 degrees counter-clockwise on that axis, as seen when facing the origin from that axis orientation. -ORIENT_ZNEG_180 = [ 0, 180, 180]; // Orient reversed along the Z axis, then rotate 180 degrees counter-clockwise on that axis, as seen when facing the origin from that axis orientation. - - -// Section: Orientations Rotated 270º -// Orientations for `cyl()`, `prismoid()`, etc. They take the form of standard [X,Y,Z] -// rotation angles for rotating a vertical shape into the given orientations. -// Figure(Spin): Orientations Rotated 270º -// orient_cube(270); - -ORIENT_X_270 = [ 90, 90, 90]; // Orient along the X axis, then rotate 270 degrees counter-clockwise on that axis, as seen when facing the origin from that axis orientation. -ORIENT_Y_270 = [ 90, 90, 180]; // Orient along the Y axis, then rotate 270 degrees counter-clockwise on that axis, as seen when facing the origin from that axis orientation. -ORIENT_Z_270 = [ 0, 0, -90]; // Orient along the Z axis, then rotate 270 degrees counter-clockwise on that axis, as seen when facing the origin from that axis orientation. -ORIENT_XNEG_270 = [ 90, 90, -90]; // Orient reversed along the X axis, then rotate 270 degrees counter-clockwise on that axis, as seen when facing the origin from that axis orientation. -ORIENT_YNEG_270 = [ 90, 90, 0]; // Orient reversed along the Y axis, then rotate 270 degrees counter-clockwise on that axis, as seen when facing the origin from that axis orientation. -ORIENT_ZNEG_270 = [ 0, 180, 90]; // Orient reversed along the Z axis, then rotate 270 degrees counter-clockwise on that axis, as seen when facing the origin from that axis orientation. - // vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap diff --git a/debug.scad b/debug.scad index d0b7341..e54a57b 100644 --- a/debug.scad +++ b/debug.scad @@ -169,8 +169,8 @@ function standard_anchors() = [ module anchor_arrow(s=10, color=[0.333,0.333,1], flag=true, $tags="anchor-arrow") { $fn=12; recolor("gray") spheroid(d=s/6) - recolor(color) cyl(h=s*2/3, d=s/15, anchor=DOWN) - attach(TOP) cyl(h=s/3, d1=s/5, d2=0, anchor=DOWN) { + attach(CENTER,BOT) recolor(color) cyl(h=s*2/3, d=s/15, anchor=BOT) + attach(TOP) cyl(h=s/3, d1=s/5, d2=0, anchor=BOT) { if(flag) { attach(BOTTOM) recolor([1,0.5,0.5]) cuboid([s/50, s/6, s/4], anchor=FRONT+TOP); } @@ -180,17 +180,17 @@ module anchor_arrow(s=10, color=[0.333,0.333,1], flag=true, $tags="anchor-arrow" -// Module: transparent() +// Module: show_internal_anchors() // Usage: -// transparent() ... +// show_internal_anchors() ... // Description: // Makes the children transparent gray, while showing any // anchor arrows that may exist. // Example(FlatSpin): -// transparent() cube(50, center=true) show_anchors(); -module transparent(opacity=0.2) { +// show_internal_anchors() cube(50, center=true) show_anchors(); +module show_internal_anchors(opacity=0.2) { show("anchor-arrow") children() show_anchors(); - hide("anchor-arrow") recolor([0,0,0,opacity]) children(); + hide("anchor-arrow") recolor(list_pad(point3d($color),4,fill=opacity)) children(); } @@ -240,9 +240,9 @@ module show_anchors(s=10, std=true, custom=true) { // frame_ref(25); module frame_ref(s=15) { cube(0.01, center=true) { - attach(RIGHT) anchor_arrow(s=s, color="red", flag=false); - attach(BACK) anchor_arrow(s=s, color="green", flag=false); - attach(TOP) anchor_arrow(s=s, color="blue", flag=false); + attach(RIGHT) anchor_arrow(s=s, flag=false, color="red"); + attach(BACK) anchor_arrow(s=s, flag=false, color="green"); + attach(TOP) anchor_arrow(s=s, flag=false, color="blue"); children(); } } diff --git a/examples/attachments.scad b/examples/attachments.scad index dce1262..21b6da6 100644 --- a/examples/attachments.scad +++ b/examples/attachments.scad @@ -7,10 +7,8 @@ cuboid([60,40,40], rounding=5, edges=edges("Z"), anchor=BOTTOM) { attach(TOP) cylinder(d=20, h=30) { attach(TOP) cylinder(d1=50, d2=30, h=12); } - for (a = [FRONT, BACK, LEFT, RIGHT]) { - attach(a) cylinder(d1=14, d2=5, h=20) { - attach(TOP, LEFT, overlap=5) prismoid([30,20], [20,20], h=10, shift=[-7,0]); - } + attach([FRONT, BACK, LEFT, RIGHT]) cylinder(d1=14, d2=5, h=20) { + attach(TOP, LEFT, overlap=5) prismoid([30,20], [20,20], h=10, shift=[-7,0]); } } } diff --git a/examples/bezier_patches.scad b/examples/bezier_patches.scad index cd4592d..d31bedf 100644 --- a/examples/bezier_patches.scad +++ b/examples/bezier_patches.scad @@ -2,10 +2,11 @@ include include include +rounding_factor = 0.667; -function CR_corner(size, orient=[0,0,0], trans=[0,0,0]) = +function CR_corner(size, spin=0, orient=UP, trans=[0,0,0]) = let ( - r = 0.4, + r = rounding_factor, k = r/2, // I know this patch is not yet correct for continuous // rounding, but it's a first approximation proof of concept. @@ -19,16 +20,16 @@ function CR_corner(size, orient=[0,0,0], trans=[0,0,0]) = ] ) [for (row=patch) translate_points(v=trans, - rotate_points3d(v=orient, + rotate_points3d(a=spin, from=UP, to=orient, scale_points(v=size, row) ) ) ]; -function CR_edge(size, orient=[0,0,0], trans=[0,0,0]) = +function CR_edge(size, spin=0, orient=UP, trans=[0,0,0]) = let ( - r = 0.4, + r = rounding_factor, a = -1/2, b = -1/4, c = 1/4, @@ -45,7 +46,7 @@ function CR_edge(size, orient=[0,0,0], trans=[0,0,0]) = ] ) [for (row=patch) translate_points(v=trans, - rotate_points3d(v=orient, + rotate_points3d(a=spin, from=UP, to=orient, scale_points(v=size, row) ) ) @@ -57,43 +58,43 @@ module CR_cube(size=[100,100,100], r=10, splinesteps=8, cheat=false) s = size-2*[r,r,r]; h = size/2; corners = [ - CR_corner([r,r,r], orient=ORIENT_Z, trans=[-size.x/2, -size.y/2, -size.z/2]), - CR_corner([r,r,r], orient=ORIENT_Z_90, trans=[ size.x/2, -size.y/2, -size.z/2]), - CR_corner([r,r,r], orient=ORIENT_Z_180, trans=[ size.x/2, size.y/2, -size.z/2]), - CR_corner([r,r,r], orient=ORIENT_Z_270, trans=[-size.x/2, size.y/2, -size.z/2]), + CR_corner([r,r,r], spin=0, orient=UP, trans=[-size.x/2, -size.y/2, -size.z/2]), + CR_corner([r,r,r], spin=90, orient=UP, trans=[ size.x/2, -size.y/2, -size.z/2]), + CR_corner([r,r,r], spin=180, orient=UP, trans=[ size.x/2, size.y/2, -size.z/2]), + CR_corner([r,r,r], spin=270, orient=UP, trans=[-size.x/2, size.y/2, -size.z/2]), - CR_corner([r,r,r], orient=ORIENT_ZNEG, trans=[ size.x/2, -size.y/2, size.z/2]), - CR_corner([r,r,r], orient=ORIENT_ZNEG_90, trans=[-size.x/2, -size.y/2, size.z/2]), - CR_corner([r,r,r], orient=ORIENT_ZNEG_180, trans=[-size.x/2, size.y/2, size.z/2]), - CR_corner([r,r,r], orient=ORIENT_ZNEG_270, trans=[ size.x/2, size.y/2, size.z/2]) + CR_corner([r,r,r], spin=0, orient=DOWN, trans=[ size.x/2, -size.y/2, size.z/2]), + CR_corner([r,r,r], spin=90, orient=DOWN, trans=[-size.x/2, -size.y/2, size.z/2]), + CR_corner([r,r,r], spin=180, orient=DOWN, trans=[-size.x/2, size.y/2, size.z/2]), + CR_corner([r,r,r], spin=270, orient=DOWN, trans=[ size.x/2, size.y/2, size.z/2]) ]; edges = [ - CR_edge([r, r, s.x], orient=ORIENT_X, trans=[ 0, -h.y, -h.z]), - CR_edge([r, r, s.x], orient=ORIENT_X_90, trans=[ 0, h.y, -h.z]), - CR_edge([r, r, s.x], orient=ORIENT_X_180, trans=[ 0, h.y, h.z]), - CR_edge([r, r, s.x], orient=ORIENT_X_270, trans=[ 0, -h.y, h.z]), + CR_edge([r, r, s.x], spin=0, orient=RIGHT, trans=[ 0, -h.y, h.z]), + CR_edge([r, r, s.x], spin=90, orient=RIGHT, trans=[ 0, -h.y, -h.z]), + CR_edge([r, r, s.x], spin=180, orient=RIGHT, trans=[ 0, h.y, -h.z]), + CR_edge([r, r, s.x], spin=270, orient=RIGHT, trans=[ 0, h.y, h.z]), - CR_edge([r, r, s.y], orient=ORIENT_Y, trans=[ h.x, 0, -h.z]), - CR_edge([r, r, s.y], orient=ORIENT_Y_90, trans=[-h.x, 0, -h.z]), - CR_edge([r, r, s.y], orient=ORIENT_Y_180, trans=[-h.x, 0, h.z]), - CR_edge([r, r, s.y], orient=ORIENT_Y_270, trans=[ h.x, 0, h.z]), + CR_edge([r, r, s.y], spin=0, orient=BACK, trans=[-h.x, 0, h.z]), + CR_edge([r, r, s.y], spin=90, orient=BACK, trans=[ h.x, 0, h.z]), + CR_edge([r, r, s.y], spin=180, orient=BACK, trans=[ h.x, 0, -h.z]), + CR_edge([r, r, s.y], spin=270, orient=BACK, trans=[-h.x, 0, -h.z]), - CR_edge([r, r, s.z], orient=ORIENT_Z, trans=[-h.x, -h.y, 0]), - CR_edge([r, r, s.z], orient=ORIENT_Z_90, trans=[ h.x, -h.y, 0]), - CR_edge([r, r, s.z], orient=ORIENT_Z_180, trans=[ h.x, h.y, 0]), - CR_edge([r, r, s.z], orient=ORIENT_Z_270, trans=[-h.x, h.y, 0]) + CR_edge([r, r, s.z], spin=0, orient=UP, trans=[-h.x, -h.y, 0]), + CR_edge([r, r, s.z], spin=90, orient=UP, trans=[ h.x, -h.y, 0]), + CR_edge([r, r, s.z], spin=180, orient=UP, trans=[ h.x, h.y, 0]), + CR_edge([r, r, s.z], spin=270, orient=UP, trans=[-h.x, h.y, 0]) ]; faces = [ // Yes, these are degree 1 bezier patches. That means just the four corner points. // Since these are flat, it doesn't matter what degree they are, and this will reduce calculation overhead. - bezier_patch_flat([s.y, s.z], N=1, orient=ORIENT_X, trans=[ h.x, 0, 0]), - bezier_patch_flat([s.y, s.z], N=1, orient=ORIENT_XNEG, trans=[-h.x, 0, 0]), + bezier_patch_flat([s.y, s.z], N=1, orient=RIGHT, trans=[ h.x, 0, 0]), + bezier_patch_flat([s.y, s.z], N=1, orient=LEFT, trans=[-h.x, 0, 0]), - bezier_patch_flat([s.x, s.z], N=1, orient=ORIENT_Y, trans=[ 0, h.y, 0]), - bezier_patch_flat([s.x, s.z], N=1, orient=ORIENT_YNEG, trans=[ 0, -h.y, 0]), + bezier_patch_flat([s.x, s.z], N=1, orient=BACK, trans=[ 0, h.y, 0]), + bezier_patch_flat([s.x, s.z], N=1, orient=FRONT, trans=[ 0, -h.y, 0]), - bezier_patch_flat([s.x, s.y], N=1, orient=ORIENT_Z, trans=[ 0, 0, h.z]), - bezier_patch_flat([s.x, s.y], N=1, orient=ORIENT_ZNEG, trans=[ 0, 0, -h.z]) + bezier_patch_flat([s.x, s.y], N=1, orient=UP, trans=[ 0, 0, h.z]), + bezier_patch_flat([s.x, s.y], N=1, orient=DOWN, trans=[ 0, 0, -h.z]) ]; // Generating all the patches above took about 0.05 secs. @@ -107,7 +108,7 @@ module CR_cube(size=[100,100,100], r=10, splinesteps=8, cheat=false) } -CR_cube(size=[100,100,100], r=20, splinesteps=9, cheat=false); +CR_cube(size=[100,100,100], r=20, splinesteps=15, cheat=false); cube(1); diff --git a/examples/orientations.scad b/examples/orientations.scad index fa4318f..9cabdfd 100644 --- a/examples/orientations.scad +++ b/examples/orientations.scad @@ -3,46 +3,60 @@ include // Shows all the orientations on cubes in their correct rotations. orientations = [ - ORIENT_X, ORIENT_Y, ORIENT_Z, - ORIENT_XNEG, ORIENT_YNEG, ORIENT_ZNEG, - - ORIENT_X_90, ORIENT_Y_90, ORIENT_Z_90, - ORIENT_XNEG_90, ORIENT_YNEG_90, ORIENT_ZNEG_90, - - ORIENT_X_180, ORIENT_Y_180, ORIENT_Z_180, - ORIENT_XNEG_180, ORIENT_YNEG_180, ORIENT_ZNEG_180, - - ORIENT_X_270, ORIENT_Y_270, ORIENT_Z_270, - ORIENT_XNEG_270, ORIENT_YNEG_270, ORIENT_ZNEG_270 + RIGHT, BACK, UP, + LEFT, FWD, DOWN, ]; - - +axiscolors = ["red", "forestgreen", "dodgerblue"]; axisdiam = 0.5; axislen = 12; axislbllen = 15; -axiscolors = ["red", "forestgreen", "dodgerblue"]; + +module orient_cube(ang) { + color("lightgray") cube(20, center=true); + color(axiscolors.x) up ((20-1)/2+0.01) back ((20-1)/2+0.01) cube([18,1,1], center=true); + color(axiscolors.y) up ((20-1)/2+0.01) right((20-1)/2+0.01) cube([1,18,1], center=true); + color(axiscolors.z) back((20-1)/2+0.01) right((20-1)/2+0.01) cube([1,1,18], center=true); + for (axis=[0:2], neg=[0:1]) { + idx = axis + 3*neg; + labels = [ + "RIGHT", "BACK", "UP", + "LEFT", "FWD", "DOWN" + ]; + rot(ang, from=UP, to=orientations[idx]) { + up(10) { + back(4) color("black") text3d(text=str("spin=",ang), size=2.5); + fwd(2) color(axiscolors[axis]) text3d(text="orient=", size=2.5); + fwd(6) color(axiscolors[axis]) text3d(text=labels[idx], size=2.5); + } + } + } +} + module text3d(text, h=0.01, size=3) { - linear_extrude(height=h, convexity=10) { - text(text=text, size=size, valign="center", halign="center"); - } + linear_extrude(height=h, convexity=10) { + text(text=text, size=size, valign="center", halign="center"); + } } module dottedline(l, d) for(y = [0:d*3:l]) up(y) sphere(d=d); module orient_cubes() { + // X axis color(axiscolors[0]) { yrot( 90) cylinder(h=axislen, d=axisdiam, center=false); right(axislbllen) rot([90,0,0]) text3d(text="X+"); yrot(-90) dottedline(l=axislen, d=axisdiam); left(axislbllen) rot([90,0,180]) text3d(text="X-"); } + // Y axis color(axiscolors[1]) { xrot(-90) cylinder(h=axislen, d=axisdiam, center=false); back(axislbllen) rot([90,0,90]) text3d(text="Y+"); xrot( 90) dottedline(l=axislen, d=axisdiam); fwd(axislbllen) rot([90,0,-90]) text3d(text="Y-"); } + // Z axis color(axiscolors[2]) { cylinder(h=axislen, d=axisdiam, center=false); up(axislbllen) rot([0,-90,90+$vpr[2]]) text3d(text="Z+"); @@ -50,30 +64,15 @@ module orient_cubes() { down(axislbllen) rot([0,90,-90+$vpr[2]]) text3d(text="Z-"); } - for (ang = [0:90:270]) { - translate(cylindrical_to_xyz(40, ang+90, 0)) { - color("lightgray") cube(20, center=true); - } - } - - for (axis=[0:2], neg=[0:1], ang = [0:90:270]) { - idx = axis + 3*neg + 6*ang/90; - translate(cylindrical_to_xyz(40, ang+90, 0)) { - rotate(orientations[idx]) { - up(10) { - ydistribute(8) { - color("black") text3d(text=str(ang, "º"), size=5); - color(axiscolors[axis]) text3d(text=str(["X","Y","Z"][axis], ["+","-"][neg]), size=5); - } - } - } + off = rotate_points3d([40*BACK],ang)[0]; + translate(off) { + orient_cube(ang); } } } -//rotate(a=180, v=[1,1,0]) orient_cubes(); diff --git a/involute_gears.scad b/involute_gears.scad index 28b1040..dc2a7b2 100644 --- a/involute_gears.scad +++ b/involute_gears.scad @@ -284,8 +284,9 @@ module gear2d( // slices = Number of vertical layers to divide gear into. Useful for refining gears with `twist`. // scale = Scale of top of gear compared to bottom. Useful for making crown gears. // interior = If true, create a mask for difference()ing from something else. -// orient = Orientation of the gear. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the gear. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example: Spur Gear // gear(mm_per_tooth=5, number_of_teeth=20, thickness=8, hole_diameter=5); // Example: Beveled Gear @@ -303,14 +304,15 @@ module gear( twist = undef, slices = undef, interior = false, - orient = ORIENT_Z, anchor = CENTER + spin = 0, + orient = UP ) { p = pitch_radius(mm_per_tooth, number_of_teeth); c = outer_radius(mm_per_tooth, number_of_teeth, clearance, interior); r = root_radius(mm_per_tooth, number_of_teeth, clearance, interior); p2 = p - (thickness*tan(bevelang)); - orient_and_anchor([p, p, thickness], orient, anchor, geometry="cylinder", chain=true) { + orient_and_anchor([p, p, thickness], orient, anchor, spin=spin, geometry="cylinder", chain=true) { difference() { linear_extrude(height=thickness, center=true, convexity=10, twist=twist, scale=p2/p, slices=slices) { gear2d( @@ -354,8 +356,9 @@ module gear( // height = Height of rack in mm, from tooth top to back of rack. // pressure_angle = Controls how straight or bulged the tooth sides are. In degrees. // backlash = Gap between two meshing teeth, in the direction along the circumference of the pitch circle -// orient = Orientation of the rack. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_X`. -// anchor = Alignment of the rack. Use the constants from `constants.scad`. Default: `RIGHT`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Anchors: // "adendum" = At the tips of the teeth, at the center of rack. // "adendum-left" = At the tips of the teeth, at the left end of the rack. @@ -377,8 +380,9 @@ module rack( pressure_angle = 28, backlash = 0.0, clearance = undef, - orient = ORIENT_Z, anchor = CENTER + spin = 0, + orient = UP ) { a = adendum(mm_per_tooth); d = dedendum(mm_per_tooth, clearance); @@ -397,7 +401,7 @@ module rack( anchorpt("dedendum-top", [0,-d,thickness/2], UP), anchorpt("dedendum-bottom", [0,-d,-thickness/2], DOWN), ]; - orient_and_anchor([l, 2*abs(a-height), thickness], orient, anchor, anchors=anchors, chain=true) { + orient_and_anchor([l, 2*abs(a-height), thickness], orient, anchor, spin=spin, anchors=anchors, chain=true) { left((number_of_teeth-1)*mm_per_tooth/2) { linear_extrude(height = thickness, center = true, convexity = 10) { for (i = [0:number_of_teeth-1] ) { diff --git a/joiners.scad b/joiners.scad index 98da13b..4c3989d 100644 --- a/joiners.scad +++ b/joiners.scad @@ -23,18 +23,19 @@ // a = Overhang angle of the joiner. // clearance = Extra width to clear. // overlap = Extra depth to clear. -// orient = Orientation of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. -// anchor = Alignment of the shape by the axis-negative (size1) end. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example: -// half_joiner_clear(orient=ORIENT_X); -module half_joiner_clear(h=20, w=10, a=30, clearance=0, overlap=0.01, orient=ORIENT_Y, anchor=CENTER) +// half_joiner_clear(spin=-90); +module half_joiner_clear(h=20, w=10, a=30, clearance=0, overlap=0.01, anchor=CENTER, spin=0, orient=UP) { dmnd_height = h*1.0; dmnd_width = dmnd_height*tan(a); guide_size = w/3; guide_width = 2*(dmnd_height/2-guide_size)*tan(a); - orient_and_anchor([w, guide_width, h], orient, anchor, orig_orient=ORIENT_Y) { + orient_and_anchor([w, guide_width, h], orient, anchor, spin=spin) { union() { yspread(overlap, n=overlap>0? 2 : 1) { difference() { @@ -68,11 +69,12 @@ module half_joiner_clear(h=20, w=10, a=30, clearance=0, overlap=0.01, orient=ORI // screwsize = Diameter of screwhole. // guides = If true, create sliding alignment guides. // slop = Printer specific slop value to make parts fit more closely. -// orient = Orientation of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. -// anchor = Alignment of the shape by the axis-negative (size1) end. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example: -// half_joiner(screwsize=3, orient=ORIENT_X); -module half_joiner(h=20, w=10, l=10, a=30, screwsize=undef, guides=true, slop=PRINTER_SLOP, orient=ORIENT_Y, anchor=CENTER) +// half_joiner(screwsize=3, spin=-90); +module half_joiner(h=20, w=10, l=10, a=30, screwsize=undef, guides=true, slop=PRINTER_SLOP, anchor=CENTER, spin=0, orient=UP) { dmnd_height = h*1.0; dmnd_width = dmnd_height*tan(a); @@ -82,11 +84,11 @@ module half_joiner(h=20, w=10, l=10, a=30, screwsize=undef, guides=true, slop=PR if ($children > 0) { difference() { children(); - half_joiner_clear(h=h, w=w, a=a, clearance=0.1, overlap=0.01, orient=orient, anchor=anchor); + half_joiner_clear(h=h, w=w, a=a, clearance=0.1, overlap=0.01, anchor=anchor, spin=spin, orient=orient); } } render(convexity=12) - orient_and_anchor([w, 2*l, h], orient, anchor, orig_orient=ORIENT_Y) { + orient_and_anchor([w, 2*l, h], orient, anchor, spin=spin) { difference() { union() { // Make base. @@ -134,7 +136,7 @@ module half_joiner(h=20, w=10, l=10, a=30, screwsize=undef, guides=true, slop=PR } } } -//half_joiner(screwsize=3, orient=ORIENT_Z, anchor=UP); +//half_joiner(screwsize=3); @@ -150,11 +152,12 @@ module half_joiner(h=20, w=10, l=10, a=30, screwsize=undef, guides=true, slop=PR // a = Overhang angle of the half_joiner. // screwsize = Diameter of screwhole. // guides = If true, create sliding alignment guides. -// orient = Orientation of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. -// anchor = Alignment of the shape by the axis-negative (size1) end. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example: -// half_joiner2(screwsize=3, orient=ORIENT_X); -module half_joiner2(h=20, w=10, l=10, a=30, screwsize=undef, guides=true, orient=ORIENT_Y, anchor=CENTER) +// half_joiner2(screwsize=3, spin=-90); +module half_joiner2(h=20, w=10, l=10, a=30, screwsize=undef, guides=true, anchor=CENTER, spin=0, orient=UP) { dmnd_height = h*1.0; dmnd_width = dmnd_height*tan(a); @@ -164,12 +167,12 @@ module half_joiner2(h=20, w=10, l=10, a=30, screwsize=undef, guides=true, orient if ($children > 0) { difference() { children(); - half_joiner_clear(h=h, w=w, a=a, clearance=0.1, overlap=0.01, orient=orient, anchor=anchor); + half_joiner_clear(h=h, w=w, a=a, clearance=0.1, overlap=0.01, orient=orient, spin=spin, anchor=anchor); } } render(convexity=12) - orient_and_anchor([w, 2*l, h], orient, anchor, orig_orient=ORIENT_Y) { + orient_and_anchor([w, 2*l, h], orient, anchor, spin=spin) { difference() { union () { fwd(l/2) cube(size=[w, l, h], center=true); @@ -203,18 +206,19 @@ module half_joiner2(h=20, w=10, l=10, a=30, screwsize=undef, guides=true, orient // a = Overhang angle of the joiner. // clearance = Extra width to clear. // overlap = Extra depth to clear. -// orient = Orientation of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. -// anchor = Alignment of the shape by the axis-negative (size1) end. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example: -// joiner_clear(orient=ORIENT_X); -module joiner_clear(h=40, w=10, a=30, clearance=0, overlap=0.01, orient=ORIENT_Y, anchor=CENTER) +// joiner_clear(spin=-90); +module joiner_clear(h=40, w=10, a=30, clearance=0, overlap=0.01, anchor=CENTER, spin=0, orient=UP) { dmnd_height = h*0.5; dmnd_width = dmnd_height*tan(a); guide_size = w/3; guide_width = 2*(dmnd_height/2-guide_size)*tan(a); - orient_and_anchor([w, guide_width, h], orient, anchor, orig_orient=ORIENT_Y) { + orient_and_anchor([w, guide_width, h], orient, anchor, spin=spin) { union() { up(h/4) half_joiner_clear(h=h/2.0-0.01, w=w, a=a, overlap=overlap, clearance=clearance); down(h/4) half_joiner_clear(h=h/2.0-0.01, w=w, a=a, overlap=overlap, clearance=-0.01); @@ -237,20 +241,21 @@ module joiner_clear(h=40, w=10, a=30, clearance=0, overlap=0.01, orient=ORIENT_Y // screwsize = Diameter of screwhole. // guides = If true, create sliding alignment guides. // slop = Printer specific slop value to make parts fit more closely. -// orient = Orientation of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. -// anchor = Alignment of the shape by the axis-negative (size1) end. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Examples: -// joiner(screwsize=3, orient=ORIENT_X); -// joiner(w=10, l=10, h=40, orient=ORIENT_X) cuboid([10, 10*2, 40], anchor=RIGHT); -module joiner(h=40, w=10, l=10, a=30, screwsize=undef, guides=true, slop=PRINTER_SLOP, orient=ORIENT_Y, anchor=CENTER) +// joiner(screwsize=3, spin=-90); +// joiner(w=10, l=10, h=40, spin=-90) cuboid([10, 10*2, 40], anchor=RIGHT); +module joiner(h=40, w=10, l=10, a=30, screwsize=undef, guides=true, slop=PRINTER_SLOP, anchor=CENTER, spin=0, orient=UP) { if ($children > 0) { difference() { children(); - joiner_clear(h=h, w=w, a=a, clearance=0.1, orient=orient, anchor=anchor); + joiner_clear(h=h, w=w, a=a, clearance=0.1, orient=orient, spin=spin, anchor=anchor); } } - orient_and_anchor([w, 2*l, h], orient, anchor, orig_orient=ORIENT_Y) { + orient_and_anchor([w, 2*l, h], orient, anchor, spin=spin) { union() { up(h/4) half_joiner(h=h/2, w=w, l=l, a=a, screwsize=screwsize, guides=guides, slop=slop); down(h/4) half_joiner2(h=h/2, w=w, l=l, a=a, screwsize=screwsize, guides=guides); @@ -276,19 +281,20 @@ module joiner(h=40, w=10, l=10, a=30, screwsize=undef, guides=true, slop=PRINTER // n = Number of joiners (2 by default) to clear for. // clearance = Extra width to clear. // overlap = Extra depth to clear. -// orient = Orientation of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. -// anchor = Alignment of the shape by the axis-negative (size1) end. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Examples: // joiner_pair_clear(spacing=50, n=2); // joiner_pair_clear(spacing=50, n=3); -module joiner_pair_clear(spacing=100, h=40, w=10, a=30, n=2, clearance=0, overlap=0.01, orient=ORIENT_Y, anchor=CENTER) +module joiner_pair_clear(spacing=100, h=40, w=10, a=30, n=2, clearance=0, overlap=0.01, anchor=CENTER, spin=0, orient=UP) { dmnd_height = h*0.5; dmnd_width = dmnd_height*tan(a); guide_size = w/3; guide_width = 2*(dmnd_height/2-guide_size)*tan(a); - orient_and_anchor([spacing+w, guide_width, h], orient, anchor, orig_orient=ORIENT_Y) { + orient_and_anchor([spacing+w, guide_width, h], orient, anchor, spin=spin) { xspread(spacing, n=n) { joiner_clear(h=h, w=w, a=a, clearance=clearance, overlap=overlap); } @@ -313,23 +319,24 @@ module joiner_pair_clear(spacing=100, h=40, w=10, a=30, n=2, clearance=0, overla // screwsize = Diameter of screwhole. // guides = If true, create sliding alignment guides. // slop = Printer specific slop value to make parts fit more closely. -// orient = Orientation of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. -// anchor = Alignment of the shape by the axis-negative (size1) end. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Examples: -// joiner_pair(spacing=50, l=10, orient=ORIENT_X) cuboid([10, 50+10-0.1, 40], anchor=RIGHT); -// joiner_pair(spacing=50, l=10, n=2, orient=ORIENT_X); -// joiner_pair(spacing=50, l=10, n=3, alternate=false, orient=ORIENT_X); -// joiner_pair(spacing=50, l=10, n=3, alternate=true, orient=ORIENT_X); -// joiner_pair(spacing=50, l=10, n=3, alternate="alt", orient=ORIENT_X); -module joiner_pair(spacing=100, h=40, w=10, l=10, a=30, n=2, alternate=true, screwsize=undef, guides=true, slop=PRINTER_SLOP, orient=ORIENT_Y, anchor=CENTER) +// joiner_pair(spacing=50, l=10, spin=-90) cuboid([10, 50+10-0.1, 40], anchor=RIGHT); +// joiner_pair(spacing=50, l=10, n=2, spin=-90); +// joiner_pair(spacing=50, l=10, n=3, alternate=false, spin=-90); +// joiner_pair(spacing=50, l=10, n=3, alternate=true, spin=-90); +// joiner_pair(spacing=50, l=10, n=3, alternate="alt", spin=-90); +module joiner_pair(spacing=100, h=40, w=10, l=10, a=30, n=2, alternate=true, screwsize=undef, guides=true, slop=PRINTER_SLOP, anchor=CENTER, spin=0, orient=UP) { if ($children > 0) { difference() { children(); - joiner_pair_clear(spacing=spacing, h=h, w=w, a=a, clearance=0.1, orient=orient, anchor=anchor); + joiner_pair_clear(spacing=spacing, h=h, w=w, a=a, clearance=0.1, orient=orient, spin=spin, anchor=anchor); } } - orient_and_anchor([spacing+w, 2*l, h], orient, anchor, orig_orient=ORIENT_Y) { + orient_and_anchor([spacing+w, 2*l, h], orient, anchor, spin=spin) { left((n-1)*spacing/2) { for (i=[0:n-1]) { right(i*spacing) { @@ -361,16 +368,17 @@ module joiner_pair(spacing=100, h=40, w=10, l=10, a=30, n=2, alternate=true, scr // n = Number of joiners in a row. Default: 2 // clearance = Extra width to clear. // overlap = Extra depth to clear. -// orient = Orientation of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. -// anchor = Alignment of the shape by the axis-negative (size1) end. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Examples: // joiner_quad_clear(spacing1=50, spacing2=50, n=2); // joiner_quad_clear(spacing1=50, spacing2=50, n=3); -module joiner_quad_clear(xspacing=undef, yspacing=undef, spacing1=undef, spacing2=undef, n=2, h=40, w=10, a=30, clearance=0, overlap=0.01, orient=ORIENT_Y, anchor=CENTER) +module joiner_quad_clear(xspacing=undef, yspacing=undef, spacing1=undef, spacing2=undef, n=2, h=40, w=10, a=30, clearance=0, overlap=0.01, anchor=CENTER, spin=0, orient=UP) { spacing1 = first_defined([spacing1, xspacing, 100]); spacing2 = first_defined([spacing2, yspacing, 50]); - orient_and_anchor([w+spacing1, spacing2, h], orient, anchor, orig_orient=ORIENT_Y) { + orient_and_anchor([w+spacing1, spacing2, h], orient, anchor, spin=spin) { zrot_copies(n=2) { back(spacing2/2) { joiner_pair_clear(spacing=spacing1, n=n, h=h, w=w, a=a, clearance=clearance, overlap=overlap); @@ -397,25 +405,26 @@ module joiner_quad_clear(xspacing=undef, yspacing=undef, spacing1=undef, spacing // screwsize = Diameter of screwhole. // guides = If true, create sliding alignment guides. // slop = Printer specific slop value to make parts fit more closely. -// orient = Orientation of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. -// anchor = Alignment of the shape by the axis-negative (size1) end. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Examples: -// joiner_quad(spacing1=50, spacing2=50, l=10, orient=ORIENT_X) cuboid([50, 50+10-0.1, 40]); -// joiner_quad(spacing1=50, spacing2=50, l=10, n=2, orient=ORIENT_X); -// joiner_quad(spacing1=50, spacing2=50, l=10, n=3, alternate=false, orient=ORIENT_X); -// joiner_quad(spacing1=50, spacing2=50, l=10, n=3, alternate=true, orient=ORIENT_X); -// joiner_quad(spacing1=50, spacing2=50, l=10, n=3, alternate="alt", orient=ORIENT_X); -module joiner_quad(spacing1=undef, spacing2=undef, xspacing=undef, yspacing=undef, h=40, w=10, l=10, a=30, n=2, alternate=true, screwsize=undef, guides=true, slop=PRINTER_SLOP, orient=ORIENT_Y, anchor=CENTER) +// joiner_quad(spacing1=50, spacing2=50, l=10, spin=-90) cuboid([50, 50+10-0.1, 40]); +// joiner_quad(spacing1=50, spacing2=50, l=10, n=2, spin=-90); +// joiner_quad(spacing1=50, spacing2=50, l=10, n=3, alternate=false, spin=-90); +// joiner_quad(spacing1=50, spacing2=50, l=10, n=3, alternate=true, spin=-90); +// joiner_quad(spacing1=50, spacing2=50, l=10, n=3, alternate="alt", spin=-90); +module joiner_quad(spacing1=undef, spacing2=undef, xspacing=undef, yspacing=undef, h=40, w=10, l=10, a=30, n=2, alternate=true, screwsize=undef, guides=true, slop=PRINTER_SLOP, anchor=CENTER, spin=0, orient=UP) { spacing1 = first_defined([spacing1, xspacing, 100]); spacing2 = first_defined([spacing2, yspacing, 50]); if ($children > 0) { difference() { children(); - joiner_quad_clear(spacing1=spacing1, spacing2=spacing2, h=h, w=w, a=a, clearance=0.1, orient=orient, anchor=anchor); + joiner_quad_clear(spacing1=spacing1, spacing2=spacing2, h=h, w=w, a=a, clearance=0.1, orient=orient, spin=spin, anchor=anchor); } } - orient_and_anchor([w+spacing1, spacing2, h], orient, anchor, orig_orient=ORIENT_Y) { + orient_and_anchor([w+spacing1, spacing2, h], orient, anchor, spin=spin) { zrot_copies(n=2) { back(spacing2/2) { joiner_pair(spacing=spacing1, n=n, h=h, w=w, l=l, a=a, screwsize=screwsize, guides=guides, slop=slop); diff --git a/linear_bearings.scad b/linear_bearings.scad index e4909b5..b8d99c2 100644 --- a/linear_bearings.scad +++ b/linear_bearings.scad @@ -76,11 +76,12 @@ function get_lmXuu_bearing_length(size) = lookup(size, [ // wall = Wall thickness of clamp housing. (Default: 3) // gap = Gap in clamp. (Default: 5) // screwsize = Size of screw to use to tighten clamp. (Default: 3) -// orient = Orientation of the housing. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_X`. -// anchor = Alignment of the housing by the axis-negative (size1) end. Use the constants from `constants.scad`. Default: `UP` +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example: // linear_bearing_housing(d=19, l=29, wall=2, tab=6, screwsize=2.5); -module linear_bearing_housing(d=15, l=24, tab=7, gap=5, wall=3, tabwall=5, screwsize=3, orient=ORIENT_X, anchor=BOTTOM) +module linear_bearing_housing(d=15, l=24, tab=7, gap=5, wall=3, tabwall=5, screwsize=3, anchor=BOTTOM, spin=0, orient=UP) { od = d+2*wall; ogap = gap+2*tabwall; @@ -91,7 +92,7 @@ module linear_bearing_housing(d=15, l=24, tab=7, gap=5, wall=3, tabwall=5, screw anchorpt("screw", [0,2-ogap/2,tabh-tab/2/2],FWD), anchorpt("nut", [0,ogap/2-2,tabh-tab/2/2],FWD) ]; - orient_and_anchor([l, od, h], orient, anchor, anchors=anchors, orig_orient=ORIENT_X, chain=true) { + orient_and_anchor([l, od, h], orient, anchor, spin=spin, anchors=anchors, chain=true) { down(tab/2/2) difference() { union() { @@ -113,10 +114,10 @@ module linear_bearing_housing(d=15, l=24, tab=7, gap=5, wall=3, tabwall=5, screw up(tabh) { // Screwhole - fwd(ogap/2-2+0.01) xrot(90) screw(screwsize=screwsize*1.06, screwlen=ogap, headsize=screwsize*2, headlen=10); + fwd(ogap/2-2+0.01) screw(screwsize=screwsize*1.06, screwlen=ogap, headsize=screwsize*2, headlen=10, orient=FWD); // Nut holder - back(ogap/2-2+0.01) xrot(90) metric_nut(size=screwsize, hole=false); + back(ogap/2-2+0.01) metric_nut(size=screwsize, hole=false, anchor=BOTTOM, orient=BACK); } } children(); @@ -134,15 +135,16 @@ module linear_bearing_housing(d=15, l=24, tab=7, gap=5, wall=3, tabwall=5, screw // wall = Wall thickness of clamp housing. Default: 3 // gap = Gap in clamp. Default: 5 // screwsize = Size of screw to use to tighten clamp. Default: 3 -// orient = Orientation of the housing. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_X`. -// anchor = Alignment of the housing by the axis-negative (size1) end. Use the constants from `constants.scad`. Default: `UP` +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example: // lmXuu_housing(size=10, wall=2, tab=6, screwsize=2.5); -module lmXuu_housing(size=8, tab=7, gap=5, wall=3, tabwall=5, screwsize=3, orient=ORIENT_X, anchor=BOTTOM) +module lmXuu_housing(size=8, tab=7, gap=5, wall=3, tabwall=5, screwsize=3, anchor=BOTTOM, spin=0, orient=UP) { d = get_lmXuu_bearing_diam(size); l = get_lmXuu_bearing_length(size); - linear_bearing_housing(d=d,l=l,tab=tab,gap=gap,wall=wall,tabwall=tabwall,screwsize=screwsize, orient=orient, anchor=anchor) children(); + linear_bearing_housing(d=d, l=l, tab=tab, gap=gap, wall=wall, tabwall=tabwall, screwsize=screwsize, orient=orient, spin=spin, anchor=anchor) children(); } diff --git a/masks.scad b/masks.scad index 4168eff..c4d1aa5 100644 --- a/masks.scad +++ b/masks.scad @@ -25,21 +25,22 @@ // d = Diameter of circle wedge is created from. (optional) // d1 = Bottom diameter of cone that wedge is created from. (optional) // d2 = Upper diameter of cone that wedge is created from. (optional) -// orient = Orientation of the pie slice. Use the ORIENT_ constants from constants.h. Default: ORIENT_Z. -// anchor = Alignment of the pie slice. Use the constants from constants.h. Default: CENTER. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example(FR): // angle_pie_mask(ang=30, d=100, l=20); module angle_pie_mask( ang=45, l=undef, r=undef, r1=undef, r2=undef, d=undef, d1=undef, d2=undef, - orient=ORIENT_Z, anchor=CENTER, - h=undef + h=undef, + anchor=CENTER, spin=0, orient=UP ) { l = first_defined([l, h, 1]); r1 = get_radius(r1, r, d1, d, 10); r2 = get_radius(r2, r, d2, d, 10); - orient_and_anchor([2*r1, 2*r1, l], orient, anchor, chain=true) { + orient_and_anchor([2*r1, 2*r1, l], orient, anchor, spin=spin, chain=true) { pie_slice(ang=ang, l=l+0.1, r1=r1, r2=r2, anchor=CENTER); children(); } @@ -84,8 +85,9 @@ module angle_pie_mask( // from_end = If true, chamfer/bevel size is measured from end of region. If false, chamfer/bevel is measured outset from the radius of the region. (Default: false) // overage = The extra thickness of the mask. Default: `10`. // ends_only = If true, only mask the ends and not around the middle of the cylinder. -// orient = Orientation. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the region. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example: // difference() { // cylinder(h=100, r1=60, r2=30, center=true); @@ -104,7 +106,7 @@ module cylinder_mask( rounding=undef, rounding1=undef, rounding2=undef, circum=false, from_end=false, overage=10, ends_only=false, - orient=ORIENT_Z, anchor=CENTER + anchor=CENTER, spin=0, orient=UP ) { r1 = get_radius(r=r, d=d, r1=r1, d1=d1, dflt=1); r2 = get_radius(r=r, d=d, r1=r2, d1=d2, dflt=1); @@ -124,7 +126,7 @@ module cylinder_mask( cylinder_mask(l=l, r1=sc*r1, r2=sc*r2, chamfer1=cham1, chamfer2=cham2, chamfang1=ang1, chamfang2=ang2, rounding1=fil1, rounding2=fil2, orient=orient, from_end=from_end); } } else { - orient_and_anchor([2*r1, 2*r1, l], orient, anchor, chain=true) { + orient_and_anchor([2*r1, 2*r1, l], orient, anchor, spin=spin, chain=true) { difference() { union() { chlen1 = cham1 / (from_end? 1 : tan(ang1)); @@ -160,15 +162,16 @@ module cylinder_mask( // Arguments: // l = Length of mask. // chamfer = Size of chamfer -// orient = Orientation of the mask. Use the `ORIENT_` constants from `constants.h`. Default: vertical. -// anchor = Alignment of the mask. Use the constants from `constants.h`. Default: centered. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example: // difference() { // cube(50, anchor=BOTTOM+FRONT); -// #chamfer_mask(l=50, chamfer=10, orient=ORIENT_X); +// #chamfer_mask(l=50, chamfer=10, orient=RIGHT); // } -module chamfer_mask(l=1, chamfer=1, orient=ORIENT_Z, anchor=CENTER) { - orient_and_anchor([chamfer*2, chamfer*2, l], orient, anchor, chain=true) { +module chamfer_mask(l=1, chamfer=1, anchor=CENTER, spin=0, orient=UP) { + orient_and_anchor([chamfer*2, chamfer*2, l], orient, anchor, spin=spin, chain=true) { cylinder(r=chamfer, h=l+0.1, center=true, $fn=4); children(); } @@ -185,14 +188,15 @@ module chamfer_mask(l=1, chamfer=1, orient=ORIENT_Z, anchor=CENTER) { // Arguments: // l = Height of mask // chamfer = size of chamfer -// anchor = Alignment of the cylinder. Use the constants from constants.h. Default: centered. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the X axis after anchor. See [spin](attachments#spin). Default: `0` // Example: // difference() { // cube(50, anchor=BOTTOM+FRONT); // #chamfer_mask_x(l=50, chamfer=10); // } -module chamfer_mask_x(l=1.0, chamfer=1.0, anchor=CENTER) { - chamfer_mask(l=l, chamfer=chamfer, orient=ORIENT_X, anchor=anchor) children(); +module chamfer_mask_x(l=1.0, chamfer=1.0, anchor=CENTER, spin=0) { + chamfer_mask(l=l, chamfer=chamfer, anchor=anchor, spin=spin, orient=RIGHT) children(); } @@ -206,14 +210,15 @@ module chamfer_mask_x(l=1.0, chamfer=1.0, anchor=CENTER) { // Arguments: // l = Height of mask // chamfer = size of chamfer -// anchor = Alignment of the cylinder. Use the constants from constants.h. Default: centered. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Y axis after anchor. See [spin](attachments#spin). Default: `0` // Example: // difference() { // cube(50, anchor=BOTTOM+RIGHT); // #chamfer_mask_y(l=50, chamfer=10); // } -module chamfer_mask_y(l=1.0, chamfer=1.0, anchor=CENTER) { - chamfer_mask(l=l, chamfer=chamfer, orient=ORIENT_Y, anchor=anchor) children(); +module chamfer_mask_y(l=1.0, chamfer=1.0, anchor=CENTER, spin=0) { + chamfer_mask(l=l, chamfer=chamfer, anchor=anchor, spin=spin, orient=BACK) children(); } @@ -227,14 +232,15 @@ module chamfer_mask_y(l=1.0, chamfer=1.0, anchor=CENTER) { // Arguments: // l = Height of mask // chamfer = size of chamfer -// anchor = Alignment of the cylinder. Use the constants from constants.h. Default: centered. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` // Example: // difference() { // cube(50, anchor=FRONT+RIGHT); // #chamfer_mask_z(l=50, chamfer=10); // } -module chamfer_mask_z(l=1.0, chamfer=1.0, anchor=CENTER) { - chamfer_mask(l=l, chamfer=chamfer, orient=ORIENT_Z, anchor=anchor) children(); +module chamfer_mask_z(l=1.0, chamfer=1.0, anchor=CENTER, spin=0) { + chamfer_mask(l=l, chamfer=chamfer, anchor=anchor, spin=spin, orient=UP) children(); } @@ -289,7 +295,9 @@ module chamfer(chamfer=1, size=[1,1,1], edges=EDGES_ALL) // chamfer = Size of the edge chamferred, inset from edge. (Default: 0.25) // ang = Angle of chamfer in degrees from vertical. (Default: 45) // from_end = If true, chamfer size is measured from end of cylinder. If false, chamfer is measured outset from the radius of the cylinder. (Default: false) -// orient = Orientation of the mask. Use the `ORIENT_` constants from `constants.h`. Default: ORIENT_Z. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example: // difference() { // cylinder(r=50, h=100, center=true); @@ -300,10 +308,13 @@ module chamfer(chamfer=1, size=[1,1,1], edges=EDGES_ALL) // cylinder(r=50, h=100, center=true); // up(50) chamfer_cylinder_mask(r=50, chamfer=10); // } -module chamfer_cylinder_mask(r=undef, d=undef, chamfer=0.25, ang=45, from_end=false, orient=ORIENT_Z) +module chamfer_cylinder_mask(r=undef, d=undef, chamfer=0.25, ang=45, from_end=false, anchor=CENTER, spin=0, orient=UP) { r = get_radius(r=r, d=d, dflt=1); - rot(orient) cylinder_mask(l=chamfer*3, r=r, chamfer2=chamfer, chamfang2=ang, from_end=from_end, ends_only=true, anchor=TOP); + orient_and_anchor([2*r,2*r,chamfer*2], orient, anchor, spin=spin, chain=true) { + cylinder_mask(l=chamfer*3, r=r, chamfer2=chamfer, chamfang2=ang, from_end=from_end, ends_only=true, anchor=TOP); + children(); + } } @@ -321,8 +332,9 @@ module chamfer_cylinder_mask(r=undef, d=undef, chamfer=0.25, ang=45, from_end=fa // ang = Angle of chamfer in degrees from vertical. (Default: 45) // from_end = If true, chamfer size is measured from end of hole. If false, chamfer is measured outset from the radius of the hole. (Default: false) // overage = The extra thickness of the mask. Default: `0.1`. -// orient = Orientation of the mask. Use the `ORIENT_` constants from `constants.h`. Default: `ORIENT_Z`. -// anchor = Alignment of the mask. Use the constants from `constants.h`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example: // difference() { // cube(100, center=true); @@ -337,13 +349,13 @@ module chamfer_cylinder_mask(r=undef, d=undef, chamfer=0.25, ang=45, from_end=fa // } // Example: // chamfer_hole_mask(d=100, chamfer=25, ang=30, overage=10); -module chamfer_hole_mask(r=undef, d=undef, chamfer=0.25, ang=45, from_end=false, overage=0.1, orient=ORIENT_Z, anchor=CENTER) +module chamfer_hole_mask(r=undef, d=undef, chamfer=0.25, ang=45, from_end=false, overage=0.1, anchor=CENTER, spin=0, orient=UP) { r = get_radius(r=r, d=d, dflt=1); h = chamfer * (from_end? 1 : tan(90-ang)); r2 = r + chamfer * (from_end? tan(ang) : 1); $fn = segs(r); - orient_and_anchor([2*r, 2*r, h*2], orient, anchor, size2=[2*r2, 2*r2], chain=true) { + orient_and_anchor([2*r, 2*r, h*2], orient, anchor, spin=spin, size2=[2*r2, 2*r2], chain=true) { union() { cylinder(r=r2, h=overage, center=false); down(h) cylinder(r1=r, r2=r2, h=h, center=false); @@ -366,18 +378,36 @@ module chamfer_hole_mask(r=undef, d=undef, chamfer=0.25, ang=45, from_end=false, // Arguments: // l = Length of mask. // r = Radius of the rounding. -// orient = Orientation of the mask. Use the `ORIENT_` constants from `constants.h`. Default: vertical. -// anchor = Alignment of the mask. Use the constants from `constants.h`. Default: centered. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example: // difference() { // cube(size=100, center=false); -// #rounding_mask(l=100, r=25, orient=ORIENT_Z, anchor=BOTTOM); +// #rounding_mask(l=100, r=25, orient=UP, anchor=BOTTOM); // } -module rounding_mask(l=undef, r=1.0, orient=ORIENT_Z, anchor=CENTER, h=undef) +// Example: Masking by Attachment +// diff("mask") +// cube(100, center=true) +// attach(FRONT+RIGHT) +// #rounding_mask(l=$parent_size.z+0.01, r=25, spin=45, orient=BACK, $tags="mask"); +// Example: Multiple Masking by Attachment +// diff("mask") +// cube([80,90,100], center=true) { +// let(p = $parent_size*1.01, $tags="mask") { +// attach([for (x=[-1,1],y=[-1,1]) [x,y,0]]) +// rounding_mask(l=p.z, r=25, spin=45, orient=BACK); +// attach([for (x=[-1,1],z=[-1,1]) [x,0,z]]) +// chamfer_mask(l=p.y, chamfer=20, spin=45, orient=RIGHT); +// attach([for (y=[-1,1],z=[-1,1]) [0,y,z]]) +// rounding_mask(l=p.x, r=25, spin=45, orient=RIGHT); +// } +// } +module rounding_mask(l=undef, r=1.0, anchor=CENTER, spin=0, orient=UP, h=undef) { l = first_defined([l, h, 1]); sides = quantup(segs(r),4); - orient_and_anchor([2*r, 2*r, l], orient, anchor, chain=true) { + orient_and_anchor([2*r, 2*r, l], orient, anchor, spin=spin, chain=true) { linear_extrude(height=l+0.1, convexity=4, center=true) { difference() { square(2*r, center=true); @@ -400,17 +430,17 @@ module rounding_mask(l=undef, r=1.0, orient=ORIENT_Z, anchor=CENTER, h=undef) // Arguments: // l = Length of mask. // r = Radius of the rounding. -// anchor = Alignment of the mask. Use the constants from `constants.h`. Default: centered. +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` // Example: // difference() { // cube(size=100, center=false); // #rounding_mask_x(l=100, r=25, anchor=LEFT); // } -module rounding_mask_x(l=1.0, r=1.0, anchor=CENTER) +module rounding_mask_x(l=1.0, r=1.0, spin=0) { - orient_and_anchor([l, 2*r, 2*r], ORIENT_Z, anchor, chain=true) { - rounding_mask(l=l, r=r, orient=ORIENT_X, anchor=CENTER) - children(); + rounding_mask(l=l, r=r, spin=spin, orient=RIGHT) { + for (i=[0:1:$children-2]) children(i); + if ($children) children($children-1); } } @@ -426,17 +456,17 @@ module rounding_mask_x(l=1.0, r=1.0, anchor=CENTER) // Arguments: // l = Length of mask. // r = Radius of the rounding. -// anchor = Alignment of the mask. Use the constants from `constants.h`. Default: centered. +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` // Example: // difference() { // cube(size=100, center=false); // right(100) #rounding_mask_y(l=100, r=25, anchor=FRONT); // } -module rounding_mask_y(l=1.0, r=1.0, anchor=CENTER) +module rounding_mask_y(l=1.0, r=1.0, spin=0) { - orient_and_anchor([2*r, l, 2*r], ORIENT_Z, anchor, chain=true) { - rounding_mask(l=l, r=r, orient=ORIENT_Y, anchor=CENTER) - children(); + rounding_mask(l=l, r=r, spin=spin, orient=BACK) { + for (i=[0:1:$children-2]) children(i); + if ($children) children($children-1); } } @@ -452,13 +482,19 @@ module rounding_mask_y(l=1.0, r=1.0, anchor=CENTER) // Arguments: // l = Length of mask. // r = Radius of the rounding. -// anchor = Alignment of the mask. Use the constants from `constants.h`. Default: centered. +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` // Example: // difference() { // cube(size=100, center=false); // #rounding_mask_z(l=100, r=25, anchor=BOTTOM); // } -module rounding_mask_z(l=1.0, r=1.0, anchor=CENTER) rounding_mask(l=l, r=r, orient=ORIENT_Z, anchor=anchor) children(); +module rounding_mask_z(l=1.0, r=1.0, spin=0) +{ + rounding_mask(l=l, r=r, spin=spin, orient=UP) { + for (i=[0:1:$children-2]) children(i); + if ($children) children($children-1); + } +} // Module: rounding() @@ -510,19 +546,20 @@ module rounding(r=1, size=[1,1,1], edges=EDGES_ALL) // h = height of vertical mask. // r = radius of the rounding. // ang = angle that the planes meet at. -// orient = Orientation of the mask. Use the `ORIENT_` constants from `constants.h`. Default: `ORIENT_Z`. -// anchor = Alignment of the mask. Use the constants from `constants.h`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example: // difference() { // angle_pie_mask(ang=70, h=50, d=100); // #rounding_angled_edge_mask(h=51, r=20.0, ang=70, $fn=32); // } -module rounding_angled_edge_mask(h=1.0, r=1.0, ang=90, orient=ORIENT_Z, anchor=CENTER) +module rounding_angled_edge_mask(h=1.0, r=1.0, ang=90, anchor=CENTER, spin=spin, orient=UP) { sweep = 180-ang; n = ceil(segs(r)*sweep/360); x = r*sin(90-(ang/2))/sin(ang/2); - orient_and_anchor([2*x,2*r,h], orient, anchor, chain=true) { + orient_and_anchor([2*x,2*r,h], orient, anchor, spin=spin, chain=true) { linear_extrude(height=h, convexity=4, center=true) { polygon( points=concat( @@ -550,8 +587,9 @@ module rounding_angled_edge_mask(h=1.0, r=1.0, ang=90, orient=ORIENT_Z, anchor=C // Arguments: // r = Radius of the rounding. // ang = Angle between planes that you need to round the corner of. -// orient = Orientation of the mask. Use the `ORIENT_` constants from `constants.h`. Default: `ORIENT_Z`. -// anchor = Alignment of the mask. Use the constants from `constants.h`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example(Med): // ang=60; // difference() { @@ -562,12 +600,12 @@ module rounding_angled_edge_mask(h=1.0, r=1.0, ang=90, orient=ORIENT_Z, anchor=C // } // rounding_angled_edge_mask(h=51, r=20, ang=ang); // } -module rounding_angled_corner_mask(r=1.0, ang=90, orient=ORIENT_Z, anchor=CENTER) +module rounding_angled_corner_mask(r=1.0, ang=90, anchor=CENTER, spin=0, orient=UP) { dx = r / tan(ang/2); dx2 = dx / cos(ang/2) + 1; fn = quantup(segs(r), 4); - orient_and_anchor([2*dx2, 2*dx2, r*2], orient, anchor, chain=true) { + orient_and_anchor([2*dx2, 2*dx2, r*2], orient, anchor, spin=spin, chain=true) { difference() { down(r) cylinder(r=dx2, h=r+1, center=false); yflip_copy() { @@ -596,7 +634,9 @@ module rounding_angled_corner_mask(r=1.0, ang=90, orient=ORIENT_Z, anchor=CENTER // object should align exactly with the corner to be rounded. // Arguments: // r = Radius of corner rounding. -// anchor = Alignment of the mask. Use the constants from `constants.h`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example: // rounding_corner_mask(r=20.0); // Example: @@ -607,9 +647,9 @@ module rounding_angled_corner_mask(r=1.0, ang=90, orient=ORIENT_Z, anchor=CENTER // translate([15, 25, 0]) rounding_mask_z(l=81, r=15); // translate([15, 25, 40]) #rounding_corner_mask(r=15); // } -module rounding_corner_mask(r=1.0, anchor=CENTER) +module rounding_corner_mask(r=1.0, anchor=CENTER, spin=0, orient=UP) { - orient_and_anchor([2*r, 2*r, 2*r], ORIENT_Z, anchor, chain=true) { + orient_and_anchor([2*r, 2*r, 2*r], orient, anchor, spin=spin, chain=true) { difference() { cube(size=r*2, center=true); grid3d(n=[2,2,2], spacing=r*2-0.05) { @@ -662,8 +702,9 @@ module rounding_cylinder_mask(r=1.0, rounding=0.25) // d = Diameter of hole to rounding. // rounding = Radius of the rounding. (Default: 0.25) // overage = The extra thickness of the mask. Default: `0.1`. -// orient = Orientation of the mask. Use the `ORIENT_` constants from `constants.h`. Default: `ORIENT_Z`. -// anchor = Alignment of the mask. Use the constants from `constants.h`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example(Med): // difference() { // cube([150,150,100], center=true); @@ -678,10 +719,10 @@ module rounding_cylinder_mask(r=1.0, rounding=0.25) // } // Example: // rounding_hole_mask(r=40, rounding=20, $fa=2, $fs=2); -module rounding_hole_mask(r=undef, d=undef, rounding=0.25, overage=0.1, orient=ORIENT_Z, anchor=CENTER) +module rounding_hole_mask(r=undef, d=undef, rounding=0.25, overage=0.1, anchor=CENTER, spin, orient=UP) { r = get_radius(r=r, d=d, dflt=1); - orient_and_anchor([2*(r+rounding), 2*(r+rounding), rounding*2], orient, anchor, chain=true) { + orient_and_anchor([2*(r+rounding), 2*(r+rounding), rounding*2], orient, anchor, spin=spin, chain=true) { rotate_extrude(convexity=4) { difference() { right(r-overage) fwd(rounding) square(rounding+overage, center=false); diff --git a/metric_screws.scad b/metric_screws.scad index f4d007d..9856793 100644 --- a/metric_screws.scad +++ b/metric_screws.scad @@ -363,17 +363,20 @@ function get_metric_nut_thickness(size) = lookup(size, [ // Description: // Makes a very simple screw model, useful for making screwholes. // Usage: -// screw(screwsize, screwlen, headsize, headlen, [countersunk], [orient], [anchor]) +// screw(screwsize, screwlen, headsize, headlen, [orient], [anchor]) // Arguments: // screwsize = diameter of threaded part of screw. // screwlen = length of threaded part of screw. // headsize = diameter of the screw head. // headlen = length of the screw head. -// countersunk = If true, center from cap's top instead of it's bottom. -// orient = Orientation of the screw. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the screw. Use the constants from `constants.scad` or `"sunken"`, or `"base"`. Default: `"base"`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` +// Extra Anchors: +// "base" = At the base of the head. +// "countersunk" = At the head height that would be just barely exposed when countersunk. // Examples: -// screw(screwsize=3,screwlen=10,headsize=6,headlen=3,countersunk=true); +// screw(screwsize=3,screwlen=10,headsize=6,headlen=3, anchor="countersunk"); // screw(screwsize=3,screwlen=10,headsize=6,headlen=3, anchor="base"); // Example(FlatSpin): Standard Anchors // screw(screwsize=3,screwlen=10,headsize=6,headlen=3) @@ -388,17 +391,16 @@ module screw( headsize=6, headlen=3, pitch=undef, - countersunk=false, - orient=ORIENT_Z, - anchor="base" + anchor="base", + spin=0, + orient=UP ) { sides = max(12, segs(screwsize/2)); - algn = countersunk? TOP : anchor; anchors = [ - anchorpt("base", [0,0,-headlen/2+screwlen/2]), - anchorpt("sunken", [0,0,(headlen+screwlen)/2-0.01]) + anchorpt("countersunk", [0,0,(headlen+screwlen)/2-0.01]), + anchorpt("base", [0,0,-headlen/2+screwlen/2]) ]; - orient_and_anchor([screwsize, screwsize, headlen+screwlen], orient, algn, anchors=anchors, geometry="cylinder", chain=true) { + orient_and_anchor([screwsize, screwsize, headlen+screwlen], orient, anchor, spin=spin, anchors=anchors, geometry="cylinder", chain=true) { down(headlen/2-screwlen/2) { down(screwlen/2) { if (pitch == undef) { @@ -428,8 +430,13 @@ module screw( // flange = Radius of flange beyond the head. Default = 0 (no flange) // phillips = If given, the size of the phillips drive hole to add. (ie: "#1", "#2", or "#3") // torx = If given, the size of the torx drive hole to add. (ie: 10, 20, 30, etc.) -// orient = Orientation of the bolt. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the bolt. Use the constants from `constants.scad` or `"sunken"`, `"base"`, or `"shank"`. Default: `"base"`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` +// Extra Anchors: +// "base" = At the base of the head. +// "countersunk" = At the head height that would be just barely exposed when countersunk. +// "shank" = At the bottom start of the unthreaded shank. // Example: Bolt Head Types // ydistribute(40) { // xdistribute(30) { @@ -480,8 +487,9 @@ module metric_bolt( phillips=undef, torx=undef, flange=0, - orient=ORIENT_Z, - anchor="base" + anchor="base", + spin=0, + orient=UP ) { D = headtype != "hex"? get_metric_socket_cap_diam(size) : @@ -498,7 +506,6 @@ module metric_bolt( bevtop = (tcirc-D)/2; bevbot = P/2; - //algn = (headtype == "countersunk" || headtype == "oval")? (D-size)/2 : 0; headlen = ( (headtype == "pan" || headtype == "round" || headtype == "button")? H*0.75 : (headtype == "countersunk")? (D-size)/2 : @@ -512,13 +519,13 @@ module metric_bolt( ); anchors = [ - anchorpt("sunken", [0,0,base+sunklen]), + anchorpt("countersunk", [0,0,base+sunklen]), anchorpt("base", [0,0,base]), anchorpt("shank", [0,0,base-shank]) ]; //color("silver") - orient_and_anchor([size, size, headlen+l], orient, anchor, geometry="cylinder", anchors=anchors, chain=true) { + orient_and_anchor([size, size, headlen+l], orient, anchor, spin=spin, geometry="cylinder", anchors=anchors, chain=true) { up(base) { difference() { union() { @@ -626,8 +633,9 @@ module metric_bolt( // pitch = pitch of threads in the hole. No threads if not given. // flange = radius of flange beyond the head. Default = 0 (no flange) // details = true if model should be rendered with extra details. (Default: false) -// orient = Orientation of the nut. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the nut. Use the constants from `constants.scad`. Default: `UP`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // center = If true, centers the nut at the origin. If false, sits on top of XY plane. Overrides `anchor` if given. // Example: No details, No Hole. Useful for a mask. // metric_nut(size=10, hole=false); @@ -648,8 +656,9 @@ module metric_nut( details=false, flange=0, center=undef, - orient=ORIENT_Z, - anchor=UP + anchor=CENTER, + spin=0, + orient=UP ) { H = get_metric_nut_thickness(size); D = get_metric_nut_size(size); @@ -659,7 +668,7 @@ module metric_nut( bevtop = (dcirc - D)/2; //color("silver") - orient_and_anchor([dcirc+flange, dcirc+flange, H], orient, anchor, center, geometry="cylinder", chain=true) { + orient_and_anchor([dcirc+flange, dcirc+flange, H], orient, anchor, spin=spin, center=center, geometry="cylinder", chain=true) { difference() { union() { difference() { diff --git a/nema_steppers.scad b/nema_steppers.scad index 4273d5b..b4ffaf8 100644 --- a/nema_steppers.scad +++ b/nema_steppers.scad @@ -99,8 +99,9 @@ function nema_motor_screw_depth(size) = lookup(size, [ // h = Length of motor body. Default: 24mm // shaft = Shaft diameter. Default: 5mm // shaft_len = Length of shaft protruding out the top of the stepper motor. Default: 20mm -// orient = Orientation of the stepper. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the stepper. Use the constants from `constants.scad`. Default: `TOP`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Extra Anchors: // "shaft-top" = The top of the shaft. // "shaft-middle" = The middle of the shaft. @@ -112,7 +113,7 @@ function nema_motor_screw_depth(size) = lookup(size, [ // "screw4" = The screw-hole in the X+Y- quadrant. // Example: // nema11_stepper(); -module nema11_stepper(h=24, shaft=5, shaft_len=20, orient=ORIENT_Z, anchor=TOP) +module nema11_stepper(h=24, shaft=5, shaft_len=20, anchor=TOP, spin=0, orient=UP) { size = 11; motor_width = nema_motor_width(size); @@ -132,7 +133,8 @@ module nema11_stepper(h=24, shaft=5, shaft_len=20, orient=ORIENT_Z, anchor=TOP) anchorpt("screw3", [-screw_spacing/2, -screw_spacing/2, h/2]), anchorpt("screw4", [+screw_spacing/2, -screw_spacing/2, h/2]), ]; - orient_and_anchor([motor_width, motor_width, h], orient, anchor, anchors=anchors, orig_anchor=TOP, chain=true) { + orient_and_anchor([motor_width, motor_width, h], orient, anchor, spin=spin, anchors=anchors, chain=true) { + up(h/2) union() { difference() { color([0.4, 0.4, 0.4]) @@ -162,8 +164,9 @@ module nema11_stepper(h=24, shaft=5, shaft_len=20, orient=ORIENT_Z, anchor=TOP) // h = Length of motor body. Default: 24mm // shaft = Shaft diameter. Default: 5mm // shaft_len = Length of shaft protruding out the top of the stepper motor. Default: 24mm -// orient = Orientation of the stepper. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the stepper. Use the constants from `constants.scad`. Default: `TOP`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Extra Anchors: // "shaft-top" = The top of the shaft. // "shaft-middle" = The middle of the shaft. @@ -175,7 +178,7 @@ module nema11_stepper(h=24, shaft=5, shaft_len=20, orient=ORIENT_Z, anchor=TOP) // "screw4" = The screw-hole in the X+Y- quadrant. // Example: // nema14_stepper(); -module nema14_stepper(h=24, shaft=5, shaft_len=24, orient=ORIENT_Z, anchor=TOP) +module nema14_stepper(h=24, shaft=5, shaft_len=24, anchor=TOP, spin=0, orient=UP) { size = 14; motor_width = nema_motor_width(size); @@ -195,7 +198,8 @@ module nema14_stepper(h=24, shaft=5, shaft_len=24, orient=ORIENT_Z, anchor=TOP) anchorpt("screw3", [-screw_spacing/2, -screw_spacing/2, h/2]), anchorpt("screw4", [+screw_spacing/2, -screw_spacing/2, h/2]), ]; - orient_and_anchor([motor_width, motor_width, h], orient, anchor, anchors=anchors, orig_anchor=TOP, chain=true) { + orient_and_anchor([motor_width, motor_width, h], orient, anchor, spin=spin, anchors=anchors, chain=true) { + up(h/2) union() { difference() { color([0.4, 0.4, 0.4]) @@ -225,8 +229,9 @@ module nema14_stepper(h=24, shaft=5, shaft_len=24, orient=ORIENT_Z, anchor=TOP) // h = Length of motor body. Default: 34mm // shaft = Shaft diameter. Default: 5mm // shaft_len = Length of shaft protruding out the top of the stepper motor. Default: 20mm -// orient = Orientation of the stepper. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the stepper. Use the constants from `constants.scad`. Default: `TOP`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Extra Anchors: // "shaft-top" = The top of the shaft. // "shaft-middle" = The middle of the shaft. @@ -238,7 +243,7 @@ module nema14_stepper(h=24, shaft=5, shaft_len=24, orient=ORIENT_Z, anchor=TOP) // "screw4" = The screw-hole in the X+Y- quadrant. // Example: // nema17_stepper(); -module nema17_stepper(h=34, shaft=5, shaft_len=20, orient=ORIENT_Z, anchor=TOP) +module nema17_stepper(h=34, shaft=5, shaft_len=20, anchor=TOP, spin=0, orient=UP) { size = 17; motor_width = nema_motor_width(size); @@ -258,7 +263,8 @@ module nema17_stepper(h=34, shaft=5, shaft_len=20, orient=ORIENT_Z, anchor=TOP) anchorpt("screw3", [-screw_spacing/2, -screw_spacing/2, h/2]), anchorpt("screw4", [+screw_spacing/2, -screw_spacing/2, h/2]), ]; - orient_and_anchor([motor_width, motor_width, h], orient, anchor, anchors=anchors, orig_anchor=UP, chain=true) { + orient_and_anchor([motor_width, motor_width, h], orient, anchor, spin=spin, anchors=anchors, chain=true) { + up(h/2) union() { difference() { color([0.4, 0.4, 0.4]) @@ -279,7 +285,7 @@ module nema17_stepper(h=34, shaft=5, shaft_len=20, orient=ORIENT_Z, anchor=TOP) fwd(motor_width/2+motor_width/24/2-0.1) { difference() { cube(size=[motor_width/8, motor_width/24, motor_width/8], center=true); - cyl(d=motor_width/8-2, h=motor_width/6, orient=ORIENT_Y, $fn=12); + cyl(d=motor_width/8-2, h=motor_width/6, orient=BACK, $fn=12); } } } @@ -307,8 +313,9 @@ module nema17_stepper(h=34, shaft=5, shaft_len=20, orient=ORIENT_Z, anchor=TOP) // h = Length of motor body. Default: 50mm // shaft = Shaft diameter. Default: 6.35mm // shaft_len = Length of shaft protruding out the top of the stepper motor. Default: 25mm -// orient = Orientation of the stepper. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the stepper. Use the constants from `constants.scad`. Default: `TOP`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Extra Anchors: // "shaft-top" = The top of the shaft. // "shaft-middle" = The middle of the shaft. @@ -320,7 +327,7 @@ module nema17_stepper(h=34, shaft=5, shaft_len=20, orient=ORIENT_Z, anchor=TOP) // "screw4" = The screw-hole in the X+Y- quadrant. // Example: // nema23_stepper(); -module nema23_stepper(h=50, shaft=6.35, shaft_len=25, orient=ORIENT_Z, anchor=TOP) +module nema23_stepper(h=50, shaft=6.35, shaft_len=25, anchor=TOP, spin=0, orient=UP) { size = 23; motor_width = nema_motor_width(size); @@ -341,7 +348,8 @@ module nema23_stepper(h=50, shaft=6.35, shaft_len=25, orient=ORIENT_Z, anchor=TO anchorpt("screw3", [-screw_spacing/2, -screw_spacing/2, h/2]), anchorpt("screw4", [+screw_spacing/2, -screw_spacing/2, h/2]), ]; - orient_and_anchor([motor_width, motor_width, h], orient, anchor, anchors=anchors, orig_anchor=TOP, chain=true) { + orient_and_anchor([motor_width, motor_width, h], orient, anchor, spin=spin, anchors=anchors, chain=true) { + up(h/2) difference() { union() { color([0.4, 0.4, 0.4]) @@ -372,8 +380,9 @@ module nema23_stepper(h=50, shaft=6.35, shaft_len=25, orient=ORIENT_Z, anchor=TO // h = Length of motor body. Default: 75mm // shaft = Shaft diameter. Default: 12.7mm // shaft_len = Length of shaft protruding out the top of the stepper motor. Default: 32mm -// orient = Orientation of the stepper. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the stepper. Use the constants from `constants.scad`. Default: `TOP`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Extra Anchors: // "shaft-top" = The top of the shaft. // "shaft-middle" = The middle of the shaft. @@ -385,7 +394,7 @@ module nema23_stepper(h=50, shaft=6.35, shaft_len=25, orient=ORIENT_Z, anchor=TO // "screw4" = The screw-hole in the X+Y- quadrant. // Example: // nema34_stepper(); -module nema34_stepper(h=75, shaft=12.7, shaft_len=32, orient=ORIENT_Z, anchor=TOP) +module nema34_stepper(h=75, shaft=12.7, shaft_len=32, anchor=TOP, spin=0, orient=UP) { size = 34; motor_width = nema_motor_width(size); @@ -406,7 +415,8 @@ module nema34_stepper(h=75, shaft=12.7, shaft_len=32, orient=ORIENT_Z, anchor=TO anchorpt("screw3", [-screw_spacing/2, -screw_spacing/2, h/2]), anchorpt("screw4", [+screw_spacing/2, -screw_spacing/2, h/2]), ]; - orient_and_anchor([motor_width, motor_width, h], orient, anchor, anchors=anchors, orig_anchor=TOP, chain=true) { + orient_and_anchor([motor_width, motor_width, h], orient, anchor, spin=spin, anchors=anchors, chain=true) { + up(h/2) difference() { union() { color([0.4, 0.4, 0.4]) @@ -442,8 +452,9 @@ module nema34_stepper(h=75, shaft=12.7, shaft_len=32, orient=ORIENT_Z, anchor=TO // depth = The thickness of the mounting hole mask. Default: 5 // l = The length of the slots, for making an adjustable motor mount. Default: 5 // slop = The printer-specific slop value to make parts fit just right. Default: `PRINTER_SLOP` -// orient = Orientation of the stepper. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the stepper. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Extra Anchors: // "screw1" = The center top of the screw hole/slot in the X+Y+ quadrant. // "screw2" = The center top of the screw hole/slot in the X-Y+ quadrant. @@ -455,7 +466,7 @@ module nema34_stepper(h=75, shaft=12.7, shaft_len=32, orient=ORIENT_Z, anchor=TO // nema_mount_holes(size=17, depth=5, l=5); // Example: // nema_mount_holes(size=17, depth=5, l=0); -module nema_mount_holes(size=17, depth=5, l=5, slop=PRINTER_SLOP, orient=ORIENT_Z, anchor=CENTER) +module nema_mount_holes(size=17, depth=5, l=5, slop=PRINTER_SLOP, anchor=CENTER, spin=spin, orient=UP) { motor_width = nema_motor_width(size); plinth_diam = nema_motor_plinth_diam(size)+slop; @@ -470,7 +481,7 @@ module nema_mount_holes(size=17, depth=5, l=5, slop=PRINTER_SLOP, orient=ORIENT_ ]; screwfn = quantup(max(8,segs(screw_size/2)),4); plinthfn = quantup(max(8,segs(plinth_diam/2)),4); - orient_and_anchor([screw_spacing+screw_size, screw_spacing+screw_size+l, depth], orient, anchor, chain=true) { + orient_and_anchor([screw_spacing+screw_size, screw_spacing+screw_size+l, depth], orient, anchor, spin=spin, chain=true) { union() { xspread(screw_spacing) { yspread(screw_spacing) { @@ -505,8 +516,9 @@ module nema_mount_holes(size=17, depth=5, l=5, slop=PRINTER_SLOP, orient=ORIENT_ // depth = The thickness of the mounting hole mask. Default: 5 // l = The length of the slots, for making an adjustable motor mount. Default: 5 // slop = The printer-specific slop value to make parts fit just right. Default: `PRINTER_SLOP` -// orient = Orientation of the stepper. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the stepper. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Extra Anchors: // "screw1" = The center top of the screw hole/slot in the X+Y+ quadrant. // "screw2" = The center top of the screw hole/slot in the X-Y+ quadrant. @@ -516,9 +528,9 @@ module nema_mount_holes(size=17, depth=5, l=5, slop=PRINTER_SLOP, orient=ORIENT_ // nema11_mount_holes(depth=5, l=5); // Example: // nema11_mount_holes(depth=5, l=0); -module nema11_mount_holes(depth=5, l=5, slop=PRINTER_SLOP, orient=ORIENT_Z, anchor=CENTER) +module nema11_mount_holes(depth=5, l=5, slop=PRINTER_SLOP, anchor=CENTER, spin=0, orient=UP) { - nema_mount_holes(size=11, depth=depth, l=l, slop=slop, orient=orient, anchor=anchor) children(); + nema_mount_holes(size=11, depth=depth, l=l, slop=slop, anchor=anchor, spin=spin, orient=orient) children(); } @@ -529,8 +541,9 @@ module nema11_mount_holes(depth=5, l=5, slop=PRINTER_SLOP, orient=ORIENT_Z, anch // depth = The thickness of the mounting hole mask. Default: 5 // l = The length of the slots, for making an adjustable motor mount. Default: 5 // slop = The printer-specific slop value to make parts fit just right. Default: `PRINTER_SLOP` -// orient = Orientation of the stepper. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the stepper. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Extra Anchors: // "screw1" = The center top of the screw hole/slot in the X+Y+ quadrant. // "screw2" = The center top of the screw hole/slot in the X-Y+ quadrant. @@ -540,9 +553,9 @@ module nema11_mount_holes(depth=5, l=5, slop=PRINTER_SLOP, orient=ORIENT_Z, anch // nema14_mount_holes(depth=5, l=5); // Example: // nema14_mount_holes(depth=5, l=0); -module nema14_mount_holes(depth=5, l=5, slop=PRINTER_SLOP, orient=ORIENT_Z, anchor=CENTER) +module nema14_mount_holes(depth=5, l=5, slop=PRINTER_SLOP, anchor=CENTER, spin=0, orient=UP) { - nema_mount_holes(size=14, depth=depth, l=l, slop=slop, orient=orient, anchor=anchor) children(); + nema_mount_holes(size=14, depth=depth, l=l, slop=slop, anchor=anchor, spin=spin, orient=orient) children(); } @@ -553,8 +566,9 @@ module nema14_mount_holes(depth=5, l=5, slop=PRINTER_SLOP, orient=ORIENT_Z, anch // depth = The thickness of the mounting hole mask. Default: 5 // l = The length of the slots, for making an adjustable motor mount. Default: 5 // slop = The printer-specific slop value to make parts fit just right. Default: `PRINTER_SLOP` -// orient = Orientation of the stepper. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the stepper. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Extra Anchors: // "screw1" = The center top of the screw hole/slot in the X+Y+ quadrant. // "screw2" = The center top of the screw hole/slot in the X-Y+ quadrant. @@ -564,9 +578,9 @@ module nema14_mount_holes(depth=5, l=5, slop=PRINTER_SLOP, orient=ORIENT_Z, anch // nema17_mount_holes(depth=5, l=5); // Example: // nema17_mount_holes(depth=5, l=0); -module nema17_mount_holes(depth=5, l=5, slop=PRINTER_SLOP, orient=ORIENT_Z, anchor=CENTER) +module nema17_mount_holes(depth=5, l=5, slop=PRINTER_SLOP, anchor=CENTER, spin=0, orient=UP) { - nema_mount_holes(size=17, depth=depth, l=l, slop=slop, orient=orient, anchor=anchor) children(); + nema_mount_holes(size=17, depth=depth, l=l, slop=slop, anchor=anchor, spin=spin, orient=orient) children(); } @@ -577,8 +591,9 @@ module nema17_mount_holes(depth=5, l=5, slop=PRINTER_SLOP, orient=ORIENT_Z, anch // depth = The thickness of the mounting hole mask. Default: 5 // l = The length of the slots, for making an adjustable motor mount. Default: 5 // slop = The printer-specific slop value to make parts fit just right. Default: `PRINTER_SLOP` -// orient = Orientation of the stepper. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the stepper. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Extra Anchors: // "screw1" = The center top of the screw hole/slot in the X+Y+ quadrant. // "screw2" = The center top of the screw hole/slot in the X-Y+ quadrant. @@ -588,9 +603,9 @@ module nema17_mount_holes(depth=5, l=5, slop=PRINTER_SLOP, orient=ORIENT_Z, anch // nema23_mount_holes(depth=5, l=5); // Example: // nema23_mount_holes(depth=5, l=0); -module nema23_mount_holes(depth=5, l=5, slop=PRINTER_SLOP, orient=ORIENT_Z, anchor=CENTER) +module nema23_mount_holes(depth=5, l=5, slop=PRINTER_SLOP, anchor=CENTER, spin=0, orient=UP) { - nema_mount_holes(size=23, depth=depth, l=l, slop=slop, orient=orient, anchor=anchor) children(); + nema_mount_holes(size=23, depth=depth, l=l, slop=slop, anchor=anchor, spin=spin, orient=orient) children(); } @@ -601,8 +616,9 @@ module nema23_mount_holes(depth=5, l=5, slop=PRINTER_SLOP, orient=ORIENT_Z, anch // depth = The thickness of the mounting hole mask. Default: 5 // l = The length of the slots, for making an adjustable motor mount. Default: 5 // slop = The printer-specific slop value to make parts fit just right. Default: `PRINTER_SLOP` -// orient = Orientation of the stepper. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the stepper. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Extra Anchors: // "screw1" = The center top of the screw hole/slot in the X+Y+ quadrant. // "screw2" = The center top of the screw hole/slot in the X-Y+ quadrant. @@ -612,33 +628,9 @@ module nema23_mount_holes(depth=5, l=5, slop=PRINTER_SLOP, orient=ORIENT_Z, anch // nema34_mount_holes(depth=5, l=5); // Example: // nema34_mount_holes(depth=5, l=0); -module nema34_mount_holes(depth=5, l=5, slop=PRINTER_SLOP, orient=ORIENT_Z, anchor=CENTER) +module nema34_mount_holes(depth=5, l=5, slop=PRINTER_SLOP, anchor=CENTER, spin=0, orient=UP) { - nema_mount_holes(size=34, depth=depth, l=l, slop=slop, orient=orient, anchor=anchor) children(); -} - - - -// Module: nema34_mount_holes() -// Description: Creates a mask to use when making NEMA 34 stepper motor mounts. -// Arguments: -// depth = The thickness of the mounting hole mask. Default: 5 -// l = The length of the slots, for making an adjustable motor mount. Default: 5 -// slop = The printer-specific slop value to make parts fit just right. Default: `PRINTER_SLOP` -// orient = Orientation of the stepper. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the stepper. Use the constants from `constants.scad`. Default: `CENTER`. -// Extra Anchors: -// "screw1" = The center top of the screw hole/slot in the X+Y+ quadrant. -// "screw2" = The center top of the screw hole/slot in the X-Y+ quadrant. -// "screw3" = The center top of the screw hole/slot in the X-Y- quadrant. -// "screw4" = The center top of the screw hole/slot in the X+Y- quadrant. -// Example: -// nema34_mount_holes(depth=5, l=5); -// Example: -// nema34_mount_holes(depth=5, l=0); -module nema34_mount_holes(depth=5, l=5, slop=PRINTER_SLOP, orient=ORIENT_Z, anchor=CENTER) -{ - nema_mount_holes(size=34, depth=depth, l=l, slop=slop, orient=orient, anchor=anchor) children(); + nema_mount_holes(size=34, depth=depth, l=l, slop=slop, anchor=anchor, spin=spin, orient=orient) children(); } diff --git a/paths.scad b/paths.scad index 189531f..a58a7a2 100644 --- a/paths.scad +++ b/paths.scad @@ -199,21 +199,25 @@ module extrude_from_to(pt1, pt2, convexity=undef, twist=undef, scale=undef, slic // height = height of extrusion. // twist = degrees of twist, from bottom to top. // slices = how many slices to use when making extrusion. -// orient = Orientation of the spiral. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the spiral. Use the constants from `constants.scad`. Default: `BOTTOM`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // center = If given, overrides `anchor`. A true value sets `anchor=CENTER`, false sets `anchor=BOTTOM`. // Example: // extrude_2d_hollow(wall=2, height=100, twist=90, slices=50) // circle(r=40, $fn=6); -module extrude_2d_hollow(wall=2, height=50, twist=90, slices=60, center=undef, orient=ORIENT_Z, anchor=BOTTOM) +module extrude_2d_hollow(wall=2, height=50, twist=90, slices=60, center=undef, anchor=BOTTOM, spin=0, orient=UP) { - linear_extrude(height=height, twist=twist, slices=slices, center=true) { - difference() { - children(); - offset(r=-wall) { + orient_and_anchor([0.01,0.01,height], orient, anchor, spin=spin, center=center, chain=true) { + linear_extrude(height=height, twist=twist, slices=slices, center=true) { + difference() { children(); + offset(r=-wall) { + children(); + } } } + children(); } } @@ -227,13 +231,14 @@ module extrude_2d_hollow(wall=2, height=50, twist=90, slices=60, center=undef, o // h = height of the spiral to extrude along. // r = radius of the spiral to extrude along. // twist = number of degrees of rotation to spiral up along height. -// orient = Orientation of the spiral. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the spiral. Use the constants from `constants.scad`. Default: `BOTTOM`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // center = If given, overrides `anchor`. A true value sets `anchor=CENTER`, false sets `anchor=BOTTOM`. // Example: // poly = [[-10,0], [-3,-5], [3,-5], [10,0], [0,-30]]; // extrude_2dpath_along_spiral(poly, h=200, r=50, twist=1080, $fn=36); -module extrude_2dpath_along_spiral(polyline, h, r, twist=360, center=undef, orient=ORIENT_Z, anchor=BOTTOM) { +module extrude_2dpath_along_spiral(polyline, h, r, twist=360, center=undef, anchor=BOTTOM, spin=0, orient=UP) { pline_count = len(polyline); steps = ceil(segs(r)*(twist/360)); @@ -275,7 +280,7 @@ module extrude_2dpath_along_spiral(polyline, h, r, twist=360, center=undef, orie ); tri_faces = triangulate_faces(poly_points, poly_faces); - orient_and_anchor([r,r,h], orient, anchor, center, chain=true) { + orient_and_anchor([r,r,h], orient, anchor, spin=spin, center=center, geometry="cylinder", chain=true) { polyhedron(points=poly_points, faces=tri_faces, convexity=10); children(); } diff --git a/phillips_drive.scad b/phillips_drive.scad index 21f220c..73e0111 100644 --- a/phillips_drive.scad +++ b/phillips_drive.scad @@ -18,13 +18,16 @@ // size = The size of the bit. "#1", "#2", or "#3" // shaft = The diameter of the drive bit's shaft. // l = The length of the drive bit. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example: // xdistribute(10) { // phillips_drive(size="#1", shaft=4, l=20); // phillips_drive(size="#2", shaft=6, l=20); // phillips_drive(size="#3", shaft=6, l=20); // } -module phillips_drive(size="#2", shaft=6, l=20, orient=ORIENT_Z, anchor=BOTTOM) { +module phillips_drive(size="#2", shaft=6, l=20, anchor=BOTTOM, spin=0, orient=UP) { // These are my best guess reverse-engineered measurements of // the tip diameters of various phillips screwdriver sizes. ang = 11; diff --git a/primitives.scad b/primitives.scad index 546e67d..34ee86c 100644 --- a/primitives.scad +++ b/primitives.scad @@ -20,18 +20,19 @@ // 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` +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` // Example(2D): // square(40); // Example(2D): Centered // square([40,30], center=true); // Example(2D): Anchoring // square([40,30], anchor=FRONT); -module square(size, center=undef, anchor=FRONT+LEFT) { +module square(size, center=undef, anchor=FRONT+LEFT, spin=0) { 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) { + orient_and_anchor(point3d(size), UP, anchor, spin=spin, center=center, noncentered=FRONT+LEFT, two_d=true, chain=true) { polygon(pts); children(); } @@ -46,18 +47,19 @@ module square(size, center=undef, anchor=FRONT+LEFT) { // 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` +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` // Example(2D): By Radius // circle(r=25); // Example(2D): By Diameter // circle(d=50); // Example(2D): Anchoring // circle(d=50, anchor=FRONT); -module circle(r=undef, d=undef, anchor=CENTER) { +module circle(r=undef, d=undef, anchor=CENTER, spin=0) { 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) { + orient_and_anchor([2*r,2*r,0], UP, anchor, spin=spin, geometry="cylinder", two_d=true, chain=true) { polygon(pts); children(); } @@ -76,19 +78,21 @@ module circle(r=undef, d=undef, anchor=CENTER) { // // Arguments: // size = The size of the cube. -// anchor = The side of the origin to anchor to. Use constants from `constants.scad`. Default: `ALLNEG` +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // center = If given, overrides `anchor`. A true value sets `anchor=CENTER`, false sets `anchor=ALLNEG`. // -// Example: Simple regular cube. +// Example: Simple cube. // cube(40); // Example: Rectangular cube. // cuboid([20,40,50]); // Example: Standard Connectors. // cube(40, center=true) show_anchors(); -module cube(size, center=undef, anchor=ALLNEG) +module cube(size, center=undef, anchor=ALLNEG, spin=0, orient=UP) { size = scalar_vec3(size); - orient_and_anchor(size, ORIENT_Z, anchor, center, noncentered=ALLNEG, chain=true) { + orient_and_anchor(size, orient, anchor, center, spin=spin, noncentered=ALLNEG, chain=true) { linear_extrude(height=size.z, convexity=2, center=true) { square([size.x, size.y], center=true); } @@ -112,8 +116,9 @@ module cube(size, center=undef, anchor=ALLNEG) // d = The diameter of the cylinder. // d1 = The bottom diameter of the cylinder. (Before orientation.) // d2 = The top diameter of the cylinder. (Before orientation.) -// orient = Orientation of the cylinder. Use the `ORIENT_` constants from `constants.scad`. Default: vertical. -// anchor = The side of the part to anchor to the origin. Use constants from `constants.scad`. Default: `UP` +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // center = If given, overrides `anchor`. A true value sets `anchor=CENTER`, false sets `anchor=BOTTOM`. // Example: By Radius // xdistribute(30) { @@ -130,14 +135,14 @@ module cube(size, center=undef, anchor=ALLNEG) // cylinder(h=30, d=25) show_anchors(); // cylinder(h=30, d1=25, d2=10) show_anchors(); // } -module cylinder(r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h=undef, l=undef, center=undef, orient=ORIENT_Z, anchor=BOTTOM) +module cylinder(r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h=undef, l=undef, center=undef, anchor=BOTTOM, spin=0, orient=UP) { r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=1); r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=1); l = first_defined([h, l]); sides = segs(max(r1,r2)); size = [r1*2, r1*2, l]; - orient_and_anchor(size, orient, anchor, center, size2=[r2*2,r2*2], noncentered=BOTTOM, geometry="cylinder", chain=true) { + orient_and_anchor(size, orient, anchor, center, spin=spin, size2=[r2*2,r2*2], noncentered=BOTTOM, geometry="cylinder", chain=true) { linear_extrude(height=l, scale=r2/r1, convexity=2, center=true) { circle(r=r1, $fn=sides); } @@ -156,20 +161,21 @@ module cylinder(r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h=unde // Arguments: // r = Radius of the sphere. // d = Diameter of the sphere. -// orient = Orientation of the sphere, if you don't like where the vertices lay. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the sphere. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example: By Radius // sphere(r=50); // Example: By Diameter // sphere(d=100); // Example: Standard Connectors // sphere(d=50) show_anchors(); -module sphere(r=undef, d=undef, orient=ORIENT_Z, anchor=CENTER) +module sphere(r=undef, d=undef, anchor=CENTER, spin=0, orient=UP) { r = get_radius(r=r, d=d, dflt=1); sides = segs(r); size = [r*2, r*2, r*2]; - orient_and_anchor(size, orient, anchor, geometry="sphere", chain=true) { + orient_and_anchor(size, orient, anchor, spin=spin, geometry="sphere", chain=true) { rotate_extrude(convexity=2) { difference() { circle(r=r, $fn=sides); diff --git a/scripts/docs_gen.py b/scripts/docs_gen.py index 758399a..d8be438 100755 --- a/scripts/docs_gen.py +++ b/scripts/docs_gen.py @@ -96,6 +96,7 @@ class ImageProcessing(object): def gen_example_image(self, libfile, imgfile, code, extype): OPENSCAD = "/Applications/OpenSCAD.app/Contents/MacOS/OpenSCAD" + GIT = "/usr/local/bin/git" CONVERT = "/usr/local/bin/convert" COMPARE = "/usr/local/bin/compare" @@ -208,6 +209,7 @@ class ImageProcessing(object): os.unlink(scriptfile) targimgfile = self.imgroot + imgfile newimgfile = self.imgroot + "_new_" + imgfile + if len(tmpimgs) == 1: cnvcmd = [CONVERT, tmpimgfile, "-resize", imgsizes[1], newimgfile] res = subprocess.call(cnvcmd) @@ -234,6 +236,11 @@ class ImageProcessing(object): for tmpimg in tmpimgs: os.unlink(tmpimg) + # Pull previous committed image from git, if it exists. + gitcmd = [GIT, "checkout", targimgfile] + p = subprocess.Popen(gitcmd, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True) + err = p.stdout.read() + # Time to compare image. if not os.path.isfile(targimgfile): print(" NEW IMAGE\n") @@ -428,28 +435,30 @@ class LeafNode(object): extitle = "**Example {0}**:".format(exnum) if title: extitle += " " + mkdn_esc(title) - out.append(extitle) - out.append("") - for line in excode: - out.append(" " + line) - out.append("") san_name = re.sub(r"[^A-Za-z0-9_]", "", self.name) imgfile = "{}{}.{}".format( san_name, ("_%d" % exnum) if exnum > 1 else "", "gif" if "Spin" in extype else "png" ) - if extype != "NORENDER": - out.append( - "![{0} Example{1}]({2}{3})".format( - mkdn_esc(self.name), - (" %d" % exnum) if len(self.examples) > 1 else "", - imgroot, - imgfile - ) - ) - out.append("") + if "NORENDER" not in extype: imgprc.add_image(fileroot+".scad", imgfile, excode, extype) + if "Hide" not in extype: + out.append(extitle) + out.append("") + for line in excode: + out.append(" " + line) + out.append("") + if "NORENDER" not in extype: + out.append( + "![{0} Example{1}]({2}{3})".format( + mkdn_esc(self.name), + (" %d" % exnum) if len(self.examples) > 1 else "", + imgroot, + imgfile + ) + ) + out.append("") out.append("---") out.append("") return out diff --git a/scripts/make_all_docs.sh b/scripts/make_all_docs.sh index 887f8e9..20bd7fc 100755 --- a/scripts/make_all_docs.sh +++ b/scripts/make_all_docs.sh @@ -18,7 +18,7 @@ rm -f tmpscad*.scad for lib in $PREVIEW_LIBS; do lib="$(basename $lib .scad)" mkdir -p images/$lib - # rm -f images/$lib/*.png images/$lib/*.gif + rm -f images/$lib/*.png images/$lib/*.gif # echo ../scripts/docs_gen.py ../$lib.scad -o $lib.scad.md -c -i -I images/$lib/ echo "$lib.scad" ../scripts/docs_gen.py ../$lib.scad -o $lib.scad.md -c -i -I images/$lib/ || exit 1 diff --git a/shapes.scad b/shapes.scad index 76d3a4c..9413644 100644 --- a/shapes.scad +++ b/shapes.scad @@ -24,8 +24,9 @@ // trimcorners = If true, rounds or chamfers corners where three chamferred/rounded edges meet. Default: `true` // p1 = Align the cuboid's corner at `p1`, if given. Forces `anchor=ALLNEG`. // p2 = If given with `p1`, defines the cornerpoints of the cuboid. -// anchor = The side of the part to anchor to. Use constants from `constants.scad`. Default: `CENTER` -// center = If given, overrides `anchor`. A true value sets `anchor=CENTER`, false sets `anchor=ALLNEG`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards. See [orient](attachments#orient). Default: `UP` // // Example: Simple regular cube. // cuboid(40); @@ -57,7 +58,8 @@ module cuboid( edges=EDGES_ALL, trimcorners=true, anchor=CENTER, - center=undef + spin=0, + orient=UP ) { size = scalar_vec3(size); if (!is_undef(p1)) { @@ -74,7 +76,7 @@ module cuboid( if (chamfer != undef) assert(chamfer <= min(size)/2, "chamfer must be smaller than half the cube width, length, or height."); if (rounding != undef) assert(rounding <= min(size)/2, "rounding radius must be smaller than half the cube width, length, or height."); majrots = [[0,90,0], [90,0,0], [0,0,0]]; - orient_and_anchor(size, ORIENT_Z, anchor, center=center, noncentered=ALLPOS, chain=true) { + orient_and_anchor(size, orient, anchor, spin=spin, chain=true) { if (chamfer != undef) { isize = [for (v = size) max(0.001, v-2*chamfer)]; if (edges == EDGES_ALL && trimcorners) { @@ -183,16 +185,16 @@ module cuboid( // Creates a rectangular prismoid shape. // // Usage: -// prismoid(size1, size2, h, [shift], [orient], [anchor|center]); +// prismoid(size1, size2, h, [shift], [anchor], [spin], [orient]); // // Arguments: // size1 = [width, length] of the axis-negative end of the prism. // size2 = [width, length] of the axis-positive end of the prism. // h = Height of the prism. // shift = [x, y] amount to shift the center of the top with respect to the center of the bottom. -// orient = Orientation of the prismoid. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the prismoid by the axis-negative (size1) end. Use the constants from `constants.scad`. Default: `BOTTOM`. -// center = If given, overrides `anchor`. A true value sets `anchor=CENTER`, false sets `anchor=BOTTOM`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // // Example: Rectangular Pyramid // prismoid(size1=[40,40], size2=[0,0], h=20); @@ -214,13 +216,13 @@ module cuboid( // prismoid(size1=[50,30], size2=[20,20], h=20, shift=[15,5]) show_anchors(); module prismoid( size1=[1,1], size2=[1,1], h=1, shift=[0,0], - orient=ORIENT_Z, anchor=DOWN, center=undef + anchor=DOWN, spin=0, orient=UP ) { eps = 0.001; shiftby = point3d(point2d(shift)); s1 = [max(size1.x, eps), max(size1.y, eps)]; s2 = [max(size2.x, eps), max(size2.y, eps)]; - orient_and_anchor([s1.x,s1.y,h], orient, anchor, center, size2=s2, shift=shift, noncentered=DOWN, chain=true) { + orient_and_anchor([s1.x,s1.y,h], orient, anchor, spin=spin, size2=s2, shift=shift, chain=true) { polyhedron( points=[ [+s2.x/2, +s2.y/2, +h/2] + shiftby, @@ -266,14 +268,12 @@ module prismoid( // r1 = radius of vertical edge rounding at bottom. // r2 = radius of vertical edge rounding at top. // shift = [x, y] amount to shift the center of the top with respect to the center of the bottom. -// orient = Orientation of the prismoid. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the prismoid by the axis-negative (`size1`) end. Use the constants from `constants.scad`. Default: `BOTTOM`. -// center = vertically center the prism. Overrides `anchor`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // // Example: Rounded Pyramid // rounded_prismoid(size1=[40,40], size2=[0,0], h=25, r=5); -// Example: Centered Rounded Pyramid -// rounded_prismoid(size1=[40,40], size2=[0,0], h=25, r=5, center=true); // Example: Disparate Top and Bottom Radii // rounded_prismoid(size1=[40,60], size2=[40,60], h=20, r1=3, r2=10, $fn=24); // Example(FlatSpin): Shifting/Skewing @@ -283,7 +283,7 @@ module prismoid( module rounded_prismoid( size1, size2, h, shift=[0,0], r=undef, r1=undef, r2=undef, - anchor=BOTTOM, orient=ORIENT_Z, center=undef + anchor=BOTTOM, spin=0, orient=UP ) { eps = 0.001; maxrad1 = min(size1.x/2, size1.y/2); @@ -291,7 +291,7 @@ module rounded_prismoid( rr1 = min(maxrad1, (r1!=undef)? r1 : r); rr2 = min(maxrad2, (r2!=undef)? r2 : r); shiftby = point3d(shift); - orient_and_anchor([size1.x, size1.y, h], orient, anchor, center, size2=size2, shift=shift, noncentered=UP, chain=true) { + orient_and_anchor([size1.x, size1.y, h], orient, anchor, spin=spin, size2=size2, shift=shift, noncentered=UP, chain=true) { down(h/2) { hull() { linear_extrude(height=eps, center=false, convexity=2) { @@ -326,9 +326,9 @@ module rounded_prismoid( // // Arguments: // size = [width, thickness, height] -// orient = The axis to place the hypotenuse along. Only accepts `ORIENT_X`, `ORIENT_Y`, or `ORIENT_Z` from `constants.scad`. Default: `ORIENT_Y`. -// anchor = The side of the origin to anchor to. Use constants from `constants.scad`. Default: `ALLNEG`. -// center = If given, overrides `anchor`. A true value sets `anchor=CENTER`, false sets `anchor=ALLNEG`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `ALLNEG` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // // Example: Centered // right_triangle([60, 10, 40], center=true); @@ -336,11 +336,11 @@ module rounded_prismoid( // right_triangle([60, 10, 40]); // Example: Standard Connectors // right_triangle([60, 15, 40]) show_anchors(); -module right_triangle(size=[1, 1, 1], orient=ORIENT_Y, anchor=ALLNEG, center=undef) +module right_triangle(size=[1, 1, 1], anchor=ALLNEG, spin=0, orient=UP, center=undef) { size = scalar_vec3(size); - orient_and_anchor(size, anchor=anchor, center=center, chain=true) { - if (orient == ORIENT_X) { + orient_and_anchor(size, orient, anchor, spin=spin, center=center, chain=true) { + if (orient == RIGHT) { ang = atan2(size.y, size.z); masksize = [size.x, size.y, norm([size.y,size.z])] + [1,1,1]; xrot(ang) { @@ -349,7 +349,7 @@ module right_triangle(size=[1, 1, 1], orient=ORIENT_Y, anchor=ALLNEG, center=und back(masksize.y/2) cube(masksize, center=true); } } - } else if (orient == ORIENT_Y) { + } else if (orient == BACK) { ang = atan2(size.x, size.z); masksize = [size.x, size.y, norm([size.x,size.z])] + [1,1,1]; yrot(-ang) { @@ -358,7 +358,7 @@ module right_triangle(size=[1, 1, 1], orient=ORIENT_Y, anchor=ALLNEG, center=und right(masksize.x/2) cube(masksize, center=true); } } - } else if (orient == ORIENT_Z) { + } else if (orient == UP) { ang = atan2(size.x, size.y); masksize = [norm([size.x,size.y]), size.y, size.z] + [1,1,1]; zrot(-ang) { @@ -423,8 +423,9 @@ module right_triangle(size=[1, 1, 1], orient=ORIENT_Y, anchor=ALLNEG, center=und // rounding1 = The radius of the rounding on the axis-negative end of the cylinder. // rounding2 = The radius of the rounding on the axis-positive end of the cylinder. // realign = If true, rotate the cylinder by half the angle of one face. -// orient = Orientation of the cylinder. Use the `ORIENT_` constants from `constants.scad`. Default: vertical. -// anchor = Alignment of the cylinder. Use the constants from `constants.scad`. Default: centered. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // center = If given, overrides `anchor`. A true value sets `anchor=CENTER`, false sets `anchor=DOWN`. // // Example: By Radius @@ -453,9 +454,9 @@ module right_triangle(size=[1, 1, 1], orient=ORIENT_Y, anchor=ALLNEG, center=und // Example: Heterogenous Chamfers and Rounding // ydistribute(80) { // // Shown Front to Back. -// cyl(l=40, d=40, rounding1=15, orient=ORIENT_X); -// cyl(l=40, d=40, chamfer2=5, orient=ORIENT_X); -// cyl(l=40, d=40, chamfer1=12, rounding2=10, orient=ORIENT_X); +// cyl(l=40, d=40, rounding1=15, orient=UP); +// cyl(l=40, d=40, chamfer2=5, orient=UP); +// cyl(l=40, d=40, chamfer1=12, rounding2=10, orient=UP); // } // // Example: Putting it all together @@ -475,7 +476,7 @@ module cyl( chamfang=undef, chamfang1=undef, chamfang2=undef, rounding=undef, rounding1=undef, rounding2=undef, circum=false, realign=false, from_end=false, - orient=ORIENT_Z, anchor=CENTER, center=undef + anchor=CENTER, spin=0, orient=UP, center=undef ) { r1 = get_radius(r1, r, d1, d, 1); r2 = get_radius(r2, r, d2, d, 1); @@ -485,7 +486,7 @@ module cyl( sides = segs(max(r1,r2)); sc = circum? 1/cos(180/sides) : 1; phi = atan2(l, r1-r2); - orient_and_anchor(size1, orient, anchor, center=center, size2=size2, geometry="cylinder", chain=true) { + orient_and_anchor(size1, orient, anchor, spin=spin, center=center, size2=size2, geometry="cylinder", chain=true) { zrot(realign? 180/sides : 0) { if (!any_defined([chamfer, chamfer1, chamfer2, rounding, rounding1, rounding2])) { cylinder(h=l, r1=r1*sc, r2=r2*sc, center=true, $fn=sides); @@ -618,8 +619,8 @@ module cyl( // Creates a cylinder oriented along the X axis. // // Usage: -// xcyl(l|h, r|d, [anchor|center]); -// xcyl(l|h, r1|d1, r2|d2, [anchor|center]); +// xcyl(l|h, r|d, [anchor]); +// xcyl(l|h, r1|d1, r2|d2, [anchor]); // // Arguments: // l / h = Length of cylinder along oriented axis. (Default: `1.0`) @@ -629,8 +630,7 @@ module cyl( // d = Optional diameter of cylinder. (use instead of `r`) // d1 = Optional diameter of left (X-) end of cylinder. // d2 = Optional diameter of right (X+) end of cylinder. -// anchor = The side of the origin to anchor to. Use constants from `constants.scad`. Default: `CENTER` -// center = If given, overrides `anchor`. A `true` value sets `anchor=CENTER`, `false` sets `anchor=BOTTOM`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` // // Example: By Radius // ydistribute(50) { @@ -643,9 +643,9 @@ module cyl( // xcyl(l=35, d=20); // xcyl(l=35, d1=30, d2=10); // } -module xcyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h=undef, anchor=CENTER, center=undef) +module xcyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h=undef, anchor=CENTER) { - cyl(l=l, h=h, r=r, r1=r1, r2=r2, d=d, d1=d1, d2=d2, orient=ORIENT_X, anchor=anchor, center=center) children(); + cyl(l=l, h=h, r=r, r1=r1, r2=r2, d=d, d1=d1, d2=d2, orient=RIGHT, anchor=anchor) children(); } @@ -656,8 +656,8 @@ module xcyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h // Creates a cylinder oriented along the Y axis. // // Usage: -// ycyl(l|h, r|d, [anchor|center]); -// ycyl(l|h, r1|d1, r2|d2, [anchor|center]); +// ycyl(l|h, r|d, [anchor]); +// ycyl(l|h, r1|d1, r2|d2, [anchor]); // // Arguments: // l / h = Length of cylinder along oriented axis. (Default: `1.0`) @@ -667,8 +667,7 @@ module xcyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h // d = Diameter of cylinder. // d1 = Diameter of front (Y-) end of one. // d2 = Diameter of back (Y+) end of one. -// anchor = The side of the origin to anchor to. Use constants from `constants.scad`. Default: `CENTER` -// center = Overrides `anchor` if given. If true, `anchor=CENTER`, if false, `anchor=UP`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` // // Example: By Radius // xdistribute(50) { @@ -681,9 +680,9 @@ module xcyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h // ycyl(l=35, d=20); // ycyl(l=35, d1=30, d2=10); // } -module ycyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h=undef, anchor=CENTER, center=undef) +module ycyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h=undef, anchor=CENTER) { - cyl(l=l, h=h, r=r, r1=r1, r2=r2, d=d, d1=d1, d2=d2, orient=ORIENT_Y, anchor=anchor, center=center) children(); + cyl(l=l, h=h, r=r, r1=r1, r2=r2, d=d, d1=d1, d2=d2, orient=BACK, anchor=anchor) children(); } @@ -694,8 +693,8 @@ module ycyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h // Creates a cylinder oriented along the Z axis. // // Usage: -// zcyl(l|h, r|d, [anchor|center]); -// zcyl(l|h, r1|d1, r2|d2, [anchor|center]); +// zcyl(l|h, r|d, [anchor]); +// zcyl(l|h, r1|d1, r2|d2, [anchor]); // // Arguments: // l / h = Length of cylinder along oriented axis. (Default: 1.0) @@ -705,8 +704,7 @@ module ycyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h // d = Diameter of cylinder. // d1 = Diameter of front (Y-) end of one. // d2 = Diameter of back (Y+) end of one. -// anchor = The side of the origin to anchor to. Use constants from `constants.scad`. Default: `CENTER` -// center = Overrides `anchor` if given. If true, `anchor=CENTER`, if false, `anchor=UP`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` // // Example: By Radius // xdistribute(50) { @@ -719,9 +717,9 @@ module ycyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h // zcyl(l=35, d=20); // zcyl(l=35, d1=30, d2=10); // } -module zcyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h=undef, anchor=CENTER, center=undef) +module zcyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h=undef, anchor=CENTER) { - cyl(l=l, h=h, r=r, r1=r1, r2=r2, d=d, d1=d1, d2=d2, orient=ORIENT_Z, anchor=anchor, center=center) children(); + cyl(l=l, h=h, r=r, r1=r1, r2=r2, d=d, d1=d1, d2=d2, orient=UP, anchor=anchor) children(); } @@ -755,8 +753,9 @@ module zcyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h // id1 = Inner diameter of bottom of tube. // id2 = Inner diameter of top of tube. // realign = If true, rotate the tube by half the angle of one face. -// orient = Orientation of the tube. Use the `ORIENT_` constants from `constants.scad`. Default: vertical. -// anchor = Alignment of the tube. Use the constants from `constants.scad`. Default: centered. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // // Example: These all Produce the Same Tube // tube(h=30, or=40, wall=5); @@ -779,8 +778,8 @@ module tube( od=undef, od1=undef, od2=undef, ir=undef, id=undef, ir1=undef, ir2=undef, id1=undef, id2=undef, - center=undef, orient=ORIENT_Z, anchor=BOTTOM, - realign=false + anchor=BOTTOM, spin=0, orient=UP, + center=undef, realign=false ) { r1 = first_defined([or1, od1/2, r1, d1/2, or, od/2, r, d/2, ir1+wall, id1/2+wall, ir+wall, id/2+wall]); r2 = first_defined([or2, od2/2, r2, d2/2, or, od/2, r, d/2, ir2+wall, id2/2+wall, ir+wall, id/2+wall]); @@ -791,7 +790,7 @@ module tube( sides = segs(max(r1,r2)); size = [r1*2,r1*2,h]; size2 = [r2*2,r2*2,h]; - orient_and_anchor(size, orient, anchor, center=center, size2=size2, geometry="cylinder", chain=true) { + orient_and_anchor(size, orient, anchor, spin=spin, center=center, size2=size2, geometry="cylinder", chain=true) { zrot(realign? 180/sides : 0) { difference() { cyl(h=h, r1=r1, r2=r2, $fn=sides) children(); @@ -821,8 +820,8 @@ module tube( // ir = inside radius of the torus. (use with 'or', or 'od') // od = outer diameter of the torus. (use with 'ir' or 'id') // id = inside diameter of the torus. (use with 'or' or 'od') -// orient = Orientation of the torus. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the torus. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // // Example: // // These all produce the same torus. @@ -837,14 +836,15 @@ module torus( r2=undef, d2=undef, or=undef, od=undef, ir=undef, id=undef, - orient=ORIENT_Z, anchor=CENTER, center=undef + anchor=CENTER, center=undef, + spin=0, orient=UP ) { orr = get_radius(r=or, d=od, dflt=1.0); irr = get_radius(r=ir, d=id, dflt=0.5); majrad = get_radius(r=r, d=d, dflt=(orr+irr)/2); minrad = get_radius(r=r2, d=d2, dflt=(orr-irr)/2); size = [(majrad+minrad)*2, (majrad+minrad)*2, minrad*2]; - orient_and_anchor(size, orient, anchor, center=center, geometry="cylinder", chain=true) { + orient_and_anchor(size, orient, anchor, spin=spin, center=center, geometry="cylinder", chain=true) { rotate_extrude(convexity=4) { right(majrad) circle(minrad); } @@ -866,22 +866,23 @@ module torus( // r = Radius of the sphere. // d = Diameter of the sphere. // circum = If true, circumscribes the perfect sphere of the given radius/diameter. -// orient = Orientation of the sphere, if you don't like where the vertices lay. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the sphere. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example: By Radius // spheroid(r=50, circum=true); // Example: By Diameter // spheroid(d=100, circum=true); // Example: Standard Connectors // spheroid(d=40, circum=true) show_anchors(); -module spheroid(r=undef, d=undef, circum=false, orient=UP, anchor=CENTER) +module spheroid(r=undef, d=undef, circum=false, anchor=CENTER, spin=0, orient=UP) { r = get_radius(r=r, d=d, dflt=1); hsides = segs(r); vsides = ceil(hsides/2); rr = circum? (r / cos(90/vsides) / cos(180/hsides)) : r; size = [2*rr, 2*rr, 2*rr]; - orient_and_anchor(size, orient, anchor, geometry="sphere", chain=true) { + orient_and_anchor(size, orient, anchor, spin=spin, geometry="sphere", chain=true) { sphere(r=rr); children(); } @@ -901,8 +902,9 @@ module spheroid(r=undef, d=undef, circum=false, orient=UP, anchor=CENTER) // r = Radius of the sphere. // d = Diameter of the sphere. // circum = If true, circumscribes the perfect sphere of the given size. -// orient = Orientation of the sphere, if you don't like where the vertices lay. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the sphere. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // // Example: By Radius // staggered_sphere(r=50, circum=true); @@ -910,7 +912,7 @@ module spheroid(r=undef, d=undef, circum=false, orient=UP, anchor=CENTER) // staggered_sphere(d=100, circum=true); // Example: Standard Connectors // staggered_sphere(d=40, circum=true) show_anchors(); -module staggered_sphere(r=undef, d=undef, circum=false, orient=ORIENT_Z, anchor=CENTER) { +module staggered_sphere(r=undef, d=undef, circum=false, anchor=CENTER, spin=0, orient=UP) { r = get_radius(r=r, d=d, dflt=1); sides = segs(r); vsides = max(3, ceil(sides/2))+1; @@ -947,7 +949,7 @@ module staggered_sphere(r=undef, d=undef, circum=false, orient=ORIENT_Z, anchor= ] ); size = [2*rr, 2*rr, 2*rr]; - orient_and_anchor(size, orient, anchor, geometry="sphere", chain=true) { + orient_and_anchor(size, orient, anchor, spin=spin, geometry="sphere", chain=true) { zrot((floor(sides/4)%2==1)? 180/sides : 0) polyhedron(points=pts, faces=faces); children(); } @@ -1011,8 +1013,9 @@ module teardrop2d(r=1, d=undef, ang=45, cap_h=undef) // l = Thickness of teardrop. (Default: 1) // ang = Angle of hat walls from the Z axis. (Default: 45 degrees) // cap_h = If given, height above center where the shape will be truncated. -// orient = Orientation of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. -// anchor = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `BACK` // // Example: Typical Shape // teardrop(r=30, h=10, ang=30); @@ -1020,12 +1023,12 @@ module teardrop2d(r=1, d=undef, ang=45, cap_h=undef) // teardrop(r=30, h=10, ang=30, cap_h=40); // Example: Close Crop // teardrop(r=30, h=10, ang=30, cap_h=20); -module teardrop(r=undef, d=undef, l=undef, h=undef, ang=45, cap_h=undef, orient=ORIENT_Y, anchor=CENTER) +module teardrop(r=undef, d=undef, l=undef, h=undef, ang=45, cap_h=undef, anchor=CENTER, spin=0, orient=FWD) { r = get_radius(r=r, d=d, dflt=1); l = first_defined([l, h, 1]); size = [r*2,r*2,l]; - orient_and_anchor(size, orient, anchor, geometry="cylinder", chain=true) { + orient_and_anchor(size, orient, anchor, spin=spin, geometry="cylinder", chain=true) { linear_extrude(height=l, center=true, slices=2) { teardrop2d(r=r, ang=ang, cap_h=cap_h); } @@ -1047,8 +1050,9 @@ module teardrop(r=undef, d=undef, l=undef, h=undef, ang=45, cap_h=undef, orient= // d = diameter of spherical portion of bottom. // cap_h = height above sphere center to truncate teardrop shape. // maxang = angle of cone on top from vertical. -// orient = Orientation of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. -// anchor = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // // Example: Typical Shape // onion(r=30, maxang=30); @@ -1058,7 +1062,7 @@ module teardrop(r=undef, d=undef, l=undef, h=undef, ang=45, cap_h=undef, orient= // onion(r=30, maxang=30, cap_h=20); // Example: Standard Connectors // onion(r=30, maxang=30, cap_h=40) show_anchors(); -module onion(cap_h=undef, r=undef, d=undef, maxang=45, h=undef, orient=ORIENT_Z, anchor=CENTER) +module onion(cap_h=undef, r=undef, d=undef, maxang=45, h=undef, anchor=CENTER, spin=0, orient=UP) { r = get_radius(r=r, d=d, dflt=1); h = first_defined([cap_h, h]); @@ -1067,7 +1071,7 @@ module onion(cap_h=undef, r=undef, d=undef, maxang=45, h=undef, orient=ORIENT_Z, anchors = [ ["cap", [0,0,h], UP, 0] ]; - orient_and_anchor(size, orient, anchor, geometry="sphere", anchors=anchors, chain=true) { + orient_and_anchor(size, orient, anchor, spin=spin, geometry="sphere", anchors=anchors, chain=true) { rotate_extrude(convexity=2) { difference() { teardrop2d(r=r, ang=maxang, cap_h=h); @@ -1095,7 +1099,11 @@ module nil() union(){} // Description: // Passes through the children passed to it, with no action at all. // Useful while debugging when you want to replace a command. -module noop(orient=ORIENT_Z) orient_and_anchor([0.01,0.01,0.01], orient, CENTER, chain=true) {nil(); children();} +// +// Arguments: +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` +module noop(spin=0, orient=UP) orient_and_anchor([0.01,0.01,0.01], orient, CENTER, spin=spin, chain=true) {nil(); children();} // Module: pie_slice() @@ -1116,8 +1124,9 @@ module noop(orient=ORIENT_Z) orient_and_anchor([0.01,0.01,0.01], orient, CENTER, // d = diameter of pie slice. // d1 = bottom diameter of pie slice. // d2 = top diameter of pie slice. -// orient = Orientation of the pie slice. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the pie slice. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // center = If given, overrides `anchor`. A true value sets `anchor=CENTER`, false sets `anchor=UP`. // // Example: Cylindrical Pie Slice @@ -1128,7 +1137,7 @@ module pie_slice( ang=30, l=undef, r=10, r1=undef, r2=undef, d=undef, d1=undef, d2=undef, - orient=ORIENT_Z, anchor=BOTTOM, + anchor=BOTTOM, spin=0, orient=UP, center=undef, h=undef ) { l = first_defined([l, h, 1]); @@ -1136,7 +1145,7 @@ module pie_slice( r2 = get_radius(r2, r, d2, d, 10); maxd = max(r1,r2)+0.1; size = [2*r1, 2*r1, l]; - orient_and_anchor(size, orient, anchor, center=center, geometry="cylinder", chain=true) { + orient_and_anchor(size, orient, anchor, spin=spin, center=center, geometry="cylinder", chain=true) { difference() { cylinder(r1=r1, r2=r2, h=l, center=true); if (ang<180) rotate(ang) back(maxd/2) cube([2*maxd, maxd, l+0.1], center=true); @@ -1164,22 +1173,22 @@ module pie_slice( // r = radius of fillet. // ang = angle between faces to fillet. // overlap = overlap size for unioning with faces. -// orient = Orientation of the fillet. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_X`. +// orient = Orientation of the fillet. Use the directional constants from `constants.scad`. Default: `RIGHT`. // anchor = Alignment of the fillet. Use the constants from `constants.scad`. Default: `CENTER`. // // Example: // union() { // translate([0,2,-4]) cube([20, 4, 24], anchor=BOTTOM); // translate([0,-10,-4]) cube([20, 20, 4], anchor=BOTTOM); -// color("green") interior_fillet(l=20, r=10, orient=ORIENT_XNEG); +// color("green") interior_fillet(l=20, r=10, orient=LEFT); // } // // Example: -// interior_fillet(l=40, r=10, orient=ORIENT_Y_90); -module interior_fillet(l=1.0, r=1.0, ang=90, overlap=0.01, orient=ORIENT_X, anchor=CENTER) { +// interior_fillet(l=40, r=10, spin=180); +module interior_fillet(l=1.0, r=1.0, ang=90, overlap=0.01, anchor=CENTER, spin=0, orient=UP) { dy = r/tan(ang/2); size = [l,r,r]; - orient_and_anchor(size, orient, anchor, orig_orient=ORIENT_X, chain=true) { + orient_and_anchor(size, orient, anchor, spin=spin, chain=true) { difference() { translate([0,-overlap/tan(ang/2),-overlap]) { if (ang == 90) { @@ -1258,9 +1267,9 @@ module slot( // sd2 = Top diameter of slot channel cone. Use instead of `sd`. // sa = Starting angle. Default: `0` // ea = Ending angle. Default: `90` -// orient = Orientation of the arced slot. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z` -// anchor = Alignment of the arced slot. Use the constants from `constants.scad`. Default: `CENTER` -// center = If given and true, centers vertically. If given and false, drops flush with XY plane. Overrides `anchor`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // $fn2 = The `$fn` value to use on the small round endcaps. The major arcs are still based on `$fn`. Default: `$fn` // // Example(Med): Typical Arced Slot @@ -1272,7 +1281,7 @@ module arced_slot( sr=undef, sr1=undef, sr2=undef, sd=undef, sd1=undef, sd2=undef, sa=0, ea=90, cp=[0,0,0], - orient=ORIENT_Z, anchor=CENTER, + anchor=TOP, spin=spin, orient=UP, $fn2 = undef ) { r = get_radius(r=r, d=d, dflt=2); @@ -1281,11 +1290,11 @@ module arced_slot( fn_minor = first_defined([$fn2, $fn]); da = ea - sa; size = [r+sr1, r+sr1, h]; - orient_and_anchor(size, orient, anchor, geometry="cylinder", chain=true) { + orient_and_anchor(size, orient, anchor, spin=spin, geometry="cylinder", chain=true) { translate(cp) { zrot(sa) { difference() { - pie_slice(ang=da, l=h, r1=r+sr1, r2=r+sr2, orient=ORIENT_Z, anchor=CENTER); + pie_slice(ang=da, l=h, r1=r+sr1, r2=r+sr2, orient=UP, anchor=CENTER); cylinder(h=h+0.1, r1=r-sr1, r2=r-sr2, center=true); } right(r) cylinder(h=h, r1=sr1, r2=sr2, center=true, $fn=fn_minor); diff --git a/sliders.scad b/sliders.scad index f7f706e..8d8fe77 100644 --- a/sliders.scad +++ b/sliders.scad @@ -25,16 +25,17 @@ // wall = Width of wall behind each side of the slider. // ang = Overhang angle for slider, to facilitate supportless printig. // slop = Printer-specific slop value to make parts fit exactly. -// orient = Orientation of the slider. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. // anchor = Alignment of the slider. Use the constants from `constants.scad`. Default: `UP`. +// orient = Orientation of the slider. Use the directional constants from `constants.scad`. Default: `BACK`. +// spin = Number of degrees to rotate around the Z axis, before orienting. // Example: -// slider(l=30, base=10, wall=4, slop=0.2, orient=ORIENT_Y); -module slider(l=30, w=10, h=10, base=10, wall=5, ang=30, slop=PRINTER_SLOP, orient=ORIENT_Y, anchor=BOTTOM) +// slider(l=30, base=10, wall=4, slop=0.2, spin=90); +module slider(l=30, w=10, h=10, base=10, wall=5, ang=30, slop=PRINTER_SLOP, anchor=BOTTOM, spin=0, orient=UP) { full_width = w + 2*wall; full_height = h + base; - orient_and_anchor([full_width, l, h+2*base], orient, anchor, orig_orient=ORIENT_Y, chain=true) { + orient_and_anchor([full_width, l, h+2*base], orient, anchor, spin=spin, chain=true) { down(base+h/2) { // Base cuboid([full_width, l, base-slop], chamfer=2, edges=edges([FRONT,BACK], except=BOT), anchor=BOTTOM); @@ -48,7 +49,7 @@ module slider(l=30, w=10, h=10, base=10, wall=5, ang=30, slop=PRINTER_SLOP, orie up(base+h/2) { xflip_copy(offset=w/2+slop+0.02) { bev_h = h/2*tan(ang); - prismoid([l, h], [l-w, 0], h=bev_h+0.01, orient=ORIENT_XNEG, anchor=RIGHT); + prismoid([h, l], [0, l-w], h=bev_h+0.01, orient=LEFT, anchor=BOT); } } } @@ -69,11 +70,12 @@ module slider(l=30, w=10, h=10, base=10, wall=5, ang=30, slop=PRINTER_SLOP, orie // h = Height of slider. // chamfer = Size of chamfer at end of rail. // ang = Overhang angle for slider, to facilitate supportless printig. -// orient = Orientation of the rail. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. -// anchor = Alignment of the rail. Use the constants from `constants.scad`. Default: `UP`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `BOTTOM` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example: // rail(l=100, w=10, h=10); -module rail(l=30, w=10, h=10, chamfer=1.0, ang=30, orient=ORIENT_Y, anchor=BOTTOM) +module rail(l=30, w=10, h=10, chamfer=1.0, ang=30, anchor=BOTTOM, spin=0, orient=UP) { attack_ang = 30; attack_len = 2; @@ -99,7 +101,7 @@ module rail(l=30, w=10, h=10, chamfer=1.0, ang=30, orient=ORIENT_Y, anchor=BOTTO y1 = l/2; y2 = y1 - attack_len * cos(attack_ang); - orient_and_anchor([w, h, l], orient, anchor, orig_orient=ORIENT_Y, chain=true) { + orient_and_anchor([w, l, h], orient, anchor, spin=spin, chain=true) { polyhedron( convexity=4, points=[ diff --git a/threading.scad b/threading.scad index 47b0e18..9d9b819 100644 --- a/threading.scad +++ b/threading.scad @@ -29,9 +29,10 @@ include // left_handed = If true, thread has a left-handed winding. // higbee = Angle to taper thread ends by. // interior = If true, invert threads for interior threading. -// orient = Orientation of the threads. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the threads. Use the constants from `constants.scad`. Default: `CENTER`. -module thread_helix(base_d, pitch, thread_depth=undef, thread_angle=15, twist=720, profile=undef, left_handed=false, higbee=60, interior=false, orient=ORIENT_Z, anchor=CENTER) +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` +module thread_helix(base_d, pitch, thread_depth=undef, thread_angle=15, twist=720, profile=undef, left_handed=false, higbee=60, interior=false, anchor=CENTER, spin=0, orient=UP) { h = pitch*twist/360; r = base_d/2; @@ -53,7 +54,7 @@ module thread_helix(base_d, pitch, thread_depth=undef, thread_angle=15, twist=72 pline = scale_points(profile, [1,1,1]*pitch); dir = left_handed? -1 : 1; idir = interior? -1 : 1; - orient_and_anchor([2*r, 2*r, h], orient, anchor, chain=true) { + orient_and_anchor([2*r, 2*r, h], orient, anchor, spin=spin, chain=true) { difference() { extrude_2dpath_along_spiral(pline, h=h, r=base_d/2, twist=twist*dir, $fn=segs(base_d/2), anchor=CENTER); down(h/2) right(r) right(interior? thread_depth : 0) zrot(higbee*dir*idir) fwd(dir*pitch/2) cube([3*thread_depth/cos(higbee), pitch, pitch], center=true); @@ -85,9 +86,10 @@ module thread_helix(base_d, pitch, thread_depth=undef, thread_angle=15, twist=72 // internal = If true, make this a mask for making internal threads. // slop = printer slop calibration to allow for tight fitting of parts. Default: `PRINTER_SLOP` // profile = The shape of a thread, if not a symmetric trapezoidal form. Given as a 2D path, where X is between -1/2 and 1/2, representing the pitch distance, and Y is 0 for the peak, and `-depth/pitch` for the valleys. The segment between the end of one thread profile and the start of the next is automatic, so the start and end coordinates should not both be at the same Y at X = ±1/2. This path is scaled up by the pitch size in both dimensions when making the final threading. This overrides the `thread_angle` and `thread_depth` options. -// orient = Orientation of the rod. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the rod. Use the constants from `constants.scad`. Default: `CENTER`. // center = If given, overrides `anchor`. A true value sets `anchor=CENTER`, false sets `anchor=UP`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Examples(Med): // trapezoidal_threaded_rod(d=10, l=40, pitch=2, thread_angle=15, $fn=32); // trapezoidal_threaded_rod(d=3/8*25.4, l=20, pitch=1/8*25.4, thread_angle=29, $fn=32); @@ -97,7 +99,7 @@ module thread_helix(base_d, pitch, thread_depth=undef, thread_angle=15, twist=72 // trapezoidal_threaded_rod(d=10, l=40, pitch=3, thread_angle=15, left_handed=true, starts=3, $fn=36); // trapezoidal_threaded_rod(d=25, l=40, pitch=10, thread_depth=8/3, thread_angle=50, starts=4, center=false, $fa=2, $fs=2); // trapezoidal_threaded_rod(d=50, l=35, pitch=8, thread_angle=30, starts=3, bevel=true); -// trapezoidal_threaded_rod(l=25, d=10, pitch=2, thread_angle=15, starts=3, $fa=1, $fs=1, orient=ORIENT_X, anchor=BOTTOM); +// trapezoidal_threaded_rod(l=25, d=10, pitch=2, thread_angle=15, starts=3, $fa=1, $fs=1, orient=RIGHT, anchor=BOTTOM); module trapezoidal_threaded_rod( d=10, l=100, @@ -110,8 +112,9 @@ module trapezoidal_threaded_rod( profile=undef, internal=false, slop=undef, - orient=ORIENT_Z, anchor=CENTER, + spin=0, + orient=UP, center=undef ) { function _thread_pt(thread, threads, start, starts, astep, asteps, part, parts) = @@ -249,7 +252,7 @@ module trapezoidal_threaded_rod( ) otri ] ); - orient_and_anchor([d,d,l], orient, anchor, center, chain=true) { + orient_and_anchor([d,d,l], orient, anchor, spin=spin, center=center, chain=true) { difference() { polyhedron(points=poly_points, faces=poly_faces, convexity=threads*starts*2); zspread(l+4*pitch*starts) cube([d+1, d+1, 4*pitch*starts], center=true); @@ -281,8 +284,9 @@ module trapezoidal_threaded_rod( // bevel = if true, bevel the thread ends. Default: true // slop = printer slop calibration to allow for tight fitting of parts. Default: `PRINTER_SLOP` // profile = The shape of a thread, if not a symmetric trapezoidal form. Given as a 2D path, where X is between -1/2 and 1/2, representing the pitch distance, and Y is 0 for the peak, and `-depth/pitch` for the valleys. The segment between the end of one thread profile and the start of the next is automatic, so the start and end coordinates should not both be at the same Y at X = ±1/2. This path is scaled up by the pitch size in both dimensions when making the final threading. This overrides the `thread_angle` and `thread_depth` options. -// orient = Orientation of the nut. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the nut. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Examples(Med): // trapezoidal_threaded_nut(od=16, id=8, h=8, pitch=2, slop=0.2, anchor=UP); // trapezoidal_threaded_nut(od=17.4, id=10, h=10, pitch=2, slop=0.2, left_handed=true); @@ -299,12 +303,13 @@ module trapezoidal_threaded_nut( starts=1, bevel=true, slop=undef, - orient=ORIENT_Z, - anchor=CENTER + anchor=CENTER, + spin=0, + orient=UP ) { depth = min((thread_depth==undef? pitch/2 : thread_depth), pitch/2/tan(thread_angle)); slop = default(slop, PRINTER_SLOP); - orient_and_anchor([od/cos(30),od,h], orient, anchor, chain=true) { + orient_and_anchor([od/cos(30),od,h], orient, anchor, spin=spin, chain=true) { difference() { cylinder(d=od/cos(30), h=h, center=true, $fn=6); trapezoidal_threaded_rod( @@ -346,11 +351,12 @@ module trapezoidal_threaded_nut( // bevel = if true, bevel the thread ends. Default: false // internal = If true, make this a mask for making internal threads. // slop = printer slop calibration to allow for tight fitting of parts. Default: `PRINTER_SLOP` -// orient = Orientation of the rod. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the rod. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example(2D): // projection(cut=true) -// threaded_rod(d=10, l=15, pitch=2, orient=ORIENT_X); +// threaded_rod(d=10, l=15, pitch=2, orient=RIGHT); // Examples(Med): // threaded_rod(d=10, l=20, pitch=1.25, left_handed=true, $fa=1, $fs=1); // threaded_rod(d=25, l=20, pitch=2, $fa=1, $fs=1); @@ -360,8 +366,9 @@ module threaded_rod( bevel=false, internal=false, slop=undef, - orient=ORIENT_Z, - anchor=CENTER + anchor=CENTER, + spin=0, + orient=UP ) { depth = pitch * cos(30) * 5/8; profile = internal? [ @@ -388,8 +395,9 @@ module threaded_rod( bevel=bevel, internal=internal, slop=slop, - orient=orient, - anchor=anchor + anchor=anchor, + spin=spin, + orient=orient ) children(); } @@ -407,15 +415,16 @@ module threaded_rod( // left_handed = if true, create left-handed threads. Default = false // bevel = if true, bevel the thread ends. Default: false // slop = printer slop calibration to allow for tight fitting of parts. default=0.2 -// orient = Orientation of the nut. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the nut. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Examples(Med): // threaded_nut(od=16, id=8, h=8, pitch=1.25, left_handed=true, slop=0.2, $fa=1, $fs=1); module threaded_nut( od=16, id=10, h=10, pitch=2, left_handed=false, bevel=false, slop=undef, - orient=ORIENT_Z, anchor=CENTER + anchor=CENTER, spin=0, orient=UP ) { depth = pitch * cos(30) * 5/8; profile = [ @@ -432,7 +441,8 @@ module threaded_nut( profile=profile, left_handed=left_handed, bevel=bevel, slop=slop, - orient=orient, anchor=anchor + anchor=anchor, spin=spin, + orient=orient ) children(); } @@ -451,11 +461,12 @@ module threaded_nut( // bevel = if true, bevel the thread ends. Default: false // internal = If true, this is a mask for making internal threads. // slop = printer slop calibration to allow for tight fitting of parts. default=0.2 -// orient = Orientation of the rod. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the rod. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example(2D): // projection(cut=true) -// buttress_threaded_rod(d=10, l=15, pitch=2, orient=ORIENT_X); +// buttress_threaded_rod(d=10, l=15, pitch=2, orient=RIGHT); // Examples(Med): // buttress_threaded_rod(d=10, l=20, pitch=1.25, left_handed=true, $fa=1, $fs=1); // buttress_threaded_rod(d=25, l=20, pitch=2, $fa=1, $fs=1); @@ -465,8 +476,9 @@ module buttress_threaded_rod( bevel=false, internal=false, slop=undef, - orient=ORIENT_Z, - anchor=CENTER + anchor=CENTER, + spin=0, + orient=UP ) { depth = pitch * 3/4; profile = [ @@ -484,9 +496,10 @@ module buttress_threaded_rod( left_handed=left_handed, bevel=bevel, internal=internal, - orient=orient, slop=slop, - anchor=anchor + anchor=anchor, + spin=spin, + orient=orient ) children(); } @@ -504,15 +517,18 @@ module buttress_threaded_rod( // left_handed = if true, create left-handed threads. Default = false // bevel = if true, bevel the thread ends. Default: false // slop = printer slop calibration to allow for tight fitting of parts. default=0.2 -// orient = Orientation of the nut. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the nut. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Examples(Med): // buttress_threaded_nut(od=16, id=8, h=8, pitch=1.25, left_handed=true, slop=0.2, $fa=1, $fs=1); module buttress_threaded_nut( od=16, id=10, h=10, pitch=2, left_handed=false, bevel=false, slop=undef, - orient=ORIENT_Z, anchor=CENTER + anchor=CENTER, + spin=0, + orient=UP ) { depth = pitch * 3/4; profile = [ @@ -529,7 +545,8 @@ module buttress_threaded_nut( thread_depth=pitch*3*sqrt(3)/8, left_handed=left_handed, bevel=bevel, slop=slop, - orient=orient, anchor=anchor + anchor=anchor, spin=spin, + orient=orient ) children(); } @@ -547,11 +564,12 @@ module buttress_threaded_nut( // left_handed = if true, create left-handed threads. Default = false // bevel = if true, bevel the thread ends. Default: false // starts = The number of lead starts. Default = 1 -// orient = Orientation of the rod. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the rod. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example(2D): // projection(cut=true) -// metric_trapezoidal_threaded_rod(d=10, l=15, pitch=2, orient=ORIENT_X); +// metric_trapezoidal_threaded_rod(d=10, l=15, pitch=2, orient=RIGHT); // Examples(Med): // metric_trapezoidal_threaded_rod(d=10, l=30, pitch=2, left_handed=true, $fa=1, $fs=1); module metric_trapezoidal_threaded_rod( @@ -559,8 +577,9 @@ module metric_trapezoidal_threaded_rod( left_handed=false, starts=1, bevel=false, - orient=ORIENT_Z, - anchor=CENTER + anchor=CENTER, + spin=0, + orient=UP ) { trapezoidal_threaded_rod( d=d, l=l, @@ -569,8 +588,9 @@ module metric_trapezoidal_threaded_rod( left_handed=left_handed, starts=starts, bevel=bevel, - orient=orient, - anchor=anchor + anchor=anchor, + spin=spin, + orient=orient ) children(); } @@ -589,8 +609,9 @@ module metric_trapezoidal_threaded_rod( // bevel = if true, bevel the thread ends. Default: false // starts = The number of lead starts. Default = 1 // slop = printer slop calibration to allow for tight fitting of parts. default=0.2 -// orient = Orientation of the nut. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the nut. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Examples(Med): // metric_trapezoidal_threaded_nut(od=16, id=10, h=10, pitch=2, left_handed=true, bevel=true, $fa=1, $fs=1); module metric_trapezoidal_threaded_nut( @@ -600,8 +621,9 @@ module metric_trapezoidal_threaded_nut( left_handed=false, bevel=false, slop=undef, - orient=ORIENT_Z, - anchor=CENTER + anchor=CENTER, + spin=0, + orient=UP ) { trapezoidal_threaded_nut( od=od, id=id, h=h, @@ -610,8 +632,9 @@ module metric_trapezoidal_threaded_nut( starts=starts, bevel=bevel, slop=slop, - orient=orient, - anchor=anchor + anchor=anchor, + spin=spin, + orient=orient ) children(); } @@ -631,11 +654,12 @@ module metric_trapezoidal_threaded_nut( // starts = The number of lead starts. Default = 1 // left_handed = if true, create left-handed threads. Default = false // bevel = if true, bevel the thread ends. Default: false -// orient = Orientation of the rod. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the rod. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example(2D): // projection(cut=true) -// acme_threaded_rod(d=10, l=15, pitch=2, orient=ORIENT_X); +// acme_threaded_rod(d=10, l=15, pitch=2, orient=RIGHT); // Examples(Med): // acme_threaded_rod(d=3/8*25.4, l=20, pitch=1/8*25.4, $fn=32); // acme_threaded_rod(d=10, l=30, pitch=2, starts=3, $fa=1, $fs=1); @@ -646,8 +670,9 @@ module acme_threaded_rod( starts=1, left_handed=false, bevel=false, - orient=ORIENT_Z, - anchor=CENTER + anchor=CENTER, + spin=0, + orient=UP ) { trapezoidal_threaded_rod( d=d, l=l, pitch=pitch, @@ -656,8 +681,9 @@ module acme_threaded_rod( starts=starts, left_handed=left_handed, bevel=bevel, - orient=orient, - anchor=anchor + anchor=anchor, + spin=spin, + orient=orient ) children(); } @@ -677,8 +703,9 @@ module acme_threaded_rod( // left_handed = if true, create left-handed threads. Default = false // bevel = if true, bevel the thread ends. Default: false // slop = printer slop calibration to allow for tight fitting of parts. default=0.2 -// orient = Orientation of the nut. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the nut. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Examples(Med): // acme_threaded_nut(od=16, id=3/8*25.4, h=8, pitch=1/8*25.4, slop=0.2); // acme_threaded_nut(od=16, id=10, h=10, pitch=2, starts=3, slop=0.2, $fa=1, $fs=1); @@ -690,8 +717,9 @@ module acme_threaded_nut( left_handed=false, bevel=false, slop=undef, - orient=ORIENT_Z, - anchor=CENTER + anchor=CENTER, + spin=0, + orient=UP ) { trapezoidal_threaded_nut( od=od, id=id, h=h, pitch=pitch, @@ -701,8 +729,9 @@ module acme_threaded_nut( bevel=bevel, starts=starts, slop=slop, - orient=orient, - anchor=anchor + anchor=anchor, + spin=spin, + orient=orient ) children(); } @@ -720,11 +749,12 @@ module acme_threaded_nut( // left_handed = if true, create left-handed threads. Default = false // bevel = if true, bevel the thread ends. Default: false // starts = The number of lead starts. Default = 1 -// orient = Orientation of the rod. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the rod. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Example(2D): // projection(cut=true) -// square_threaded_rod(d=10, l=15, pitch=2, orient=ORIENT_X); +// square_threaded_rod(d=10, l=15, pitch=2, orient=RIGHT); // Examples(Med): // square_threaded_rod(d=10, l=20, pitch=2, starts=2, $fn=32); module square_threaded_rod( @@ -732,8 +762,9 @@ module square_threaded_rod( left_handed=false, bevel=false, starts=1, - orient=ORIENT_Z, - anchor=CENTER + anchor=CENTER, + spin=0, + orient=UP ) { trapezoidal_threaded_rod( d=d, l=l, pitch=pitch, @@ -741,8 +772,9 @@ module square_threaded_rod( left_handed=left_handed, bevel=bevel, starts=starts, - orient=orient, - anchor=anchor + anchor=anchor, + spin=spin, + orient=orient ) children(); } @@ -761,8 +793,9 @@ module square_threaded_rod( // bevel = if true, bevel the thread ends. Default: false // starts = The number of lead starts. Default = 1 // slop = printer slop calibration to allow for tight fitting of parts. default=0.2 -// orient = Orientation of the nut. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the nut. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Examples(Med): // square_threaded_nut(od=16, id=10, h=10, pitch=2, starts=2, slop=0.15, $fn=32); module square_threaded_nut( @@ -772,8 +805,9 @@ module square_threaded_nut( bevel=false, starts=1, slop=undef, - orient=ORIENT_Z, - anchor=CENTER + anchor=CENTER, + spin=0, + orient=UP ) { trapezoidal_threaded_nut( od=od, id=id, h=h, pitch=pitch, @@ -782,8 +816,9 @@ module square_threaded_nut( bevel=bevel, starts=starts, slop=slop, - orient=orient, - anchor=anchor + anchor=anchor, + spin=spin, + orient=orient ) children(); } @@ -798,18 +833,21 @@ module square_threaded_nut( // Creates an approximation of a standard PCO-1881 threaded beverage bottle neck. // Arguments: // wall = Wall thickness in mm. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Extra Anchors: // "support-ring" = Centered at the bottom of the support ring. // Example: // pco1881_neck(); -module pco1881_neck(wall=2, orient=ORIENT_Z, anchor="support-ring") +module pco1881_neck(wall=2, anchor="support-ring", spin=0, orient=UP) { $fn = segs(33/2); h = 17+5; anchors = [ anchorpt("support-ring", [0,0,5-h/2]) ]; - orient_and_anchor([33,33,17+5], orient, anchor, anchors=anchors, chain=true) { + orient_and_anchor([33,33,17+5], orient, anchor, spin=spin, anchors=anchors, chain=true) { up(5-h/2) difference() { union() { @@ -866,22 +904,23 @@ module pco1881_neck(wall=2, orient=ORIENT_Z, anchor="support-ring") // Creates a basic cap for a PCO1881 threaded beverage bottle. // Arguments: // wall = Wall thickness in mm. -// orient = Orientation of the threads. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. -// anchor = Alignment of the threads. Use the constants from `constants.scad`. Default: `"inside-top"`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // Extra Anchors: // "inside-top" = Centered on the inside top of the cap. // Example: // pco1881_cap(); -module pco1881_cap(wall=2, orient=ORIENT_ZNEG, anchor=BOTTOM) +module pco1881_cap(wall=2, anchor=BOTTOM, spin=0, orient=UP) { $fn = segs(33/2); w = 28.58 + 2*wall; h = 11.2 + wall; anchors = [ - anchorpt("inside-top", [0,0,h/2-wall]) + anchorpt("inside-top", [0,0,-(h/2-wall)]) ]; - orient_and_anchor([w, w, 11.2+wall], orient, anchor, anchors=anchors, orig_anchor=TOP, chain=true) { - zrot(45) xrot(180) { + orient_and_anchor([w, w, h], orient, anchor, spin=spin, anchors=anchors, chain=true) { + down(h/2) zrot(45) { tube(id=28.58, wall=wall, h=11.2+wall, anchor=BOTTOM); cylinder(d=w, h=wall, anchor=BOTTOM); up(wall+2) thread_helix(base_d=25.5, pitch=2.7, thread_depth=1.6, thread_angle=15, twist=650, higbee=45, interior=true, anchor=BOTTOM); diff --git a/torx_drive.scad b/torx_drive.scad index e5aeb32..ca0a9aa 100644 --- a/torx_drive.scad +++ b/torx_drive.scad @@ -181,9 +181,9 @@ module torx_drive2d(size) { // center = If true, centers bit vertically. // Examples: // torx_drive(size=30, l=10, $fa=1, $fs=1); -module torx_drive(size, l=5, center=undef, orient=ORIENT_Z, anchor=BOTTOM) { +module torx_drive(size, l=5, center=undef, anchor=BOTTOM, spin=0, orient=UP) { od = torx_outer_diam(size); - orient_and_anchor([od, od, l], orient, anchor, center, chain=true) { + orient_and_anchor([od, od, l], orient, anchor, spin=spin, center=center, chain=true) { linear_extrude(height=l, convexity=4, center=true) { torx_drive2d(size); } diff --git a/transforms.scad b/transforms.scad index 32f17ca..27545d8 100644 --- a/transforms.scad +++ b/transforms.scad @@ -884,8 +884,9 @@ module zdistribute(spacing=10, sizes=undef, l=undef) // stagger = If true, make a staggered (hexagonal) grid. If false, make square grid. If `"alt"`, makes alternate staggered pattern. Default: false // scale = [X,Y] scaling factors to reshape grid. // in_poly = If given a list of polygon points, only creates copies whose center would be inside the polygon. Polygon can be concave and/or self crossing. -// orient = Orientation axis for the grid. Orientation is NOT applied to individual children. -// anchor = Alignment of the grid. Alignment is NOT applies to individual children. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // // Side Effects: // `$pos` is set to the relative centerpoint of each child copy, and can be used to modify each child individually. @@ -916,7 +917,7 @@ module zdistribute(spacing=10, sizes=undef, l=undef) // zrot(180/6) // cylinder(h=20, d=10/cos(180/6)+0.01, $fn=6); // } -module grid2d(size=undef, spacing=undef, cols=undef, rows=undef, stagger=false, scale=[1,1,1], in_poly=undef, orient=ORIENT_Z, anchor=CENTER) +module grid2d(size=undef, spacing=undef, cols=undef, rows=undef, stagger=false, scale=[1,1,1], in_poly=undef, anchor=CENTER, spin=0, orient=UP) { assert_in_list("stagger", stagger, [false, true, "alt"]); scl = vmul(scalar_vec3(scale, 1), (stagger!=false? [0.5, sin(60), 0] : [1,1,0])); @@ -926,10 +927,10 @@ module grid2d(size=undef, spacing=undef, cols=undef, rows=undef, stagger=false, spc = vmul(scalar_vec3(spacing), scl); maxcols = ceil(siz[0]/spc[0]); maxrows = ceil(siz[1]/spc[1]); - grid2d(spacing=spacing, cols=maxcols, rows=maxrows, stagger=stagger, scale=scale, in_poly=in_poly, orient=orient, anchor=anchor) children(); + grid2d(spacing=spacing, cols=maxcols, rows=maxrows, stagger=stagger, scale=scale, in_poly=in_poly, anchor=anchor, spin=spin, orient=orient) children(); } else { spc = [siz[0]/cols, siz[1]/rows, 0]; - grid2d(spacing=spc, cols=cols, rows=rows, stagger=stagger, scale=scale, in_poly=in_poly, orient=orient, anchor=anchor) children(); + grid2d(spacing=spc, cols=cols, rows=rows, stagger=stagger, scale=scale, in_poly=in_poly, anchor=anchor, spin=spin, orient=orient) children(); } } else { spc = is_list(spacing)? spacing : vmul(scalar_vec3(spacing), scl); @@ -940,7 +941,7 @@ module grid2d(size=undef, spacing=undef, cols=undef, rows=undef, stagger=false, siz = vmul(spc, [mcols-1, mrows-1, 0]); staggermod = (stagger == "alt")? 1 : 0; if (stagger == false) { - orient_and_anchor(siz, orient, anchor) { + orient_and_anchor(siz, orient, anchor, spin=spin) { for (row = [0:mrows-1]) { for (col = [0:mcols-1]) { pos = [col*spc[0], row*spc[1]] - point2d(siz/2); @@ -955,7 +956,7 @@ module grid2d(size=undef, spacing=undef, cols=undef, rows=undef, stagger=false, } } else { // stagger == true or stagger == "alt" - orient_and_anchor(siz, orient, anchor) { + orient_and_anchor(siz, orient, anchor, spin=spin) { cols1 = ceil(mcols/2); cols2 = mcols - cols1; for (row = [0:mrows-1]) { diff --git a/walls.scad b/walls.scad index 27b0c52..ebf499f 100644 --- a/walls.scad +++ b/walls.scad @@ -28,16 +28,17 @@ // l = Length of the strut. // wall = height of rectangular portion of the strut. // ang = angle that the trianglar side will converge at. -// orient = Orientation of the length axis of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. -// anchor = Alignment of the shape. Use the constants from `constants.scad`. Default: `FRONT`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // // Example: // narrowing_strut(w=10, l=100, wall=5, ang=30); -module narrowing_strut(w=10, l=100, wall=5, ang=30, orient=ORIENT_Y, anchor=BOTTOM) +module narrowing_strut(w=10, l=100, wall=5, ang=30, anchor=BOTTOM, spin=0, orient=UP) { h = wall + w/2/tan(ang); size = [w, h, l]; - orient_and_anchor(size, orient, anchor, chain=true) { + orient_and_anchor(size, orient, anchor, spin=spin, chain=true) { fwd(h/2) { linear_extrude(height=l, center=true, slices=2) { back(wall/2) square([w, wall], center=true); @@ -72,14 +73,15 @@ module narrowing_strut(w=10, l=100, wall=5, ang=30, orient=ORIENT_Y, anchor=BOTT // ang = maximum overhang angle of diagonal brace. // strut = the width of the diagonal brace. // wall = the thickness of the thinned portion of the wall. -// orient = Orientation of the length axis of the wall. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_X`. -// anchor = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // // Example: Typical Shape // thinning_wall(h=50, l=80, thick=4); // Example: Trapezoidal // thinning_wall(h=50, l=[80,50], thick=4); -module thinning_wall(h=50, l=100, thick=5, ang=30, strut=5, wall=2, orient=ORIENT_Z, anchor=CENTER) +module thinning_wall(h=50, l=100, thick=5, ang=30, strut=5, wall=2, anchor=CENTER, spin=0, orient=UP) { l1 = (l[0] == undef)? l : l[0]; l2 = (l[1] == undef)? l : l[1]; @@ -103,7 +105,7 @@ module thinning_wall(h=50, l=100, thick=5, ang=30, strut=5, wall=2, orient=ORIEN y2 = y1 - min(z2-z3, x2-x3) * sin(ang); size = [l1, thick, h]; - orient_and_anchor(size, orient, anchor, size2=[l2,thick], chain=true) { + orient_and_anchor(size, orient, anchor, spin=spin, size2=[l2,thick], chain=true) { polyhedron( points=[ [-x4, -y1, -z1], @@ -216,17 +218,18 @@ module thinning_wall(h=50, l=100, thick=5, ang=30, strut=5, wall=2, orient=ORIEN // ang = maximum overhang angle of diagonal brace. // strut = the width of the diagonal brace. // wall = the thickness of the thinned portion of the wall. -// orient = Orientation of the length axis of the wall. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. -// anchor = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // -// Example: Typical Shape +// Example: // braced_thinning_wall(h=50, l=100, thick=5); -module braced_thinning_wall(h=50, l=100, thick=5, ang=30, strut=5, wall=2, orient=ORIENT_Y, anchor=CENTER) +module braced_thinning_wall(h=50, l=100, thick=5, ang=30, strut=5, wall=2, anchor=CENTER, spin=0, orient=UP) { dang = atan((h-2*strut)/(l-2*strut)); dlen = (h-2*strut)/sin(dang); size = [l, thick, h]; - orient_and_anchor(size, orient, anchor, orig_orient=ORIENT_Y, chain=true) { + orient_and_anchor(size, orient, anchor, spin=spin, chain=true) { union() { xrot_copies([0, 180]) { down(h/2) narrowing_strut(w=thick, l=l, wall=strut, ang=ang); @@ -268,9 +271,10 @@ module braced_thinning_wall(h=50, l=100, thick=5, ang=30, strut=5, wall=2, orien // strut = the width of the diagonal brace. // wall = the thickness of the thinned portion of the wall. // diagonly = boolean, which denotes only the diagonal side (hypotenuse) should be thick. -// orient = Orientation of the length axis of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. -// anchor = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`. // center = If true, centers shape. If false, overrides `anchor` with `UP+BACK`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // // Example: Centered // thinning_triangle(h=50, l=80, thick=4, ang=30, strut=5, wall=2, center=true); @@ -278,12 +282,12 @@ module braced_thinning_wall(h=50, l=100, thick=5, ang=30, strut=5, wall=2, orien // thinning_triangle(h=50, l=80, thick=4, ang=30, strut=5, wall=2, center=false); // Example: Diagonal Brace Only // thinning_triangle(h=50, l=80, thick=4, ang=30, strut=5, wall=2, diagonly=true, center=false); -module thinning_triangle(h=50, l=100, thick=5, ang=30, strut=5, wall=3, diagonly=false, center=undef, orient=ORIENT_Y, anchor=CENTER) +module thinning_triangle(h=50, l=100, thick=5, ang=30, strut=5, wall=3, diagonly=false, center=undef, anchor=CENTER, spin=0, orient=UP) { dang = atan(h/l); dlen = h/sin(dang); size = [thick, h, l]; - orient_and_anchor(size, orient, anchor, center=center, noncentered=BOTTOM+FRONT, orig_orient=ORIENT_Y, chain=true) { + orient_and_anchor(size, orient, anchor, spin=spin, center=center, noncentered=BOTTOM+FRONT, chain=true) { difference() { union() { if (!diagonly) { @@ -327,8 +331,9 @@ module thinning_triangle(h=50, l=100, thick=5, ang=30, strut=5, wall=3, diagonly // maxang = maximum overhang angle of cross-braces. // max_bridge = maximum bridging distance between cross-braces. // strut = the width of the cross-braces. -// orient = Orientation of the length axis of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. -// anchor = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // // Example: Typical Shape // sparse_strut(h=40, l=100, thick=3); @@ -338,7 +343,7 @@ module thinning_triangle(h=50, l=100, thick=5, ang=30, strut=5, wall=3, diagonly // sparse_strut(h=40, l=100, thick=3, strut=2, maxang=45); // Example: Longer max_bridge // sparse_strut(h=40, l=100, thick=3, strut=2, maxang=45, max_bridge=30); -module sparse_strut(h=50, l=100, thick=4, maxang=30, strut=5, max_bridge=20, orient=ORIENT_Y, anchor=CENTER) +module sparse_strut(h=50, l=100, thick=4, maxang=30, strut=5, max_bridge=20, anchor=CENTER, spin=0, orient=UP) { zoff = h/2 - strut/2; yoff = l/2 - strut/2; @@ -359,7 +364,7 @@ module sparse_strut(h=50, l=100, thick=4, maxang=30, strut=5, max_bridge=20, ori len = zstep / cos(ang); size = [thick, l, h]; - orient_and_anchor(size, orient, anchor, orig_orient=ORIENT_Y, chain=true) { + orient_and_anchor(size, orient, anchor, spin=spin, chain=true) { yrot(90) linear_extrude(height=thick, convexity=4*yreps, center=true) { difference() { @@ -395,8 +400,9 @@ module sparse_strut(h=50, l=100, thick=4, maxang=30, strut=5, max_bridge=20, ori // maxang = maximum overhang angle of cross-braces. // max_bridge = maximum bridging distance between cross-braces. // strut = the width of the cross-braces. -// orient = Orientation of the length axis of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. -// anchor = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // // Example(Med): Typical Shape // sparse_strut3d(h=30, w=30, l=100); @@ -406,7 +412,7 @@ module sparse_strut(h=50, l=100, thick=4, maxang=30, strut=5, max_bridge=20, ori // sparse_strut3d(h=30, w=30, l=100, strut=2, maxang=50); // Example(Med): Smaller max_bridge // sparse_strut3d(h=30, w=30, l=100, strut=2, maxang=50, max_bridge=20); -module sparse_strut3d(h=50, l=100, w=50, thick=3, maxang=40, strut=3, max_bridge=30, orient=ORIENT_Y, anchor=CENTER) +module sparse_strut3d(h=50, l=100, w=50, thick=3, maxang=40, strut=3, max_bridge=30, anchor=CENTER, spin=0, orient=UP) { xoff = w - thick; @@ -429,7 +435,7 @@ module sparse_strut3d(h=50, l=100, w=50, thick=3, maxang=40, strut=3, max_bridge supp_step = cross_len/2/supp_reps; size = [w, l, h]; - orient_and_anchor(size, orient, anchor, orig_orient=ORIENT_Y, chain=true) { + orient_and_anchor(size, orient, anchor, spin=spin, chain=true) { intersection() { union() { ybridge = (l - (yreps+1) * strut) / yreps; @@ -491,8 +497,9 @@ module sparse_strut3d(h=50, l=100, w=50, thick=3, maxang=40, strut=3, max_bridge // thick = thickness of strut wall. // strut = the width of the cross-braces. // wall = thickness of corrugations. -// orient = Orientation of the length axis of the shape. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Y`. -// anchor = Alignment of the shape. Use the constants from `constants.scad`. Default: `CENTER`. +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments#anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments#orient). Default: `UP` // // Example: Typical Shape // corrugated_wall(h=50, l=100); @@ -500,7 +507,7 @@ module sparse_strut3d(h=50, l=100, w=50, thick=3, maxang=40, strut=3, max_bridge // corrugated_wall(h=50, l=100, strut=8); // Example: Thicker Wall // corrugated_wall(h=50, l=100, strut=8, wall=3); -module corrugated_wall(h=50, l=100, thick=5, strut=5, wall=2, orient=ORIENT_Y, anchor=CENTER) +module corrugated_wall(h=50, l=100, thick=5, strut=5, wall=2, anchor=CENTER, spin=0, orient=UP) { amplitude = (thick - wall) / 2; period = min(15, thick * 2); @@ -508,7 +515,7 @@ module corrugated_wall(h=50, l=100, thick=5, strut=5, wall=2, orient=ORIENT_Y, a step = period/steps; il = l - 2*strut + 2*step; size = [thick, l, h]; - orient_and_anchor(size, orient, anchor, orig_orient=ORIENT_Y, chain=true) { + orient_and_anchor(size, orient, anchor, spin=spin, chain=true) { union() { linear_extrude(height=h-2*strut+0.1, slices=2, convexity=ceil(2*il/period), center=true) { polygon(