From 5ae4f5bc2585d401ee72239fe0a45904146629b8 Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Sat, 22 Feb 2025 13:50:44 -0500 Subject: [PATCH 1/7] improve cuboid error handling --- shapes3d.scad | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/shapes3d.scad b/shapes3d.scad index 4afcaf6d..993e64cf 100644 --- a/shapes3d.scad +++ b/shapes3d.scad @@ -192,7 +192,7 @@ function cube(size=1, center, anchor, spin=0, orient=UP) = // cuboid(40) show_anchors(); module cuboid( - size=[1,1,1], + size, p1, p2, chamfer, rounding, @@ -331,8 +331,9 @@ module cuboid( } } } - - size = scalar_vec3(size); + sizecheck = assert(num_defined([size,p1,p2])!=3, "\nCannot give size if p2 is given (did you forget braces on the size argument?)") + assert(is_def(p1) || is_undef(p2), "If p2 is given you must also give p1"); + size = scalar_vec3(default(size,[1,1,1])); edges = _edges(edges, except=first_defined([except_edges,except])); teardrop = is_bool(teardrop)&&teardrop? 45 : teardrop; chamfer = approx(chamfer,0) ? undef : chamfer; @@ -344,8 +345,8 @@ module cuboid( assert(is_undef(rounding) || is_finite(rounding),"rounding must be a finite value") assert(is_undef(rounding) || is_undef(chamfer), "Cannot specify nonzero value for both chamfer and rounding") assert(teardrop==false || (is_finite(teardrop) && teardrop>0 && teardrop<=90), "teardrop must be either false or an angle number between 0 and 90") - assert(is_undef(p1) || is_vector(p1)) - assert(is_undef(p2) || is_vector(p2)) + assert(is_undef(p1) || is_vector(p1,3), "p1 must be a 3-vector") + assert(is_undef(p2) || is_vector(p2,3), "p2 must be a 3-vector") assert(is_bool(trimcorners)); if (!is_undef(p1)) { if (!is_undef(p2)) { From 86455b1624aeabab2535b21ec5bf7df152f8a087 Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Sun, 23 Feb 2025 16:09:24 -0500 Subject: [PATCH 2/7] improved size error handling, round3d docs & default size change --- distributors.scad | 12 +++++++----- geometry.scad | 10 +++++++--- math.scad | 6 +++--- miscellaneous.scad | 15 +++++++++------ shapes3d.scad | 35 +++++++++++++++++++---------------- utility.scad | 17 +++++++++++------ walls.scad | 5 +++-- 7 files changed, 59 insertions(+), 41 deletions(-) diff --git a/distributors.scad b/distributors.scad index 10881dd3..5122e3aa 100644 --- a/distributors.scad +++ b/distributors.scad @@ -448,7 +448,7 @@ function zcopies(spacing, n, l, sp, p=_NO_ARG) = // When called as a module, copies `children()` at one or more evenly spaced positions along a line. // By default, the line will be centered at the origin, unless the starting point `p1` is given. // The line will be pointed towards `RIGHT` (X+) unless otherwise given as a vector in `l`, -// `spacing`, or `p1`/`p2`. The psotion of the copies is specified in one of several ways: +// `spacing`, or `p1`/`p2`. The position of the copies is specified in one of several ways: // . // If You Know... | Then Use Something Like... // -------------------------------- | -------------------------------- @@ -520,6 +520,7 @@ module line_copies(spacing, n, l, p1, p2) function line_copies(spacing, n, l, p1, p2, p=_NO_ARG) = assert(is_undef(spacing) || is_finite(spacing) || is_vector(spacing)) + assert(!is_list(spacing) || len(spacing)==2 || len(spacing)==3, "Vector `spacing` must have length 2 or 3") assert(is_undef(n) || is_finite(n)) assert(is_undef(l) || is_finite(l) || is_vector(l)) assert(is_undef(p1) || is_vector(p1)) @@ -527,9 +528,11 @@ function line_copies(spacing, n, l, p1, p2, p=_NO_ARG) = assert(is_undef(p2) || is_def(p1), "If p2 is given must also give p1") assert(is_undef(p2) || is_undef(l), "Cannot give both p2 and l") assert(is_undef(n) || num_defined([l,spacing,p2])==1,"If n is given then must give exactly one of 'l', 'spacing', or the 'p1'/'p2' pair") - assert(is_def(n) || num_defined([l,spacing,p2])>=1,"If n is given then must give at least one of 'l', 'spacing', or the 'p1'/'p2' pair") + assert(is_def(n) || num_defined([l,spacing,p2])>=1,"If n is not given then must give at least one of 'l', 'spacing', or the 'p1'/'p2' pair") + assert(!(is_vector(spacing) && is_vector(l)), "Cannot give vector 'spacing' and vector 'l' value.") + assert(!(is_vector(spacing) && is_def(p2)), "Cannot combine vector 'spacing' with the 'p1'/'p2' pair") let( - ll = is_def(l)? scalar_vec3(l, 0) + ll = is_def(l)? scalar_vec3(l) : is_def(spacing) && is_def(n)? (n-1) * scalar_vec3(spacing, 0) : is_def(p1) && is_def(p2)? point3d(p2-p1) : undef, @@ -538,7 +541,7 @@ function line_copies(spacing, n, l, p1, p2, p=_NO_ARG) = : 2, spc = cnt<=1? [0,0,0] : is_undef(spacing) && is_def(ll)? ll/(cnt-1) - : is_num(spacing) && is_def(ll)? (ll/(cnt-1)) + : is_num(spacing) && is_def(ll)? ll/(cnt-1) : scalar_vec3(spacing, 0) ) assert(!is_undef(cnt), "Need two of `spacing`, 'l', 'n', or `p1`/`p2` arguments in `line_copies()`.") @@ -546,7 +549,6 @@ function line_copies(spacing, n, l, p1, p2, p=_NO_ARG) = [for (i=[0:1:cnt-1]) translate(i * spc + spos, p=p)]; - // Function&Module: grid_copies() // Synopsis: Places copies of children in an [X,Y] grid. // SynTags: MatList, Trans diff --git a/geometry.scad b/geometry.scad index c8271a3c..62f608b4 100644 --- a/geometry.scad +++ b/geometry.scad @@ -1907,8 +1907,8 @@ function _merge_segments(insegs,outsegs, eps, i=1) = // the input polygon. For 3d polygons, the triangle windings will induce a normal // vector with the same direction of the polygon normal. // . -// The function produce correct triangulations for some non-twisted non-simple polygons. -// A polygon is non-twisted iff it is simple or it has a partition in +// The function produces correct triangulations for some non-twisted non-simple polygons. +// A polygon is non-twisted if it is simple or it has a partition in // simple polygons with the same winding such that the intersection of any two partitions is // made of full edges and/or vertices of both partitions. These polygons may have "touching" vertices // (two vertices having the same coordinates, but distinct adjacencies) and "contact" edges @@ -1972,7 +1972,11 @@ function polygon_triangulate(poly, ind, error=true, eps=EPSILON) = len(ind) == 3 ? _degenerate_tri([poly[ind[0]], poly[ind[1]], poly[ind[2]]], eps) ? [] : // non zero area - let( degen = norm(scalar_vec3(cross(poly[ind[1]]-poly[ind[0]], poly[ind[2]]-poly[ind[0]]))) < 2*eps ) + let( + cp = cross(poly[ind[1]]-poly[ind[0]], poly[ind[2]]-poly[ind[0]]), + degen = is_num(cp) ? abs(cp) < 2*eps + : norm(cp) < 2*eps + ) assert( ! error || ! degen, "The polygon vertices are collinear.") degen ? undef : [ind] : len(poly[ind[0]]) == 3 diff --git a/math.scad b/math.scad index 272738aa..ffc11794 100644 --- a/math.scad +++ b/math.scad @@ -358,7 +358,6 @@ function sinh(x) = assert(is_finite(x), "The input must be a finite number.") (exp(x)-exp(-x))/2; - // Function: cosh() // Synopsis: Returns the hyperbolic cosine of the given value. // Topics: Math, Trigonometry @@ -378,10 +377,11 @@ function cosh(x) = // Usage: // a = tanh(x); // Description: Takes a value `x`, and returns the hyperbolic tangent of it. + function tanh(x) = assert(is_finite(x), "The input must be a finite number.") - sinh(x)/cosh(x); - + let (e = exp(2*x) + 1) + e == INF ? 1 : (e-2)/e; // Function: asinh() // Synopsis: Returns the hyperbolic arc-sine of the given value. diff --git a/miscellaneous.scad b/miscellaneous.scad index 31c7b180..8a59e77a 100644 --- a/miscellaneous.scad +++ b/miscellaneous.scad @@ -488,7 +488,7 @@ module chain_hull() // Synopsis: Removes diff shapes from base shape surface. // SynTags: Geom // Topics: Miscellaneous -// See Also: offset3d() +// See Also: offset3d(), round3d() // Usage: // minkowski_difference() { BASE; DIFF1; DIFF2; ... } // Description: @@ -536,14 +536,15 @@ module minkowski_difference(planar=false) { // Usage: // offset3d(r, [size], [convexity]) CHILDREN; // Description: -// Expands or contracts the surface of a 3D object by a given amount. This is very, very slow. +// Expands or contracts the surface of a 3D object by a given amount. The children must +// fit in a centered cube of the specified size. This is very, very slow. // No really, this is unbearably slow. It uses `minkowski()`. Use this as a last resort. // This is so slow that no example images will be rendered. // Arguments: // r = Radius to expand object by. Negative numbers contract the object. -// size = Maximum size of object to be contracted, given as a scalar. Default: 100 +// size = Scalar size of a centered cube containing the children. Default: 1000 // convexity = Max number of times a line could intersect the walls of the object. Default: 10 -module offset3d(r, size=100, convexity=10) { +module offset3d(r, size=1000, convexity=10) { req_children($children); n = quant(max(8,segs(abs(r))),4); attachable(){ @@ -589,14 +590,16 @@ module offset3d(r, size=100, convexity=10) { // Rounds arbitrary 3D objects. Giving `r` rounds all concave and convex corners. Giving just `ir` // rounds just concave corners. Giving just `or` rounds convex corners. Giving both `ir` and `or` // can let you round to different radii for concave and convex corners. The 3D object must not have -// any parts narrower than twice the `or` radius. Such parts will disappear. This is an *extremely* +// any parts narrower than twice the `or` radius. Such parts will disappear. The children must fit +// inside a cube of the specified size. This is an *extremely* // slow operation. I cannot emphasize enough just how slow it is. It uses `minkowski()` multiple times. // Use this as a last resort. This is so slow that no example images will be rendered. // Arguments: // r = Radius to round all concave and convex corners to. // or = Radius to round only outside (convex) corners to. Use instead of `r`. // ir = Radius to round only inside (concave) corners to. Use instead of `r`. -module round3d(r, or, ir, size=100) +// size = size of centered cube that contains the children. Default: 1000 +module round3d(r, or, ir, size=1000) { req_children($children); or = get_radius(r1=or, r=r, dflt=0); diff --git a/shapes3d.scad b/shapes3d.scad index 993e64cf..3a838b7c 100644 --- a/shapes3d.scad +++ b/shapes3d.scad @@ -58,8 +58,8 @@ use module cube(size=1, center, anchor, spin=0, orient=UP) { anchor = get_anchor(anchor, center, -[1,1,1], -[1,1,1]); - size = scalar_vec3(size); - attachable(anchor,spin,orient, size=size) { + size = force_list(size,3); // Native cube prints a warning and gives a unit cube when parameters are bogus + attachable(anchor,spin,orient, size=is_vector(size,3)?size:[1,1,1]) { _cube(size, center=true); children(); } @@ -67,18 +67,17 @@ module cube(size=1, center, anchor, spin=0, orient=UP) function cube(size=1, center, anchor, spin=0, orient=UP) = let( - siz = scalar_vec3(size) + size = force_list(size,3) ) - assert(all_positive(siz), "All size components must be positive.") + assert(is_vector(size,3), "\nSize parameter cannot be converted to a 3-vector") + assert(all_positive(size), "\nAll size components must be positive.") let( anchor = get_anchor(anchor, center, -[1,1,1], -[1,1,1]), unscaled = [ [-1,-1,-1],[1,-1,-1],[1,1,-1],[-1,1,-1], [-1,-1, 1],[1,-1, 1],[1,1, 1],[-1,1, 1], ]/2, - verts = is_num(size)? unscaled * size : - is_vector(size,3)? [for (p=unscaled) v_mul(p,size)] : - assert(is_num(size) || is_vector(size,3)), + verts = [for (p=unscaled) v_mul(p,size)], faces = [ [0,1,2], [0,2,3], //BOTTOM [0,4,5], [0,5,1], //FRONT @@ -87,7 +86,7 @@ function cube(size=1, center, anchor, spin=0, orient=UP) = [3,7,4], [3,4,0], //LEFT [6,4,7], [6,5,4] //TOP ] - ) [reorient(anchor,spin,orient, size=siz, p=verts), faces]; + ) [reorient(anchor,spin,orient, size=size, p=verts), faces]; @@ -333,13 +332,13 @@ module cuboid( } sizecheck = assert(num_defined([size,p1,p2])!=3, "\nCannot give size if p2 is given (did you forget braces on the size argument?)") assert(is_def(p1) || is_undef(p2), "If p2 is given you must also give p1"); - size = scalar_vec3(default(size,[1,1,1])); + size = default(force_list(size,3),[1,1,1]); edges = _edges(edges, except=first_defined([except_edges,except])); teardrop = is_bool(teardrop)&&teardrop? 45 : teardrop; chamfer = approx(chamfer,0) ? undef : chamfer; rounding = approx(rounding,0) ? undef : rounding; checks = - assert(is_vector(size,3)) + assert(is_vector(size,3),"Size must be a scalar or 3-vector") assert(all_nonnegative(size), "All components of size= must be >=0") assert(is_undef(chamfer) || is_finite(chamfer),"chamfer must be a finite value") assert(is_undef(rounding) || is_finite(rounding),"rounding must be a finite value") @@ -804,7 +803,7 @@ function prismoid( // When called as a module, creates an octahedron with axis-aligned points. // When called as a function, creates a [VNF](vnf.scad) of an octahedron with axis-aligned points. // Arguments: -// size = Width of the octahedron, tip to tip. +// size = Width of the octahedron, tip to tip. Can be a 3-vector. Default: [1,1,1] // --- // anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER` // spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0` @@ -813,6 +812,8 @@ function prismoid( // octahedron(size=40); // Example: Anchors // octahedron(size=40) show_anchors(); +// Example: +// octahedron([10,15,25]); module octahedron(size=1, anchor=CENTER, spin=0, orient=UP) { vnf = octahedron(size=size); @@ -824,8 +825,8 @@ module octahedron(size=1, anchor=CENTER, spin=0, orient=UP) { function octahedron(size=1, anchor=CENTER, spin=0, orient=UP) = let( - size = scalar_vec3(size), - s = size/2, + s = force_list(size,3)/2, + dummy=assert(is_vector(s,3) && all_positive(s), "\nsize must be a positive scalar or 3-vector"), vnf = [ [ [0,0,s.z], [s.x,0,0], [0,s.y,0], [-s.x,0,0], [0,-s.y,0], [0,0,-s.z] ], [ [0,2,1], [0,3,2], [0,4,3], [0,1,4], [5,1,2], [5,2,3], [5,3,4], [5,4,1] ] @@ -1482,7 +1483,7 @@ function rect_tube( // direction of the sloped edge. // // Arguments: -// size = [width, thickness, height] +// size = [width, thickness, height]. Default: [1,1,1] // 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.scad#subsection-anchor). Default: `FRONT+LEFT+BOTTOM` @@ -1509,7 +1510,8 @@ function rect_tube( module wedge(size=[1, 1, 1], center, anchor, spin=0, orient=UP) { - size = scalar_vec3(size); + size = force_list(size,3); + check=assert(is_vector(size,3) && all_positive(size), "\nsize must be a positive scalar or 3-vector"); anchor = get_anchor(anchor, center, -[1,1,1], -[1,1,1]); vnf = wedge(size, anchor="origin"); spindir = unit([0,-size.y,size.z]); @@ -1533,7 +1535,8 @@ module wedge(size=[1, 1, 1], center, anchor, spin=0, orient=UP) function wedge(size=[1,1,1], center, anchor, spin=0, orient=UP) = let( - size = scalar_vec3(size), + size = force_list(size,3), + check=assert(is_vector(size,3) && all_positive(size), "\nsize must be a positive scalar or 3-vector"), anchor = get_anchor(anchor, center, -[1,1,1], -[1,1,1]), pts = [ [ 1,1,-1], [ 1,-1,-1], [ 1,-1,1], diff --git a/utility.scad b/utility.scad index 2c544a74..bdaaa335 100644 --- a/utility.scad +++ b/utility.scad @@ -748,8 +748,9 @@ function get_radius(r1, r2, r, d1, d2, d, dflt) = // same way that OpenSCAD expands short vectors in some contexts, e.g. cube(10) or rotate([45,90]). // If `v` is a scalar, and `dflt==undef`, returns `[v, v, v]`. // If `v` is a scalar, and `dflt!=undef`, returns `[v, dflt, dflt]`. -// If `v` is a vector and dflt is defined, returns the first 3 items, with any missing values replaced by `dflt`. -// If `v` is a vector and dflt is undef, returns the first 3 items, with any missing values replaced by 0. +// if `v` is a list of length 3 or more then reutnrs `v` +// If `v` is a list and dflt is defined, returns a length 3 list by padding with `dflt` +// If `v` is a list and dflt is undef, returns a length 3 list by padding with 0. // If `v` is `undef`, returns `undef`. // Arguments: // v = Value to return vector from. @@ -761,10 +762,14 @@ function get_radius(r1, r2, r, d1, d2, d, dflt) = // vec = scalar_vec3([10,10],1); // Returns: [10,10,1] // vec = scalar_vec3([10,10]); // Returns: [10,10,0] // vec = scalar_vec3([10]); // Returns: [10,0,0] -function scalar_vec3(v, dflt) = - is_undef(v)? undef : - is_list(v)? [for (i=[0:2]) default(v[i], default(dflt, 0))] : - !is_undef(dflt)? [v,dflt,dflt] : [v,v,v]; +function scalar_vec3(v, dflt) = + is_undef(v)? undef + : + is_list(v)? len(v)>=3 ? v + : [for (i=[0:2]) default(v[i], default(dflt, 0))] + : + !is_undef(dflt) ? [v,dflt,dflt] + : [v,v,v]; // Function: segs() // Synopsis: Returns the number of sides for a circle given `$fn`, `$fa`, and `$fs`. diff --git a/walls.scad b/walls.scad index 563c6812..810bb1c1 100644 --- a/walls.scad +++ b/walls.scad @@ -193,8 +193,9 @@ module sparse_cuboid(size, dir=RIGHT, strut=5, maxang=30, max_bridge=20, teardrop=false, anchor=CENTER, spin=0, orient=UP) { - size = scalar_vec3(size); - dummy1=assert(in_list(dir,["X","Y","Z"]) || is_vector(dir,3), "dir must be a 3-vector or one of \"X\", \"Y\", or \"Z\""); + size = force_list(size,3); + dummy1= assert(is_vector(size,3) && all_positive(size), "size must be a positive number or 3-vector") + assert(in_list(dir,["X","Y","Z"]) || is_vector(dir,3), "dir must be a 3-vector or one of \"X\", \"Y\", or \"Z\""); count = len([for(d=dir) if (d!=0) d]); dummy2=assert(is_string(dir) || (count==1 && len(dir)<=3), "vector valued dir must have exactly one non-zero component"); dir = is_string(dir) ? dir From d6041f1878ec78b822a3d14e09629262066ca784 Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Sun, 23 Feb 2025 16:14:28 -0500 Subject: [PATCH 3/7] revert scalar_vec3 --- utility.scad | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/utility.scad b/utility.scad index bdaaa335..3c90a0dd 100644 --- a/utility.scad +++ b/utility.scad @@ -748,9 +748,9 @@ function get_radius(r1, r2, r, d1, d2, d, dflt) = // same way that OpenSCAD expands short vectors in some contexts, e.g. cube(10) or rotate([45,90]). // If `v` is a scalar, and `dflt==undef`, returns `[v, v, v]`. // If `v` is a scalar, and `dflt!=undef`, returns `[v, dflt, dflt]`. -// if `v` is a list of length 3 or more then reutnrs `v` +// if `v` is a list of length 3 or more then returns `v` // If `v` is a list and dflt is defined, returns a length 3 list by padding with `dflt` -// If `v` is a list and dflt is undef, returns a length 3 list by padding with 0. +// If `v` is a list and dflt is undef, returns a length 3 list by padding with 0 // If `v` is `undef`, returns `undef`. // Arguments: // v = Value to return vector from. @@ -762,14 +762,10 @@ function get_radius(r1, r2, r, d1, d2, d, dflt) = // vec = scalar_vec3([10,10],1); // Returns: [10,10,1] // vec = scalar_vec3([10,10]); // Returns: [10,10,0] // vec = scalar_vec3([10]); // Returns: [10,0,0] -function scalar_vec3(v, dflt) = - is_undef(v)? undef - : - is_list(v)? len(v)>=3 ? v - : [for (i=[0:2]) default(v[i], default(dflt, 0))] - : - !is_undef(dflt) ? [v,dflt,dflt] - : [v,v,v]; +function scalar_vec3(v, dflt) = + is_undef(v)? undef : + is_list(v)? [for (i=[0:2]) default(v[i], default(dflt, 0))] : + !is_undef(dflt)? [v,dflt,dflt] : [v,v,v]; // Function: segs() // Synopsis: Returns the number of sides for a circle given `$fn`, `$fa`, and `$fs`. From 2df5a0943859d11ef60c33bdd33c7a580fd84313 Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Sun, 23 Feb 2025 16:41:44 -0500 Subject: [PATCH 4/7] bugfix --- distributors.scad | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distributors.scad b/distributors.scad index 5122e3aa..49a6ea13 100644 --- a/distributors.scad +++ b/distributors.scad @@ -532,7 +532,7 @@ function line_copies(spacing, n, l, p1, p2, p=_NO_ARG) = assert(!(is_vector(spacing) && is_vector(l)), "Cannot give vector 'spacing' and vector 'l' value.") assert(!(is_vector(spacing) && is_def(p2)), "Cannot combine vector 'spacing' with the 'p1'/'p2' pair") let( - ll = is_def(l)? scalar_vec3(l) + ll = is_def(l)? scalar_vec3(l, 0) : is_def(spacing) && is_def(n)? (n-1) * scalar_vec3(spacing, 0) : is_def(p1) && is_def(p2)? point3d(p2-p1) : undef, From cf5bfa0f3b99c641cfc4c343bfe747614bd9feee Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Sun, 23 Feb 2025 18:06:57 -0500 Subject: [PATCH 5/7] handle undef properly in cuboid --- lists.scad | 2 +- shapes3d.scad | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lists.scad b/lists.scad index 6ccb8a6e..47d6844a 100644 --- a/lists.scad +++ b/lists.scad @@ -461,7 +461,7 @@ function list(l) = is_list(l)? l : [for (x=l) x]; // Arguments: // value = The value or list to coerce into a list. // n = The number of items in the coerced list. Default: 1 -// fill = The value to pad the coerced list with, after the firt value. Default: undef (pad with copies of `value`) +// fill = The value to pad the coerced list with, after the first value. Default: undef (pad with copies of `value`) // Example: // x = force_list([3,4,5]); // Returns: [3,4,5] // y = force_list(5); // Returns: [5] diff --git a/shapes3d.scad b/shapes3d.scad index 3a838b7c..27522c4a 100644 --- a/shapes3d.scad +++ b/shapes3d.scad @@ -332,7 +332,7 @@ module cuboid( } sizecheck = assert(num_defined([size,p1,p2])!=3, "\nCannot give size if p2 is given (did you forget braces on the size argument?)") assert(is_def(p1) || is_undef(p2), "If p2 is given you must also give p1"); - size = default(force_list(size,3),[1,1,1]); + size = force_list(default(size,1),3); edges = _edges(edges, except=first_defined([except_edges,except])); teardrop = is_bool(teardrop)&&teardrop? 45 : teardrop; chamfer = approx(chamfer,0) ? undef : chamfer; From 704406cc726eabfeb804d3a6d048745b68f5402b Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Sun, 23 Feb 2025 18:42:13 -0500 Subject: [PATCH 6/7] vector spacing / line conflict issue resolution --- distributors.scad | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distributors.scad b/distributors.scad index 49a6ea13..4d7fa7eb 100644 --- a/distributors.scad +++ b/distributors.scad @@ -529,7 +529,7 @@ function line_copies(spacing, n, l, p1, p2, p=_NO_ARG) = assert(is_undef(p2) || is_undef(l), "Cannot give both p2 and l") assert(is_undef(n) || num_defined([l,spacing,p2])==1,"If n is given then must give exactly one of 'l', 'spacing', or the 'p1'/'p2' pair") assert(is_def(n) || num_defined([l,spacing,p2])>=1,"If n is not given then must give at least one of 'l', 'spacing', or the 'p1'/'p2' pair") - assert(!(is_vector(spacing) && is_vector(l)), "Cannot give vector 'spacing' and vector 'l' value.") + assert(!(is_vector(spacing) && is_vector(l) && vector_angle(spacing,l)>EPSILON), "Cannot give conflicting vector 'spacing' and vector 'l' value.") assert(!(is_vector(spacing) && is_def(p2)), "Cannot combine vector 'spacing' with the 'p1'/'p2' pair") let( ll = is_def(l)? scalar_vec3(l, 0) From 2c19cb0b9643145216cebd50c366ab9b375348c3 Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Sun, 23 Feb 2025 19:11:03 -0500 Subject: [PATCH 7/7] doc fix --- shapes3d.scad | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shapes3d.scad b/shapes3d.scad index 27522c4a..e2ebfefa 100644 --- a/shapes3d.scad +++ b/shapes3d.scad @@ -330,7 +330,7 @@ module cuboid( } } } - sizecheck = assert(num_defined([size,p1,p2])!=3, "\nCannot give size if p2 is given (did you forget braces on the size argument?)") + sizecheck = assert(num_defined([size,p1,p2])!=3, "\nCannot give size if p2 is given (did you forget brackets on the size argument?)") assert(is_def(p1) || is_undef(p2), "If p2 is given you must also give p1"); size = force_list(default(size,1),3); edges = _edges(edges, except=first_defined([except_edges,except]));