From a8522854e4f4780358de8db845497a5b1bbde6e5 Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Thu, 27 Aug 2020 17:07:12 -0400 Subject: [PATCH 1/7] small tweak to hide two functions --- polyhedra.scad | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/polyhedra.scad b/polyhedra.scad index 3231606..13cbe54 100644 --- a/polyhedra.scad +++ b/polyhedra.scad @@ -652,7 +652,7 @@ function regular_polyhedron_info( let( entry = ( name == "trapezohedron"? ( - trapezohedron(faces=faces, side=side, longside=longside, h=h, r=r) + _trapezohedron(faces=faces, side=side, longside=longside, h=h, r=r) ) : ( _polyhedra_[!is_undef(index)? indexlist[index] : @@ -671,7 +671,7 @@ function regular_polyhedron_info( ) / entry[edgelen] ), face_triangles = hull(entry[vertices]), - faces_normals_vertices = stellate_faces( + faces_normals_vertices = _stellate_faces( entry[edgelen], stellate, entry[vertices], entry[facevertices]==[3]? [face_triangles, [for(face=face_triangles) _facenormal(entry[vertices],face)]] : @@ -713,11 +713,7 @@ function regular_polyhedron_info( assert(false, str("Unknown info type '",info,"' requested")); - -/// hull solution fails due to roundoff -/// either cross product or just rotate to -/// -function stellate_faces(scalefactor,stellate,vertices,faces_normals) = +function _stellate_faces(scalefactor,stellate,vertices,faces_normals) = (stellate == false || stellate == 0)? concat(faces_normals,[vertices]) : let( faces = [for(face=faces_normals[0]) select(face,hull(select(vertices,face)))], @@ -730,8 +726,8 @@ function stellate_faces(scalefactor,stellate,vertices,faces_normals) = ) [newfaces, normals, allpts]; -function trapezohedron(faces, r, side, longside, h, d) = - assert(faces%2==0, "Number of faces must be even") +function _trapezohedron(faces, r, side, longside, h, d) = + assert(faces%2==0, "Must set 'faces' to an even number for trapezohedron") let( r = get_radius(r=r, d=d, dflt=1), N = faces/2, From c1782f11132431c83034fc4b4ed3859fdb7cf20c Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Thu, 27 Aug 2020 19:25:41 -0400 Subject: [PATCH 2/7] added no_children checks, and attachable to vnf_polyhedron --- common.scad | 3 +++ strings.scad | 6 ++++-- structs.scad | 1 + version.scad | 1 + vnf.scad | 11 +++++++++-- 5 files changed, 18 insertions(+), 4 deletions(-) diff --git a/common.scad b/common.scad index db4f3bb..570ff8e 100644 --- a/common.scad +++ b/common.scad @@ -353,6 +353,7 @@ function segs(r) = // Arguments: // $children = number of children the module has. module no_children(count) { + assert($children==0, "Module no_children() does not support child modules"); assert(count==0, str("Module ",parent_module(1),"() does not support child modules")); } @@ -377,6 +378,7 @@ function _valstr(x) = // expected = The value that was expected. // info = Extra info to print out to make the error clearer. module assert_approx(got, expected, info) { + no_children($children); if (!approx(got, expected)) { echo(); echo(str("EXPECT: ", _valstr(expected))); @@ -404,6 +406,7 @@ module assert_approx(got, expected, info) { // expected = The value that was expected. // info = Extra info to print out to make the error clearer. module assert_equal(got, expected, info) { + no_children($children); if (got != expected || (is_nan(got) && is_nan(expected))) { echo(); echo(str("EXPECT: ", _valstr(expected))); diff --git a/strings.scad b/strings.scad index cc0713b..5e34fd9 100644 --- a/strings.scad +++ b/strings.scad @@ -701,7 +701,9 @@ function str_format(fmt, vals, use_nbsp=false) = // echofmt("{:-10s}{:.3f}", ["plecostamus",27.43982]); // ECHO: "plecostamus27.440" // echofmt("{:-10.9s}{:.3f}", ["plecostamus",27.43982]); // ECHO: "plecostam 27.440" function echofmt(fmt, vals, use_nbsp=false) = echo(str_format(fmt,vals,use_nbsp)); -module echofmt(fmt, vals, use_nbsp=false) echo(str_format(fmt,vals,use_nbsp)); - +module echofmt(fmt, vals, use_nbsp=false) { + no_children($children); + echo(str_format(fmt,vals,use_nbsp)); +} // vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap diff --git a/structs.scad b/structs.scad index e7effb4..1e9f321 100644 --- a/structs.scad +++ b/structs.scad @@ -101,6 +101,7 @@ function struct_echo(struct,name="") = undef; module struct_echo(struct,name="") { + no_children($children); dummy = struct_echo(struct,name); } diff --git a/version.scad b/version.scad index d10b338..b37d43f 100644 --- a/version.scad +++ b/version.scad @@ -49,6 +49,7 @@ function bosl_version_str() = version_to_str(BOSL_VERSION); // Description: // Given a version as a list, number, or string, asserts that the currently installed BOSL library is at least the given version. module bosl_required(target) { + no_children($children); assert( version_cmp(bosl_version(), target) >= 0, str( diff --git a/vnf.scad b/vnf.scad index 05fd82f..edf00e4 100644 --- a/vnf.scad +++ b/vnf.scad @@ -341,9 +341,16 @@ function vnf_vertex_array( // Arguments: // vnf = A VNF structure, or list of VNF structures. // convexity = Max number of times a line could intersect a wall of the shape. -module vnf_polyhedron(vnf, convexity=2) { +module vnf_polyhedron(vnf, + convexity=10,anchor="origin",cp, + spin=0, orient=UP, extent=false +) +{ vnf = is_vnf_list(vnf)? vnf_merge(vnf) : vnf; - polyhedron(vnf[0], vnf[1], convexity=convexity); + attachable(anchor=anchor, spin=spin, orient=orient, vnf=vnf, extent=extent, cp=is_def(cp) ? cp : vnf_centroid(vnf)){ + polyhedron(vnf[0], vnf[1], convexity=convexity); + children(); + } } From 411c1f866eea5f83b51e0569e9d852e1385f27a2 Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Thu, 27 Aug 2020 19:48:13 -0400 Subject: [PATCH 3/7] fixed missing ; bug in test_transforms.scad --- tests/test_transforms.scad | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_transforms.scad b/tests/test_transforms.scad index a44e47c..3fb044b 100644 --- a/tests/test_transforms.scad +++ b/tests/test_transforms.scad @@ -232,7 +232,7 @@ module test_rot() { assert_equal(rot(a,p=pts2d), pts2d, info=str("rot(",a,",p=...), 2D")); assert_equal(rot(a,p=pts3d), pts3d, info=str("rot(",a,",p=...), 3D")); } - assert_equal(rot(90), [[0,-1,0,0],[1,0,0,0],[0,0,1,0],[0,0,0,1]]) + assert_equal(rot(90), [[0,-1,0,0],[1,0,0,0],[0,0,1,0],[0,0,0,1]]); for (a=angs) { assert_equal(rot(a), affine3d_zrot(a), info=str("Z angle (only) = ",a)); assert_equal(rot([a,0,0]), affine3d_xrot(a), info=str("X angle = ",a)); From e344de4aa475a67465559c7b0319b161b2824efb Mon Sep 17 00:00:00 2001 From: Garth Minette Date: Thu, 27 Aug 2020 22:29:11 -0700 Subject: [PATCH 4/7] Added cheat-sheet generation script. --- scripts/gencheat.sh | 91 +++++++++++++++++++++++++++++++++++++++++++++ version.scad | 2 +- 2 files changed, 92 insertions(+), 1 deletion(-) create mode 100755 scripts/gencheat.sh diff --git a/scripts/gencheat.sh b/scripts/gencheat.sh new file mode 100755 index 0000000..fb03406 --- /dev/null +++ b/scripts/gencheat.sh @@ -0,0 +1,91 @@ +#!/bin/bash + + +function ucase +{ + echo "$1" | tr '[:lower:]' '[:upper:]' +} + +function lcase +{ + echo "$1" | tr '[:upper:]' '[:lower:]' +} + +function columnize +{ + cols=4 + TMPFILE=$(mktemp -t $(basename $0).XXXXXX) || exit 1 + cat >>$TMPFILE + totcnt=$(wc -l $TMPFILE | awk '{print $1}') + maxrows=$((($totcnt+$cols-1)/$cols)) + maxcols=$cols + if [[ $maxcols -gt $totcnt ]] ; then + maxcols=$totcnt + fi + cnt=0 + hdrln1="| $(ucase $1) " + hdrln2='|:-----' + n=1 + while [[ $n < $maxcols ]] ; do + hdrln1+=' |  ' + hdrln2+=' |:------' + n=$(($n+1)) + done + hdrln1+=' |' + hdrln2+=' |' + n=0 + while [[ $n < $maxrows ]] ; do + lines[$n]="" + n=$(($n+1)) + done + col=0 + while IFS= read -r line; do + if [[ $col != 0 ]] ; then + lines[$cnt]+=" | " + fi + lines[$cnt]+="$line" + cnt=$(($cnt+1)) + if [[ $cnt = $maxrows ]] ; then + cnt=0 + col=$(($col+1)) + fi + done <$TMPFILE + rm -f $TMPFILE + + echo + echo $hdrln1 + echo $hdrln2 + n=0 + while [[ $n < $maxrows ]] ; do + echo "| ${lines[$n]} |" + n=$(($n+1)) + done +} + +function mkconstindex +{ + sed 's/([^)]*)//g' | sed 's/[^a-zA-Z0-9_.:$]//g' | awk -F ':' '{printf "[%s](%s#%s)\n", $3, $1, $3}' +} + +function mkotherindex +{ + sed 's/([^)]*)//g' | sed 's/[^a-zA-Z0-9_.:$]//g' | awk -F ':' '{printf "[%s()](%s#%s)\n", $3, $1, $3}' +} + +CHEAT_FILES=$(grep '^include' std.scad | sed 's/^.*<\([a-zA-Z0-9.]*\)>/\1/'|grep -v 'version.scad') + +( + echo '## Belfry OpenScad Library Cheat Sheet' + echo + echo '( [Alphabetic Index](Index.md) )' + echo + for f in $CHEAT_FILES ; do + #echo "### $f" + ( + egrep -H 'Constant: ' $f | mkconstindex + egrep -H 'Function: |Function&Module: |Module: ' $f | mkotherindex + ) | columnize $f + echo + done +) > BOSL2.wiki/CheatSheet.md + diff --git a/version.scad b/version.scad index d10b338..61bf5a8 100644 --- a/version.scad +++ b/version.scad @@ -8,7 +8,7 @@ ////////////////////////////////////////////////////////////////////// -BOSL_VERSION = [2,0,410]; +BOSL_VERSION = [2,0,412]; // Section: BOSL Library Version Functions From 7051f8ef19b6d077f49b19dd25c9fa463559c5c5 Mon Sep 17 00:00:00 2001 From: Garth Minette Date: Fri, 28 Aug 2020 00:06:28 -0700 Subject: [PATCH 5/7] Fixed cheatsheet index link. --- scripts/gencheat.sh | 2 +- version.scad | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/gencheat.sh b/scripts/gencheat.sh index fb03406..6762f0a 100755 --- a/scripts/gencheat.sh +++ b/scripts/gencheat.sh @@ -77,7 +77,7 @@ CHEAT_FILES=$(grep '^include' std.scad | sed 's/^.*<\([a-zA-Z0-9.]*\)>/\1/'|grep ( echo '## Belfry OpenScad Library Cheat Sheet' echo - echo '( [Alphabetic Index](Index.md) )' + echo '( [Alphabetic Index](Index) )' echo for f in $CHEAT_FILES ; do #echo "### $f" diff --git a/version.scad b/version.scad index 61bf5a8..55a670a 100644 --- a/version.scad +++ b/version.scad @@ -8,7 +8,7 @@ ////////////////////////////////////////////////////////////////////// -BOSL_VERSION = [2,0,412]; +BOSL_VERSION = [2,0,413]; // Section: BOSL Library Version Functions From e1b0985afcde7e4821ec19f849b425ea859e7eaf Mon Sep 17 00:00:00 2001 From: Garth Minette Date: Fri, 28 Aug 2020 19:07:10 -0700 Subject: [PATCH 6/7] Fixed broken line-plane intersections. Attachment enhanced vnf_polyhedron(). --- attachments.scad | 15 +++++++++------ geometry.scad | 26 +++++++++++++++++--------- tests/test_geometry.scad | 13 ++++++++++++- version.scad | 2 +- vnf.scad | 12 ++++++++++-- 5 files changed, 49 insertions(+), 19 deletions(-) diff --git a/attachments.scad b/attachments.scad index 48ed522..ae93412 100644 --- a/attachments.scad +++ b/attachments.scad @@ -461,13 +461,16 @@ function find_anchor(anchor, geom) = rpts = apply(rot(from=anchor, to=RIGHT) * move(point3d(-cp)), points), hits = [ for (face = faces) let( - verts = select(rpts, face) + verts = select(rpts, face), + xs = subindex(verts,0), + ys = subindex(verts,1), + zs = subindex(verts,2) ) if ( - max(subindex(verts,0)) >= -eps && - max(subindex(verts,1)) >= -eps && - max(subindex(verts,2)) >= -eps && - min(subindex(verts,1)) <= eps && - min(subindex(verts,2)) <= eps + max(xs) >= -eps && + max(ys) >= -eps && + max(zs) >= -eps && + min(ys) <= eps && + min(zs) <= eps ) let( poly = select(points, face), pt = polygon_line_intersection(poly, [cp,cp+anchor], bounded=[true,false], eps=eps) diff --git a/geometry.scad b/geometry.scad index dc86187..0ab9f73 100644 --- a/geometry.scad +++ b/geometry.scad @@ -1007,11 +1007,20 @@ function closest_point_on_plane(plane, point) = // Returns [LINE, undef] if the line is on the plane. // Returns undef if line is parallel to, but not on the given plane. function _general_plane_line_intersection(plane, line, eps=EPSILON) = - let( a = plane*[each line[0],-1], - b = plane*[each(line[1]-line[0]),-1] ) - approx(b,0,eps) - ? points_on_plane(line[0],plane,eps)? [line,undef]: undef - : [ line[0]+a/b*(line[1]-line[0]), a/b ]; + let( + l0 = line[0], // Ray start point + u = line[1] - l0, // Ray direction vector + n = plane_normal(plane), + p0 = n * plane[3], // A point on the plane + w = l0 - p0 // Vector from plane point to ray start + ) approx(n*u, 0, eps=eps) ? ( + // Line is parallel to plane. + approx(n*w, 0, eps=eps) + ? [line, undef] // Line is on the plane. + : undef // Line never intersects the plane. + ) : let( + t = (-n * w) / (n * u) // Distance ratio along ray + ) [ l0 + u*t, t ]; // Function: plane_line_angle() @@ -1098,8 +1107,8 @@ function polygon_line_intersection(poly, line, bounded=false, eps=EPSILON) = linevec = unit(line[1] - line[0]), lp1 = line[0] + (bounded[0]? 0 : -1000000) * linevec, lp2 = line[1] + (bounded[1]? 0 : 1000000) * linevec, - poly2d = clockwise_polygon(project_plane(poly, p1, p2, p3)), - line2d = project_plane([lp1,lp2], p1, p2, p3), + poly2d = clockwise_polygon(project_plane(poly, plane)), + line2d = project_plane([lp1,lp2], plane), parts = split_path_at_region_crossings(line2d, [poly2d], closed=false), inside = [for (part = parts) if (point_in_polygon(mean(part), poly2d)>0) part @@ -1107,7 +1116,7 @@ function polygon_line_intersection(poly, line, bounded=false, eps=EPSILON) = ) !inside? undef : let( - isegs = [for (seg = inside) lift_plane(seg, p1, p2, p3) ] + isegs = [for (seg = inside) lift_plane(seg, plane) ] ) isegs ) @@ -1264,7 +1273,6 @@ function find_circle_2tangents(pt1, pt2, pt3, r, d, tangents=false) = x = hyp * cos(a/2), tp1 = pt2 + x * v1, tp2 = pt2 + x * v2, -// fff=echo(tp1=tp1,cp=cp,pt2=pt2), dang1 = vector_angle(tp1-cp,pt2-cp), dang2 = vector_angle(tp2-cp,pt2-cp) ) diff --git a/tests/test_geometry.scad b/tests/test_geometry.scad index 0950e1c..e69a8ac 100644 --- a/tests/test_geometry.scad +++ b/tests/test_geometry.scad @@ -53,7 +53,7 @@ test_tri_functions(); //test__general_plane_line_intersection(); //test_plane_line_angle(); //test_plane_line_intersection(); -//test_polygon_line_intersection(); +test_polygon_line_intersection(); //test_plane_intersection(); test_coplanar(); test_points_on_plane(); @@ -542,6 +542,17 @@ module test_distance_from_plane() { *test_distance_from_plane(); +module test_polygon_line_intersection() { + poly1 = [[50,50,50], [50,-50,50], [-50,-50,50]]; + assert_approx(polygon_line_intersection(poly1, [CENTER, UP]), [0,0,50]); + assert_approx(polygon_line_intersection(poly1, [CENTER, UP+RIGHT]), [50,0,50]); + assert_approx(polygon_line_intersection(poly1, [CENTER, UP+BACK+RIGHT]), [50,50,50]); + assert_approx(polygon_line_intersection(poly1, [[0,0,50], [1,0,50]]), [[[0,0,50], [50,0,50]]]); + assert_approx(polygon_line_intersection(poly1, [[0,0,0], [1,0,0]]), undef); +} +*test_polygon_line_intersection(); + + module test_coplanar() { assert(coplanar([ [5,5,1],[0,0,1],[-1,-1,1] ]) == false); assert(coplanar([ [5,5,1],[0,0,0],[-1,-1,1] ]) == true); diff --git a/version.scad b/version.scad index 55a670a..6e4605f 100644 --- a/version.scad +++ b/version.scad @@ -8,7 +8,7 @@ ////////////////////////////////////////////////////////////////////// -BOSL_VERSION = [2,0,413]; +BOSL_VERSION = [2,0,414]; // Section: BOSL Library Version Functions diff --git a/vnf.scad b/vnf.scad index 05fd82f..b0a5607 100644 --- a/vnf.scad +++ b/vnf.scad @@ -341,9 +341,17 @@ function vnf_vertex_array( // Arguments: // vnf = A VNF structure, or list of VNF structures. // convexity = Max number of times a line could intersect a wall of the shape. -module vnf_polyhedron(vnf, convexity=2) { +// extent = If true, calculate anchors by extents, rather than intersection. Default: true. +// cp = Centerpoint of VNF to use for anchoring when `extent` is false. Default: `[0, 0, 0]` +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `"origin"` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#orient). Default: `UP` +module vnf_polyhedron(vnf, convexity=2, extent=true, cp=[0,0,0], anchor="origin", spin=0, orient=UP) { vnf = is_vnf_list(vnf)? vnf_merge(vnf) : vnf; - polyhedron(vnf[0], vnf[1], convexity=convexity); + attachable(anchor,spin,orient, vnf=vnf, cp=cp, extent=extent) { + polyhedron(vnf[0], vnf[1], convexity=convexity); + children(); + } } From 2eb0ce034854e57654d45dda370440c423f10d99 Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Fri, 28 Aug 2020 23:16:11 -0400 Subject: [PATCH 7/7] added os_mask to rounding and tweaked error messages in transpose --- arrays.scad | 26 ++++++++++++++------------ rounding.scad | 24 +++++++++++++++++++++++- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/arrays.scad b/arrays.scad index 835fd65..a6d43d1 100644 --- a/arrays.scad +++ b/arrays.scad @@ -1286,10 +1286,12 @@ function array_dim(v, depth=undef) = // Function: transpose() -// Description: Returns the transposition of the given array. -// When reverse=true, the transposition is done in respect to the secondary diagonal, that is: -// . -// reverse(transpose(reverse(arr))) == transpose(arr, reverse=true) +// Usage: +// transpose(arr, [reverse]) +// Description: +// Returns the transpose of the given input array. The input should be a list of lists that are +// all the same length. If you give a vector then transpose returns it unchanged. +// When reverse=true, the transpose is done across to the secondary diagonal. (See example below.) // By default, reverse=false. // Example: // arr = [ @@ -1329,19 +1331,19 @@ function array_dim(v, depth=undef) = // // ["h", "e", "b"], // // ["g", "d", "a"] // // ] -// Example: +// Example: Transpose on a list of numbers returns the list unchanged // transpose([3,4,5]); // Returns: [3,4,5] function transpose(arr, reverse=false) = - assert( is_list(arr) && len(arr)>0, "The array is not a vector neither a matrix." ) + assert( is_list(arr) && len(arr)>0, "Input to transpose must be a nonempty list.") is_list(arr[0]) - ? let( l0 = len(arr[0]) ) - assert([for(a=arr) if(!is_list(a) || len(a)!=l0) 1 ]==[], "The array is not a vector neither a matrix." ) + ? let( len0 = len(arr[0]) ) + assert([for(a=arr) if(!is_list(a) || len(a)!=len0) 1 ]==[], "Input to transpose has inconsistent row lengths." ) reverse - ? [for (i=[0:1:l0-1]) - [ for (j=[0:1:len(arr)-1]) arr[len(arr)-1-j][l0-1-i] ] ] - : [for (i=[0:1:l0-1]) + ? [for (i=[0:1:len0-1]) + [ for (j=[0:1:len(arr)-1]) arr[len(arr)-1-j][len0-1-i] ] ] + : [for (i=[0:1:len0-1]) [ for (j=[0:1:len(arr)-1]) arr[j][i] ] ] - : assert( is_vector(arr), "The array is not a vector neither a matrix." ) + : assert( is_vector(arr), "Input to transpose must be a vector or list of lists.") arr; diff --git a/rounding.scad b/rounding.scad index ae2aed0..c57a76f 100644 --- a/rounding.scad +++ b/rounding.scad @@ -488,6 +488,7 @@ function smooth_path(path, tangents, size, relsize, splinesteps=10, uniform=fals // - smooth: os_smooth(cut|joint). Define continuous curvature rounding, with `cut` and `joint` as for round_corners. // - teardrop: os_teardrop(r|cut). Rounding using a 1/8 circle that then changes to a 45 degree chamfer. The chamfer is at the end, and enables the object to be 3d printed without support. The radius gives the radius of the circular part. // - chamfer: os_chamfer([height], [width], [cut], [angle]). Chamfer the edge at desired angle or with desired height and width. You can specify height and width together and the angle will be ignored, or specify just one of height and width and the angle is used to determine the shape. Alternatively, specify "cut" along with angle to specify the cut back distance of the chamfer. +// - mask: os_mask(mask, [out]). Create a profile from one of the [2d masking shapes](shapes2d.scad#5-2d-masking-shapes). The `out` parameter specifies that the mask should flare outward (like crown molding or baseboard). This is set false by default. // . // The general settings that you can use with all of the helper functions are mostly used to control how offset_sweep() calls the offset() function. // - extra: Add an extra vertical step of the specified height, to be used for intersections or differences. This extra step will extend the resulting object beyond the height you specify. Default: 0 @@ -654,6 +655,15 @@ function smooth_path(path, tangents, size, relsize, splinesteps=10, uniform=fals // up(1) // offset_sweep(offset(rhex,r=-1), height=9.5, bottom=os_circle(r=2), top=os_teardrop(r=-4)); // } +// Example: Using os_mask to create ogee profiles: +// ogee = mask2d_ogee([ +// "xstep",1, "ystep",1, // Starting shoulder. +// "fillet",5, "round",5, // S-curve. +// "ystep",1, // Ending shoulder. +// ]); +// star = star(5, r=220, ir=130); +// rounded_star = round_corners(star, cut=flatten(repeat([5,0],5)), $fn=24); +// offset_sweep(rounded_star, height=100, top=os_mask(ogee), bottom=os_mask(ogee,out=true)); // This function does the actual work of repeatedly calling offset() and concatenating the resulting face and vertex lists to produce @@ -880,6 +890,18 @@ function os_profile(points, extra,check_valid, quality, offset_maxstep, offset) ]); +function os_mask(mask, out=false, extra,check_valid, quality, offset_maxstep, offset) = + let( + origin_index = [for(i=idx(mask)) if (mask[i].x<0 && mask[i].y<0) i], + xfactor = out ? -1 : 1 + ) + assert(len(origin_index)==1,"Cannot find origin in the mask") + let( + points = ([for(pt=polygon_shift(mask,origin_index[0])) [xfactor*max(pt.x,0),-max(pt.y,0)]]) + ) + os_profile(deduplicate(move(-points[1],p=select(points,1,-1))), extra,check_valid,quality,offset_maxstep,offset); + + // Module: convex_offset_extrude() // // Description: @@ -1994,4 +2016,4 @@ module bent_cutout_mask(r, thickness, path, convexity=10) } -// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap \ No newline at end of file +// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap