diff --git a/attachments.scad b/attachments.scad index a3f97baa..4f029436 100644 --- a/attachments.scad +++ b/attachments.scad @@ -3490,11 +3490,11 @@ function attach_geom( assert(is_region(region),2) let( l = default(l, h) ) two_d==true - ? assert(is_undef(l)) + ? assert(is_undef(l), "Cannot give l/h with region anchor types (when two_d is set)") extent==true ? ["rgn_extent", region, cp, offset, anchors] : ["rgn_isect", region, cp, offset, anchors] - : assert(is_finite(l)) + : assert(is_finite(l), "Must give l/h with extrusion anchor types (did you forget to set two_d?)") let( shift = default(shift, [0,0]), scale = is_num(scale)? [scale,scale] : default(scale, [1,1]), diff --git a/drawing.scad b/drawing.scad index 47fc1683..e65b7819 100644 --- a/drawing.scad +++ b/drawing.scad @@ -17,7 +17,7 @@ // Section: Line Drawing // Module: stroke() -// Synopsis: Draws a line along a path or region boundry. +// Synopsis: Draws a line along a path or region boundary. // SynTags: Geom // Topics: Paths (2D), Paths (3D), Drawing Tools // See Also: dashed_stroke(), offset_stroke(), path_sweep() @@ -36,8 +36,8 @@ // . // In 2d the stroke module works by creating a sequence of rectangles (or trapezoids if line width varies) and // filling in the gaps with rounded wedges. This is fast and produces a good result. In 3d the modules -// creates a cylinders (or cones) and fills the gaps with rounded wedges made using rotate_extrude. This process will be slow for -// long paths due to the 3d unions, and the faces on sequential cylinders may not line up. In many cases, {{path_sweep()}} will be +// creates a cylinders (or cones) and fills the gaps with rounded wedges made using rotate_extrude. This process is slow for +// long paths due to the 3d unions, and the faces on sequential cylinders may not line up. In many cases, {{path_sweep()}} is // a better choice, both running faster and producing superior output, when working in three dimensions. // Figure(Med,NoAxes,2D,VPR=[0,0,0],VPD=250): Endcap Types // cap_pairs = [ @@ -588,7 +588,7 @@ module stroke( // Function&Module: dashed_stroke() -// Synopsis: Draws a dashed line along a path or region boundry. +// Synopsis: Draws a dashed line along a path or region boundary. // SynTags: Geom, PathList // Topics: Paths, Drawing Tools // See Also: stroke(), path_cut() diff --git a/shapes2d.scad b/shapes2d.scad index 38ceadfa..2bb2e9a6 100644 --- a/shapes2d.scad +++ b/shapes2d.scad @@ -585,7 +585,7 @@ function regular_ngon(n=6, r, d, or, od, ir, id, side, rounding=0, realign=false assert(is_int(n) && n>=3) assert(is_undef(align_tip) || is_vector(align_tip)) assert(is_undef(align_side) || is_vector(align_side)) - assert(is_undef(align_tip) || is_undef(align_side), "Can only specify one of align_tip and align-side") + assert(is_undef(align_tip) || is_undef(align_side), "Can only specify one of align_tip and align_side") let( sc = 1/cos(180/n), ir = is_finite(ir)? ir*sc : undef, @@ -1525,34 +1525,41 @@ module egg(length,r1,r2,R,d1,d2,D,anchor=CENTER, spin=0) // Usage: ring or partial ring passing through three points // region=ring(n, [ring_width], [r=,d=], points=[P0,P1,P2], [full=]); // Usage: ring or partial ring from tangent point on segment `[P0,P1]` to the tangent point on segment `[P1,P2]`. -// region=ring(n, [ring_width], corner=[P0,P1,P2], [r=,d=], [r1|d1=], [r2=|d2=], [full=]); +// region=ring(n, corner=[P0,P1,P2], r1=|d1=, r2=|d2=, [full=]); // Usage: ring or partial ring based on setting a width at the X axis and height above the X axis // region=ring(n, [ring_width], [r=|d=], width=, thickness=, [full=]); // Usage: as a module // ring(...) [ATTACHMENTS]; // Description: -// If called as a function returns a region or path for a ring or part of a ring. If called as a module, creates the corresponding 2D ring or partial ring shape. +// If called as a function, returns a region or path for a ring or part of a ring. If called as a module, creates the corresponding 2D ring or partial ring shape. // The geometry of the ring can be specified using any of the methods supported by {{arc()}}. If `full` is true (the default) the ring will be complete and the // returned value a region. If `full` is false then the return is a path describing a partial ring. The returned path is always clockwise with the larger radius arc first. -// A ring has two radii, the inner and outer. When specifying geometry you must somehow specify one radius, which can be directly with `r=` or `r1=` or by giving a point list with -// or without a center point. You specify the second radius by giving `r=` directly, or `r2=` if you used `r1=` for the first radius, or by giving `ring_width`. If `ring_width` -// the second radius will be larger than the first; if `ring_width` is negative the second radius will be smaller. +// . +// You can specify the ring dimensions in a variety of ways similar to how you can use {{arc()}}. +// * Provide two radii or diameters using `r1` or `d1` and `r2` or `d2`. +// * Specify `r` or `d` and `ring_width`. A positive `ring_width` value will grow the ring outward from your given radius/diameter; if you give a negative `ring_width` then the ring will grow inward from your given radius/diameter. +// * Set `points` to a list of three points then an arc is chosen to pass through those points and the second arc of the ring is defined by either `ring_width`, `r` or `d`. +// * Give `width`, `thickness`, and either `r`, `d` or `ring_width`. The `width` and `thickness` define an arc whose endpoints lie on the X axis with the specified width between them, and whose height is `thickness`. The ring is defined by that arc, combined with either `ring_width` or the given radius/diameter. +// . +// If you specify the ring using `points` or using `width` and `thickness` then that determine its location. Otherwise the ring appears centered at the origin. +// In that case, you can shift it to a different center point by setting `cp`. Alternatively you can set `corner` to a list of three points defining a corner and the +// ring will be placed tangent to that corner. // Arguments: // n = Number of vertices to use for the inner and outer portions of the ring // ring_width = width of the ring. Can be positive or negative // --- -// r1/d1 = inner radius or diameter of the ring -// r2/d2 = outer radius or diameter of the ring -// r/d = second radius or diameter of ring when r1 or d1 are not given +// r1/d1 = one of the radii or diameters of the ring. Must combine with `r2/d2`. +// r2/d2 = one of the radii or diameters of the ring. Must combine with `r1/d1`. +// r/d = radius or diameter of the ring. Must combine with `ring_width`, `points` or `center` // full = if true create a full ring, if false create a partial ring. Default: true unless `angle` is given // cp = Centerpoint of ring. -// points = Points on the ring boundary. -// corner = A path of two segments to fit the ring tangent to. +// points = Points on the ring boundary. Combine with `r/d` or `ring_width` +// corner = A path of two segments to fit the ring tangent to. Combine with `r1/d1` and `r2/d2` or with `r/d` and `ring_width`. // long = if given with cp and points takes the long arc instead of the default short arc. Default: false // cw = if given with cp and 2 points takes the arc in the clockwise direction. Default: false // ccw = if given with cp and 2 points takes the arc in the counter-clockwise direction. Default: false -// width = If given with `thickness`, ring is defined based on an arc with ends on X axis. -// thickness = If given with `width`, ring is defined based on an arc with ends on X axis, and this height above the X axis. +// width = If given with `thickness`, ring is defined based on an arc with ends on X axis. Must combine with `thickness` and one of `ring_width`, `r` or `d`. +// thickness = If given with `width`, ring is defined based on an arc with ends on X axis, and this height above the X axis. Must combine with `width` and one of`ring_width`, `r` or `d`. // start = Start angle of ring. Default: 0 // angle = If scalar, the end angle in degrees relative to start parameter. If a vector specifies start and end angles of ring. // anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). (Module only) Default: `CENTER` @@ -1577,7 +1584,7 @@ module egg(length,r1,r2,R,d1,d2,D,anchor=CENTER, spin=0) // corner = [[0,0],[4,4],[7,3]]; // ring(corner=corner, r=3, ring_width=1,n=22,full=false); // stroke(corner, width=.1,color="red"); -// Example(2D): +// Example(2D): Here the red dashed area shows the partial ring bounded by the specified width and thickness arc at the inside and then expanding by the ring width of 2. // $fn=128; // region = ring(width=5,thickness=1.5,ring_width=2); // path = ring(width=5,thickness=1.5,ring_width=2,full=false); @@ -1613,8 +1620,9 @@ function ring(n,ring_width,r,r1,r2,angle,d,d1,d2,cp,points,corner, width,thickne assert(is_undef(points) || is_path(points,2), str("Points must be a 2d vector",points)) assert(!any_defined([points,thickness,width]) || num_defined([r1,r2])==0, "Cannot give r1, r2, d1, or d2 with points, width or thickness") is_def(width) && is_def(thickness)? - assert(!any_defined([r,cp,points,angle,start]), "Conflicting or invalid parameters to ring") + assert(!any_defined([cp,points,angle,start]), "Can only give 'ring_width', 'r' or 'd' with 'width' and 'thickness'") assert(all_positive([width,thickness]), "Width and thickness must be positive") + assert(num_defined([r,ring_width])==1, "Must give 'r' or 'ring_width' (but not both) with 'width' and 'thickness'") ring(n=n,r=r,ring_width=ring_width,points=[[width/2,0], [0,thickness], [-width/2,0]],full=full) : full && is_undef(cp) && is_def(points) ? assert(is_def(points) && len(points)==3, "Without cp given, must provide exactly three points") diff --git a/turtle3d.scad b/turtle3d.scad index eee7a044..e234e1e3 100644 --- a/turtle3d.scad +++ b/turtle3d.scad @@ -31,7 +31,7 @@ function _rotpart(T) = [for(i=[0:3]) [for(j=[0:3]) j<3 || i==3 ? T[i][j] : 0]]; // Description: // Like the classic two dimensional turtle, the 3d turtle flies through space following a sequence // of turtle graphics commands to generate either a sequence of transformations (suitable for input -// to sweep) or a 3d path. The turtle state keeps track of the position and orientation (including twist) +// to {{sweep()}}) or a 3d path. The turtle state keeps track of the position and orientation (including twist) // and scale of the turtle. By default the turtle begins pointing along the X axis with the "right" direction // along the -Y axis and the "up" direction aligned with the Z axis. You can give a direction vector // for the state input to change the starting direction. Because of the complexity of object positioning @@ -43,15 +43,14 @@ function _rotpart(T) = [for(i=[0:3]) [for(j=[0:3]) j<3 || i==3 ? T[i][j] : 0]]; // to the turtle's current orientation. This is sometimes confusing, so you can also use absolute // commands which turn the turtle relative to the absolute coordinate system, the "xrot", "yrot" and "zrot" // commands. You can use "setdir" to point the turtle along a given vector. -// If you want a valid transformation list for use with sweep you will usually want to avoid abrupt changes +// If you want a valid transformation list for use with {{sweep()}} you will usually want to avoid abrupt changes // in the orientation of the turtle. To do this, use the "arc" // forms for turns. This form, with commands like "arcright" and "arcup" creates an arc with a gradual // change in the turtle orientation, which usually produces a better result for sweep operations. // . -// Another potential problem for sweep is a command that makes movements not relative to the turtle's current direction such as -// "jump" or "untily". These commands are not a problem for tracing out a path, but if you want a swept shape to -// maintain a constant cross sectional shape then you need to avoid them. operations and avoid the movement commands -// which do not move relative to the turtle direction such as the "jump" commands. +// Another potential problem for sweeps is a command that makes a movement that does not proceed in the turtle's current direction +// such as "jump" or "untily". These commands cause no issues when you trace out a path, but if you want a swept shape to +// maintain a constant cross sectional shape then you need to avoid them. // . // If you use sweep to convert a turtle path into a 3d shape the result depends both on the path the shape traces out but also // the twist and size of the shape. The "twist" parameter described below to the compound commands has no effect on @@ -65,7 +64,7 @@ function _rotpart(T) = [for(i=[0:3]) [for(j=[0:3]) j<3 || i==3 ? T[i][j] : 0]]; // turtle direction to point backwards. This enables you to back out to create a hollow shape. But be // aware that everything is reversed, so turns will be the opposite direction. So for example if you // used "arcright" on the outside you might expect arcleft when reversed on the inside, but it will -// be "arcright" again. (Note that "reverse" is the only command that appears by itself with no argument +// be "arcright" again. (Note that "reverse" is the only command that appears by itself with no argument.) // . // By default you get a simple path (like the 2d turtle) which ignores growing/shrinking or twisting in the // transformation. If you select transform=true then you will get a list of transformations returned. Some of @@ -97,7 +96,7 @@ function _rotpart(T) = [for(i=[0:3]) [for(j=[0:3]) j<3 || i==3 ? T[i][j] : 0]]; // "jump" | | point | Move the turtle to the specified point // "xjump" | | x | Move the turtle's x position to the specified value // "yjump | | y | Move the turtle's y position to the specified value -// "zjump | | y | Move the turtle's y position to the specified value +// "zjump | | z | Move the turtle's z position to the specified value // "left" | | [angle] | Turn turtle left by specified angle or default angle // "right" | | [angle] | Turn turtle to the right by specified angle or default angle // "up" | | [angle] | Turn turtle up by specified angle or default angle