From 98e21af201e78592bbada56ee499a2592b75f2cb Mon Sep 17 00:00:00 2001 From: Alex Matulich Date: Fri, 7 Mar 2025 17:23:38 -0800 Subject: [PATCH 1/9] Added missing args to metaballs usage section --- isosurface.scad | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/isosurface.scad b/isosurface.scad index ec39e5c2..fe464dab 100644 --- a/isosurface.scad +++ b/isosurface.scad @@ -1394,7 +1394,7 @@ function debug_tetra(r) = let(size=r/norm([1,1,1])) [ // Topics: Metaballs, Isosurfaces, VNF Generators // See Also: isosurface() // Usage: As a module -// metaballs(spec, bounding_box, voxel_size, [isovalue=], [closed=], [exact_bounds=], [convexity=], [show_stats=], ...) [ATTACHMENTS]; +// metaballs(spec, bounding_box, voxel_size, [isovalue=], [closed=], [exact_bounds=], [convexity=], [show_stats=], [show_box=], [debug=] ...) [ATTACHMENTS]; // Usage: As a function // vnf = metaballs(spec, bounding_box, voxel_size, [isovalue=], [closed=], [exact_bounds=], [convexity=], [show_stats=]); // Description: @@ -1963,7 +1963,7 @@ function debug_tetra(r) = let(size=r/norm([1,1,1])) [ // vsize = 0.85; // bbox = [[-45.5, -11.5, 0], [23, 11.5, 87.55]]; // metaballs(spec, bbox, voxel_size=vsize); -// Example(3D,Med,NoAxes,VPD=228,VPT=[1,-5,35]): A model of a bunny, made from separate body components made with metaballs, with each component rendered at a different voxel size, and then combined together along with eyes and teeth. In this way, smaller bounding boxes can be defined for each component, which speeds up rendering. A bit more time is saved by saving the repeated components (ear, front leg, hind leg) in VNF structures, to render copies with {{vnf_polyhedron()}}. +// Example(3D,Med,NoAxes,VPD=228,VPT=[1,-5,35]): A model of a bunny, assembled from separate body components made with metaballs, with each component rendered at a different voxel size, and then combined together along with eyes and teeth. In this way, smaller bounding boxes can be defined for each component, which speeds up rendering. A bit more time is saved by saving the repeated components (ear, front leg, hind leg) in VNF structures, to render copies with {{vnf_polyhedron()}}. // torso = [ // up(20) * scale([1,1.2,2]), mb_sphere(10), // up(10), mb_sphere(5) // fatten lower torso From 98c1cd143306e9526f31ebbbf96ae53a01e4f375 Mon Sep 17 00:00:00 2001 From: Alex Matulich Date: Fri, 7 Mar 2025 20:51:33 -0800 Subject: [PATCH 2/9] more doc corrections --- isosurface.scad | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/isosurface.scad b/isosurface.scad index fe464dab..e3467010 100644 --- a/isosurface.scad +++ b/isosurface.scad @@ -1509,12 +1509,12 @@ function debug_tetra(r) = let(size=r/norm([1,1,1])) [ // . // The built-in metaball functions are listed below. As usual, arguments without a trailing `=` can be used positionally; arguments with a trailing `=` must be used as named arguments. // . -// * `mb_sphere(r|d=)` — spherical metaball, with radius r or diameter d. You can create an ellipsoid using `scale()` as the last transformation entry of the metaball `spec` array. +// * `mb_sphere(r|d=)` — spherical metaball, with radius `r` or diameter `d`. You can create an ellipsoid using `scale()` as the last transformation entry of the metaball `spec` array. // * `mb_cuboid(size, [squareness=])` — cuboid metaball with rounded edges and corners. The corner sharpness is controlled by the `squareness` parameter ranging from 0 (spherical) to 1 (cubical), and defaults to 0.5. The `size` parameter specifies the dimensions of the cuboid that circumscribes the rounded shape, which is tangent to the center of each cube face. The `size` parameter may be a scalar or a vector, as in {{cuboid()}}. Except when `squareness=1`, the faces are always a little bit curved. -// * `mb_cyl(h|l|height|length, [r|d=], [r1=|d1=], [r2=|d2=], [rounding=])` — vertical cylinder or cone metaball with the same dimensional arguments as {{cyl()}}. At least one of the radius or diameter arguments is required. The `rounding` argument defaults to 0 (sharp edge) if not specified. Only one rounding value is allowed: the rounding is the same at both ends. For a fully rounded cylindrical shape, consider using `mb_capsule()` or `mb_disk()`, which are less flexible but have faster execution times. -// * `mb_disk(h|l|height|length, r|d=)` — flat disk with rounded edge. The diameter specifies the total diameter of the shape including the rounded sides, and must be greater than its height. +// * `mb_cyl(h|l|height|length, [r|d=], [r1=|d1=], [r2=|d2=], [rounding=])` — vertical cylinder or cone metaball with the same dimensional arguments as {{cyl()}}. At least one of the radius or diameter arguments is required. The `rounding` argument defaults to 0 (sharp edge) if not specified. Only one rounding value is allowed: the rounding is the same at both ends. For a fully rounded cylindrical shape, consider using `mb_disk()` or `mb_capsule()`, which are less flexible but have faster execution times. +// * `mb_disk(h|l|height|length, r|d=)` — flat disk with rounded edge, using the same dimensional arguments as {{cyl()}}. The diameter specifies the total diameter of the shape including the rounded sides, and must be greater than its height. // * `mb_capsule(h|l|height|length, [r|d=]` — vertical cylinder with rounded caps, using the same dimensional arguments as {{cyl()}}. The object resembles a convex hull of two spheres. The height or length specifies the distance between the spherical centers of the ends. -// * `mb_connector(p1, p2, [r|d=])` — a connecting rod of radius `r` or diameter `d` with hemispherical caps (like `mb_capsule()`), but specified to connect point `p1` to point `p2` (where `p1` and `p2` must be different 3D coordinates). As with `mb_capsule()`, the object resembles a convex hull of two spheres. The points `p1` and `p2` are at the centers of the two round caps. The connectors themselves are still influenced by other metaballs, but it may be undesirable to have them influence others, or each other. If two connectors are connected, the joint may appear swollen unless `influence` or `cutoff` is reduced. Reducing `cutoff` is preferable if feasible, because reducing `influence` can produce interpolation artifacts. +// * `mb_connector(p1, p2, [r|d=])` — a connecting rod of radius `r` or diameter `d` with hemispherical caps (like `mb_capsule()`), but specified to connect point `p1` to point `p2` (which must be different 3D coordinates). As with `mb_capsule()`, the object resembles a convex hull of two spheres. The points `p1` and `p2` are at the centers of the two round caps. The connectors themselves are still influenced by other metaballs, but it may be undesirable to have them influence others, or each other. If two connectors are connected, the joint may appear swollen unless `influence` or `cutoff` is reduced. Reducing `cutoff` is preferable if feasible, because reducing `influence` can produce interpolation artifacts. // * `mb_torus([r_maj|d_maj=], [r_min|d_min=], [or=|od=], [ir=|id=])` — torus metaball oriented perpendicular to the z axis. You can specify the torus dimensions using the same arguments as {{torus()}}; that is, major radius (or diameter) with `r_maj` or `d_maj`, and minor radius and diameter using `r_min` or `d_min`. Alternatively you can give the inner radius or diameter with `ir` or `id` and the outer radius or diameter with `or` or `od`. You must provide a combination of inputs that completely specifies the torus. If `cutoff` is applied, it is measured from the circle represented by `r_min=0`. // * `mb_octahedron(size, [squareness=])` — octahedron metaball with rounded edges and corners. The corner sharpness is controlled by the `squareness` parameter ranging from 0 (spherical) to 1 (sharp), and defaults to 0.5. The `size` parameter specifies the tip-to-tip distance of the octahedron that circumscribes the rounded shape, which is tangent to the center of each octahedron face. The `size` parameter may be a scalar or a vector, as in {{octahedron()}}. At `squareness=0`, the shape reduces to a sphere curcumscribed by the octahedron. Except when `squareness=1`, the faces are always curved. // . @@ -1546,7 +1546,7 @@ function debug_tetra(r) = let(size=r/norm([1,1,1])) [ // 0.5 you get a $1/d^2$ falloff. Changing this exponent changes how the balls interact. // . // You can pass a custom function as a [function literal](https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/User-Defined_Functions_and_Modules#Function_literals) -// that takes a 3-vector as its first argument and returns a single numerical value. In the `spec` array +// that takes a 3-vector as its first argument and returns a single numerical value. // Generally, the function should return a scalar value that drops below the isovalue somewhere within your // bounding box. If you want your custom metaball function to behave similar to to the built-in functions, // the return value should fall off with distance as $1/d$. See Examples 20, 21, and 22 for demonstrations @@ -1557,16 +1557,16 @@ function debug_tetra(r) = let(size=r/norm([1,1,1])) [ // . // The module form of `metaballs()` can take a `debug` argument. When you set `debug=true`, the scene is // rendered as a transparency with the primitive metaball shapes shown inside, colored blue for positive, -// orange for negative, and gray for unsigned metaballs. These shapes are displayed at the sizes specified by -// the dimensional parameters in the corresponding metaball functions, regardless of isovalue. Setting -// `hide_debug=true` in individual metaball functions hides primitive shape from the debug view. Regardless -// the `debug` setting, child modules can access the metaball VNF via `$metaball_vnf`. +// orange for negative, or gray for custom metaballs with no sign specified. These shapes are displayed at +// the sizes specified by the dimensional parameters in the corresponding metaball functions, regardless of +// isovalue. Setting `hide_debug=true` in individual metaball functions hides primitive shape from the debug +// view. Regardless the `debug` setting, child modules can access the metaball VNF via `$metaball_vnf`. // . // User-defined metaball functions are displayed by default as gray tetrahedrons with a corner radius of 5, // unless you also designate a VNF for your custom function. To specify a custom VNF for a custom function // literal, enclose it in square brackets to make a list with the function literal as the first element, and -// another list as the second element, for example: -// `[ function (point) custom_func(point, arg1,...), [sign, vnf] ]` +// another list as the second element, for example: +// `[ function (point) custom_func(point, arg1,...), [sign, vnf] ]` // where `sign` is the sign of the metaball and `vnf` is the VNF to show in the debug view when `debug=true`. // The sign determines the color of the debug object: `1` is blue, `-1` is orange, and `0` is gray. // Example 31 below demonstrates setting a VNF for a custom function. From c01f56dd04d5b3618534e4c31be047ad00bbc549 Mon Sep 17 00:00:00 2001 From: Revar Desmera Date: Fri, 7 Mar 2025 21:40:45 -0800 Subject: [PATCH 3/9] Removed cuboid() from VNF Generators topic. --- shapes3d.scad | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shapes3d.scad b/shapes3d.scad index f6e7f271..9d2243e2 100644 --- a/shapes3d.scad +++ b/shapes3d.scad @@ -93,7 +93,7 @@ function cube(size=1, center, anchor, spin=0, orient=UP) = // Module: cuboid() // Synopsis: Creates a cube with chamfering and roundovers. // SynTags: Geom -// Topics: Shapes (3D), Attachable, VNF Generators +// Topics: Shapes (3D), Attachable // See Also: prismoid(), rounded_prism() // Usage: Standard Cubes // cuboid(size, [anchor=], [spin=], [orient=]); From 8b45299187ca7ff4aedfd08e0ac6be16a5024e6d Mon Sep 17 00:00:00 2001 From: Revar Desmera Date: Fri, 7 Mar 2025 21:54:53 -0800 Subject: [PATCH 4/9] Minor docs fixes in shapes3d.scad --- shapes3d.scad | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shapes3d.scad b/shapes3d.scad index 9d2243e2..24ddd418 100644 --- a/shapes3d.scad +++ b/shapes3d.scad @@ -2424,7 +2424,7 @@ module zcyl( // id1 = Inner diameter of bottom of tube. // id2 = Inner diameter of top of tube. // ifn = Set the number of facets on the inside of the tube. -// circum = If true, the tube hold will circumscribe the circle of the given size. Otherwise inscribes. Default: `false` +// circum = If true, the tube hole will circumscribe the circle of the given size. Otherwise inscribes. Default: `false` // shift = [X,Y] amount to shift the center of the top end with respect to the center of the bottom end. // rounding = The radius of the rounding on the ends of the tube. Default: none. // rounding1 = The radius of the rounding on the bottom end of the tube. @@ -2474,8 +2474,8 @@ module zcyl( // back_half() // tube(ir=10,or=20,h=30, ochamfer1=-5,irounding1=-3, orounding2=6, ichamfer2=2); // Example: Tube with hexagonal hole circumscribing its diameter -// tube(od=22, id=9, h=10, $fn=48, ifn=4, circum=true); -// half_of(v=[-1,1])color("lightblue") cyl(d=9, h=12); +// tube(od=22, id=9, h=10, $fn=48, ifn=6, circum=true); +// half_of(v=[-1,1]) color("lightblue") cyl(d=9, h=12); // Example: Round ended hexagonal tube using `rounding_fn` to get sufficient facets on the roundings // tube(or=10, ir=7, h=10, $fn=6, rounding_fn=64, rounding=1.3, teardrop=true); From 0f43c11363e73d698172916bc4fc0ce9560ab74d Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Sat, 8 Mar 2025 07:56:12 -0500 Subject: [PATCH 5/9] doc tweak --- shapes3d.scad | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shapes3d.scad b/shapes3d.scad index 24ddd418..cde2cfdd 100644 --- a/shapes3d.scad +++ b/shapes3d.scad @@ -2473,9 +2473,9 @@ module zcyl( // Example: Mixing chamfers and roundings // back_half() // tube(ir=10,or=20,h=30, ochamfer1=-5,irounding1=-3, orounding2=6, ichamfer2=2); -// Example: Tube with hexagonal hole circumscribing its diameter -// tube(od=22, id=9, h=10, $fn=48, ifn=6, circum=true); -// half_of(v=[-1,1]) color("lightblue") cyl(d=9, h=12); +// Example: Tube with a square hole circumscribing its diameter +// tube(od=22, id=9, h=10, $fn=48, ifn=4, circum=true); +// half_of(v=[-1,1]) color("lightblue") cyl(d=9, h=12, $fn=32); // Example: Round ended hexagonal tube using `rounding_fn` to get sufficient facets on the roundings // tube(or=10, ir=7, h=10, $fn=6, rounding_fn=64, rounding=1.3, teardrop=true); From 9a0b8c42514826e71da2a853bb3a6f2c39685bcf Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Sat, 8 Mar 2025 08:44:05 -0500 Subject: [PATCH 6/9] fix tube function args --- shapes3d.scad | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shapes3d.scad b/shapes3d.scad index cde2cfdd..c172d9b2 100644 --- a/shapes3d.scad +++ b/shapes3d.scad @@ -2475,7 +2475,7 @@ module zcyl( // tube(ir=10,or=20,h=30, ochamfer1=-5,irounding1=-3, orounding2=6, ichamfer2=2); // Example: Tube with a square hole circumscribing its diameter // tube(od=22, id=9, h=10, $fn=48, ifn=4, circum=true); -// half_of(v=[-1,1]) color("lightblue") cyl(d=9, h=12, $fn=32); +// half_of(v=[-1,1]) color("lightblue") cyl(d=9, h=12, $fn=32y); // Example: Round ended hexagonal tube using `rounding_fn` to get sufficient facets on the roundings // tube(or=10, ir=7, h=10, $fn=6, rounding_fn=64, rounding=1.3, teardrop=true); @@ -2486,7 +2486,8 @@ function tube( ir1, ir2, id1, id2, realign=false, l, length, height, anchor, spin=0, orient=UP, orounding1,irounding1,orounding2,irounding2,rounding1,rounding2,rounding, - ochamfer1,ichamfer1,ochamfer2,ichamfer2,chamfer1,chamfer2,chamfer,irounding,ichamfer,orounding,ochamfer, teardrop=false + ochamfer1,ichamfer1,ochamfer2,ichamfer2,chamfer1,chamfer2,chamfer,irounding,ichamfer,orounding,ochamfer, teardrop=false, shift=[0,0], + ifn, rounding_fn, circum=false ) = no_function("tube"); @@ -2500,7 +2501,6 @@ module tube( anchor, spin=0, orient=UP, orounding1,irounding1,orounding2,irounding2,rounding1,rounding2,rounding, ochamfer1,ichamfer1,ochamfer2,ichamfer2,chamfer1,chamfer2,chamfer,irounding,ichamfer,orounding,ochamfer, teardrop=false, shift=[0,0], ifn, rounding_fn, circum=false - ) { h = one_defined([h,l,height,length],"h,l,height,length",dflt=1); orr1 = get_radius(r1=or1, r=or, d1=od1, d=od, dflt=undef); From 7383b5dfeebdd395828e8aca0408e90d4ad84291 Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Sat, 8 Mar 2025 09:19:51 -0500 Subject: [PATCH 7/9] fix typo --- shapes3d.scad | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shapes3d.scad b/shapes3d.scad index c172d9b2..57d26f8e 100644 --- a/shapes3d.scad +++ b/shapes3d.scad @@ -2475,7 +2475,7 @@ module zcyl( // tube(ir=10,or=20,h=30, ochamfer1=-5,irounding1=-3, orounding2=6, ichamfer2=2); // Example: Tube with a square hole circumscribing its diameter // tube(od=22, id=9, h=10, $fn=48, ifn=4, circum=true); -// half_of(v=[-1,1]) color("lightblue") cyl(d=9, h=12, $fn=32y); +// half_of(v=[-1,1]) color("lightblue") cyl(d=9, h=12, $fn=32); // Example: Round ended hexagonal tube using `rounding_fn` to get sufficient facets on the roundings // tube(or=10, ir=7, h=10, $fn=6, rounding_fn=64, rounding=1.3, teardrop=true); From f202cdb401381654ef5b364ee95ffccf7daee3c5 Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Sat, 8 Mar 2025 11:25:41 -0500 Subject: [PATCH 8/9] fix turtle3d example --- turtle3d.scad | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/turtle3d.scad b/turtle3d.scad index 01fecfff..eee7a044 100644 --- a/turtle3d.scad +++ b/turtle3d.scad @@ -343,7 +343,6 @@ function _rotpart(T) = [for(i=[0:3]) [for(j=[0:3]) j<3 || i==3 ? T[i][j] : 0]]; // cookie_shape = star(5, r=10, ir=5); // sweep(cookie_shape, cutter, closed=true); // Example(3D): angled shopvac adapter. Shopvac tubing wedges together because the tubes are slightly tapered. We can make this part without using any difference() operations by using "reverse" to trace out the interior portion of the part. Note that it's "arcright" even when reversed. -// include // inch = 25.4; // insert_ID = 2.3*inch; // Size of shopvac tube at larger end of taper // wall = 1.7; // Desired wall thickness @@ -368,7 +367,7 @@ function _rotpart(T) = [for(i=[0:3]) [for(j=[0:3]) j<3 || i==3 ? T[i][j] : 0]]; // ["move", seg1_len, "grow", seg1_bot_ID/seg2_bot_ID] // ], // state=UP, transforms=true); -// back_half(s=300) // Remove this to get a usable part +// back_half(s=400) // Remove this to get a usable part // sweep(circle(d=seg1_bot_OD, $fn=128), trans, closed=true); // Example(3D): Closed spiral // include From fc677a5c6db4f36adaa88286b224719ab681619f Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Mon, 10 Mar 2025 18:49:30 -0400 Subject: [PATCH 9/9] doc fixes --- attachments.scad | 4 ++-- drawing.scad | 8 ++++---- shapes2d.scad | 38 +++++++++++++++++++++++--------------- turtle3d.scad | 15 +++++++-------- 4 files changed, 36 insertions(+), 29 deletions(-) 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