From a036802cea725375c8346488042e54aeee97463b Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Sat, 4 May 2024 23:32:48 -0400 Subject: [PATCH] mutators-> misc, add flip1/flip2 styles to vnf --- .openscad_docsgen_rc | 2 +- mutators.scad => miscellaneous.scad | 474 +++++++++--------- scripts/mkdocspdf.sh | 2 +- std.scad | 2 +- ..._mutators.scad => test_miscellaneous.scad} | 0 vnf.scad | 16 +- 6 files changed, 251 insertions(+), 245 deletions(-) rename mutators.scad => miscellaneous.scad (97%) rename tests/{test_mutators.scad => test_miscellaneous.scad} (100%) diff --git a/.openscad_docsgen_rc b/.openscad_docsgen_rc index ca85511..e865801 100644 --- a/.openscad_docsgen_rc +++ b/.openscad_docsgen_rc @@ -23,7 +23,7 @@ PrioritizeFiles: distributors.scad color.scad partitions.scad - mutators.scad + miscellaneous.scad paths.scad regions.scad skin.scad diff --git a/mutators.scad b/miscellaneous.scad similarity index 97% rename from mutators.scad rename to miscellaneous.scad index f64e574..a5a6f4b 100644 --- a/mutators.scad +++ b/miscellaneous.scad @@ -1,101 +1,56 @@ ////////////////////////////////////////////////////////////////////// -// LibFile: mutators.scad -// Functions and modules to mutate children in various ways. +// LibFile: miscellaneous.scad +// Miscellaneous modules that didn't fit in anywhere else, including +// bounding box, chain hull, extrusions, and minkowski based +// modules. // Includes: // include // FileGroup: Basic Modeling -// FileSummary: Modules and Functions to mutate items. +// FileSummary: Extrusion, bounding box, chain hull and minkowski-based transforms. // FileFootnotes: STD=Included in std.scad ////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////// -// Section: Bounding Box -////////////////////////////////////////////////////////////////////// +// Section: Extrusion -// Module: bounding_box() -// Synopsis: Creates the smallest bounding box that contains all the children. +// Module: extrude_from_to() +// Synopsis: Extrudes 2D children between two points in 3D space. // SynTags: Geom -// Topics: Mutators, Bounds, Bounding Boxes -// See Also: pointlist_bounds() +// Topics: Extrusion, Miscellaneous +// See Also: path_sweep(), path_extrude2d() // Usage: -// bounding_box([excess],[planar]) CHILDREN; +// extrude_from_to(pt1, pt2, [convexity=], [twist=], [scale=], [slices=]) 2D-CHILDREN; // Description: -// Returns the smallest axis-aligned square (or cube) shape that contains all the 2D (or 3D) -// children given. The module children() must 3d when planar=false and -// 2d when planar=true, or you will get a warning of mixing dimension -// or scaling by 0. +// Extrudes the 2D children linearly between the 3d points pt1 and pt2. The origin of the 2D children are placed on +// pt1 and pt2, and oriented perpendicular to the line between the points. // Arguments: -// excess = The amount that the bounding box should be larger than needed to bound the children, in each axis. -// planar = If true, creates a 2D bounding rectangle. Is false, creates a 3D bounding cube. Default: false -// Example(3D): -// module shapes() { -// translate([10,8,4]) cube(5); -// translate([3,0,12]) cube(2); +// pt1 = starting point of extrusion. +// pt2 = ending point of extrusion. +// --- +// convexity = max number of times a line could intersect a wall of the 2D shape being extruded. +// twist = number of degrees to twist the 2D shape over the entire extrusion length. +// scale = scale multiplier for end of extrusion compared the start. +// slices = Number of slices along the extrusion to break the extrusion into. Useful for refining `twist` extrusions. +// Example(FlatSpin,VPD=200,VPT=[0,0,15]): +// extrude_from_to([0,0,0], [10,20,30], convexity=4, twist=360, scale=3.0, slices=40) { +// xcopies(3) circle(3, $fn=32); // } -// #bounding_box() shapes(); -// shapes(); -// Example(2D): -// module shapes() { -// translate([10,8]) square(5); -// translate([3,0]) square(2); -// } -// #bounding_box(planar=true) shapes(); -// shapes(); -module bounding_box(excess=0, planar=false) { - // a 3d (or 2d when planar=true) approx. of the children projection on X axis - module _xProjection() { - if (planar) { - projection() - rotate([90,0,0]) - linear_extrude(1, center=true) - hull() - children(); - } else { - xs = excess<.1? 1: excess; - linear_extrude(xs, center=true) - projection() - rotate([90,0,0]) - linear_extrude(xs, center=true) - projection() - hull() - children(); - } - } - - // a bounding box with an offset of 1 in all axis - module _oversize_bbox() { - if (planar) { - minkowski() { - _xProjection() children(); // x axis - rotate(-90) _xProjection() rotate(90) children(); // y axis - } - } else { - minkowski() { - _xProjection() children(); // x axis - rotate(-90) _xProjection() rotate(90) children(); // y axis - rotate([0,-90,0]) _xProjection() rotate([0,90,0]) children(); // z axis - } - } - } - - // offsets a cube by `excess` - module _shrink_cube() { - intersection() { - translate((1-excess)*[ 1, 1, 1]) children(); - translate((1-excess)*[-1,-1,-1]) children(); - } - } - +module extrude_from_to(pt1, pt2, convexity, twist, scale, slices) { req_children($children); - attachable(){ - if(planar) { - offset(excess-1/2) _oversize_bbox() children(); - } else { - render(convexity=2) - if (excess>.1) { - _oversize_bbox() children(); - } else { - _shrink_cube() _oversize_bbox() children(); + check = + assert(is_vector(pt1),"First point must be a vector") + assert(is_vector(pt2),"Second point must be a vector"); + pt1 = point3d(pt1); + pt2 = point3d(pt2); + rtp = xyz_to_spherical(pt2-pt1); + attachable() + { + translate(pt1) { + rotate([0, rtp[2], rtp[1]]) { + if (rtp[0] > 0) { + linear_extrude(height=rtp[0], convexity=convexity, center=false, slices=slices, twist=twist, scale=scale) { + children(); + } + } } } union(); @@ -103,69 +58,10 @@ module bounding_box(excess=0, planar=false) { } -////////////////////////////////////////////////////////////////////// -// Section: Warp Mutators -////////////////////////////////////////////////////////////////////// - - -// Module: chain_hull() -// Synopsis: Performs the union of hull operations between consecutive pairs of children. -// SynTags: Geom -// Topics: Mutators -// See Also: hull() -// Usage: -// chain_hull() CHILDREN; -// -// Description: -// Performs hull operations between consecutive pairs of children, -// then unions all of the hull results. This can be a very slow -// operation, but it can provide results that are hard to get -// otherwise. -// -// Side Effects: -// `$idx` is set to the index value of the first child of each hulling pair, and can be used to modify each child pair individually. -// `$primary` is set to true when the child is the first in a chain pair. -// -// Example: -// chain_hull() { -// cube(5, center=true); -// translate([30, 0, 0]) sphere(d=15); -// translate([60, 30, 0]) cylinder(d=10, h=20); -// translate([60, 60, 0]) cube([10,1,20], center=false); -// } -// Example: Using `$idx` and `$primary` -// chain_hull() { -// zrot( 0) right(100) if ($primary) cube(5+3*$idx,center=true); else sphere(r=10+3*$idx); -// zrot( 45) right(100) if ($primary) cube(5+3*$idx,center=true); else sphere(r=10+3*$idx); -// zrot( 90) right(100) if ($primary) cube(5+3*$idx,center=true); else sphere(r=10+3*$idx); -// zrot(135) right(100) if ($primary) cube(5+3*$idx,center=true); else sphere(r=10+3*$idx); -// zrot(180) right(100) if ($primary) cube(5+3*$idx,center=true); else sphere(r=10+3*$idx); -// } -module chain_hull() -{ - req_children($children); - attachable(){ - if ($children == 1) { - children(); - } - else { - for (i =[1:1:$children-1]) { - $idx = i; - hull() { - let($primary=true) children(i-1); - let($primary=false) children(i); - } - } - } - union(); - } -} - - // Module: path_extrude2d() // Synopsis: Extrudes 2D children along a 2D path. // SynTags: Geom -// Topics: Mutators, Extrusion +// Topics: Miscellaneous, Extrusion // See Also: path_sweep(), path_extrude() // Usage: // path_extrude2d(path, [caps=], [closed=], [s=], [convexity=]) 2D-CHILDREN; @@ -285,10 +181,72 @@ module path_extrude2d(path, caps=false, closed=false, s, convexity=10) { } +// Module: path_extrude() +// Synopsis: Extrudes 2D children along a 3D path. +// SynTags: Geom +// Topics: Paths, Extrusion, Miscellaneous +// See Also: path_sweep(), path_extrude2d() +// Usage: +// path_extrude(path, [convexity], [clipsize]) 2D-CHILDREN; +// Description: +// Extrudes 2D children along a 3D path. This may be slow and can have problems with twisting. +// Arguments: +// path = Array of points for the bezier path to extrude along. +// convexity = Maximum number of walls a ray can pass through. +// clipsize = Increase if artifacts are left. Default: 100 +// Example(FlatSpin,VPD=600,VPT=[75,16,20]): +// path = [ [0, 0, 0], [33, 33, 33], [66, 33, 40], [100, 0, 0], [150,0,0] ]; +// path_extrude(path) circle(r=10, $fn=6); +module path_extrude(path, convexity=10, clipsize=100) { + req_children($children); + rotmats = cumprod([ + for (i = idx(path,e=-2)) let( + vec1 = i==0? UP : unit(path[i]-path[i-1], UP), + vec2 = unit(path[i+1]-path[i], UP) + ) rot(from=vec1,to=vec2) + ]); + // This adds a rotation midway between each item on the list + interp = rot_resample(rotmats,n=2,method="count"); + epsilon = 0.0001; // Make segments ever so slightly too long so they overlap. + ptcount = len(path); + attachable(){ + for (i = [0:1:ptcount-2]) { + pt1 = path[i]; + pt2 = path[i+1]; + dist = norm(pt2-pt1); + T = rotmats[i]; + difference() { + translate(pt1) { + multmatrix(T) { + down(clipsize/2/2) { + if ((dist+clipsize/2) > 0) { + linear_extrude(height=dist+clipsize/2, convexity=convexity) { + children(); + } + } + } + } + } + translate(pt1) { + hq = (i > 0)? interp[2*i-1] : T; + multmatrix(hq) down(clipsize/2+epsilon) cube(clipsize, center=true); + } + translate(pt2) { + hq = (i < ptcount-2)? interp[2*i+1] : T; + multmatrix(hq) up(clipsize/2+epsilon) cube(clipsize, center=true); + } + } + } + union(); + } +} + + + // Module: cylindrical_extrude() // Synopsis: Extrudes 2D children outwards around a cylinder. // SynTags: Geom -// Topics: Mutators, Extrusion, Rotation +// Topics: Miscellaneous, Extrusion, Rotation // See Also: heightfield(), cylindrical_heightfield(), cyl() // Usage: // cylindrical_extrude(ir|id=, or|od=, [size=], [convexity=], [spin=], [orient=]) 2D-CHILDREN; @@ -352,45 +310,95 @@ module cylindrical_extrude(ir, or, od, id, size=1000, convexity=10, spin=0, orie } -// Module: extrude_from_to() -// Synopsis: Extrudes 2D children between two points in 3D space. + +////////////////////////////////////////////////////////////////////// +// Section: Bounding Box +////////////////////////////////////////////////////////////////////// + +// Module: bounding_box() +// Synopsis: Creates the smallest bounding box that contains all the children. // SynTags: Geom -// Topics: Extrusion, Mutators -// See Also: path_sweep(), path_extrude2d() +// Topics: Miscellaneous, Bounds, Bounding Boxes +// See Also: pointlist_bounds() // Usage: -// extrude_from_to(pt1, pt2, [convexity=], [twist=], [scale=], [slices=]) 2D-CHILDREN; +// bounding_box([excess],[planar]) CHILDREN; // Description: -// Extrudes the 2D children linearly between the 3d points pt1 and pt2. The origin of the 2D children are placed on -// pt1 and pt2, and oriented perpendicular to the line between the points. +// Returns the smallest axis-aligned square (or cube) shape that contains all the 2D (or 3D) +// children given. The module children() must 3d when planar=false and +// 2d when planar=true, or you will get a warning of mixing dimension +// or scaling by 0. // Arguments: -// pt1 = starting point of extrusion. -// pt2 = ending point of extrusion. -// --- -// convexity = max number of times a line could intersect a wall of the 2D shape being extruded. -// twist = number of degrees to twist the 2D shape over the entire extrusion length. -// scale = scale multiplier for end of extrusion compared the start. -// slices = Number of slices along the extrusion to break the extrusion into. Useful for refining `twist` extrusions. -// Example(FlatSpin,VPD=200,VPT=[0,0,15]): -// extrude_from_to([0,0,0], [10,20,30], convexity=4, twist=360, scale=3.0, slices=40) { -// xcopies(3) circle(3, $fn=32); +// excess = The amount that the bounding box should be larger than needed to bound the children, in each axis. +// planar = If true, creates a 2D bounding rectangle. Is false, creates a 3D bounding cube. Default: false +// Example(3D): +// module shapes() { +// translate([10,8,4]) cube(5); +// translate([3,0,12]) cube(2); // } -module extrude_from_to(pt1, pt2, convexity, twist, scale, slices) { +// #bounding_box() shapes(); +// shapes(); +// Example(2D): +// module shapes() { +// translate([10,8]) square(5); +// translate([3,0]) square(2); +// } +// #bounding_box(planar=true) shapes(); +// shapes(); +module bounding_box(excess=0, planar=false) { + // a 3d (or 2d when planar=true) approx. of the children projection on X axis + module _xProjection() { + if (planar) { + projection() + rotate([90,0,0]) + linear_extrude(1, center=true) + hull() + children(); + } else { + xs = excess<.1? 1: excess; + linear_extrude(xs, center=true) + projection() + rotate([90,0,0]) + linear_extrude(xs, center=true) + projection() + hull() + children(); + } + } + + // a bounding box with an offset of 1 in all axis + module _oversize_bbox() { + if (planar) { + minkowski() { + _xProjection() children(); // x axis + rotate(-90) _xProjection() rotate(90) children(); // y axis + } + } else { + minkowski() { + _xProjection() children(); // x axis + rotate(-90) _xProjection() rotate(90) children(); // y axis + rotate([0,-90,0]) _xProjection() rotate([0,90,0]) children(); // z axis + } + } + } + + // offsets a cube by `excess` + module _shrink_cube() { + intersection() { + translate((1-excess)*[ 1, 1, 1]) children(); + translate((1-excess)*[-1,-1,-1]) children(); + } + } + req_children($children); - check = - assert(is_vector(pt1),"First point must be a vector") - assert(is_vector(pt2),"Second point must be a vector"); - pt1 = point3d(pt1); - pt2 = point3d(pt2); - rtp = xyz_to_spherical(pt2-pt1); - attachable() - { - translate(pt1) { - rotate([0, rtp[2], rtp[1]]) { - if (rtp[0] > 0) { - linear_extrude(height=rtp[0], convexity=convexity, center=false, slices=slices, twist=twist, scale=scale) { - children(); - } - } + attachable(){ + if(planar) { + offset(excess-1/2) _oversize_bbox() children(); + } else { + render(convexity=2) + if (excess>.1) { + _oversize_bbox() children(); + } else { + _shrink_cube() _oversize_bbox() children(); } } union(); @@ -398,78 +406,74 @@ module extrude_from_to(pt1, pt2, convexity, twist, scale, slices) { } +////////////////////////////////////////////////////////////////////// +// Section: Hull Based Modules +////////////////////////////////////////////////////////////////////// -// Module: path_extrude() -// Synopsis: Extrudes 2D children along a 3D path. + +// Module: chain_hull() +// Synopsis: Performs the union of hull operations between consecutive pairs of children. // SynTags: Geom -// Topics: Paths, Extrusion, Mutators -// See Also: path_sweep(), path_extrude2d() +// Topics: Miscellaneous +// See Also: hull() // Usage: -// path_extrude(path, [convexity], [clipsize]) 2D-CHILDREN; +// chain_hull() CHILDREN; +// // Description: -// Extrudes 2D children along a 3D path. This may be slow and can have problems with twisting. -// Arguments: -// path = Array of points for the bezier path to extrude along. -// convexity = Maximum number of walls a ray can pass through. -// clipsize = Increase if artifacts are left. Default: 100 -// Example(FlatSpin,VPD=600,VPT=[75,16,20]): -// path = [ [0, 0, 0], [33, 33, 33], [66, 33, 40], [100, 0, 0], [150,0,0] ]; -// path_extrude(path) circle(r=10, $fn=6); -module path_extrude(path, convexity=10, clipsize=100) { +// Performs hull operations between consecutive pairs of children, +// then unions all of the hull results. This can be a very slow +// operation, but it can provide results that are hard to get +// otherwise. +// +// Side Effects: +// `$idx` is set to the index value of the first child of each hulling pair, and can be used to modify each child pair individually. +// `$primary` is set to true when the child is the first in a chain pair. +// +// Example: +// chain_hull() { +// cube(5, center=true); +// translate([30, 0, 0]) sphere(d=15); +// translate([60, 30, 0]) cylinder(d=10, h=20); +// translate([60, 60, 0]) cube([10,1,20], center=false); +// } +// Example: Using `$idx` and `$primary` +// chain_hull() { +// zrot( 0) right(100) if ($primary) cube(5+3*$idx,center=true); else sphere(r=10+3*$idx); +// zrot( 45) right(100) if ($primary) cube(5+3*$idx,center=true); else sphere(r=10+3*$idx); +// zrot( 90) right(100) if ($primary) cube(5+3*$idx,center=true); else sphere(r=10+3*$idx); +// zrot(135) right(100) if ($primary) cube(5+3*$idx,center=true); else sphere(r=10+3*$idx); +// zrot(180) right(100) if ($primary) cube(5+3*$idx,center=true); else sphere(r=10+3*$idx); +// } +module chain_hull() +{ req_children($children); - rotmats = cumprod([ - for (i = idx(path,e=-2)) let( - vec1 = i==0? UP : unit(path[i]-path[i-1], UP), - vec2 = unit(path[i+1]-path[i], UP) - ) rot(from=vec1,to=vec2) - ]); - // This adds a rotation midway between each item on the list - interp = rot_resample(rotmats,n=2,method="count"); - epsilon = 0.0001; // Make segments ever so slightly too long so they overlap. - ptcount = len(path); attachable(){ - for (i = [0:1:ptcount-2]) { - pt1 = path[i]; - pt2 = path[i+1]; - dist = norm(pt2-pt1); - T = rotmats[i]; - difference() { - translate(pt1) { - multmatrix(T) { - down(clipsize/2/2) { - if ((dist+clipsize/2) > 0) { - linear_extrude(height=dist+clipsize/2, convexity=convexity) { - children(); - } - } - } - } - } - translate(pt1) { - hq = (i > 0)? interp[2*i-1] : T; - multmatrix(hq) down(clipsize/2+epsilon) cube(clipsize, center=true); - } - translate(pt2) { - hq = (i < ptcount-2)? interp[2*i+1] : T; - multmatrix(hq) up(clipsize/2+epsilon) cube(clipsize, center=true); - } - } - } - union(); + if ($children == 1) { + children(); + } + else { + for (i =[1:1:$children-1]) { + $idx = i; + hull() { + let($primary=true) children(i-1); + let($primary=false) children(i); + } + } + } + union(); } } - ////////////////////////////////////////////////////////////////////// -// Section: Offset Mutators +// Section: Minkowski and 3D Offset ////////////////////////////////////////////////////////////////////// // Module: minkowski_difference() // Synopsis: Removes diff shapes from base shape surface. // SynTags: Geom -// Topics: Mutators +// Topics: Miscellaneous // See Also: offset3d() // Usage: // minkowski_difference() { BASE; DIFF1; DIFF2; ... } @@ -513,7 +517,7 @@ module minkowski_difference(planar=false) { // Module: offset3d() // Synopsis: Expands or contracts the surface of a 3D object. // SynTags: Geom -// Topics: Mutators +// Topics: Miscellaneous // See Also: minkowski_difference(), round3d() // Usage: // offset3d(r, [size], [convexity]) CHILDREN; @@ -560,7 +564,7 @@ module offset3d(r, size=100, convexity=10) { // Module: round3d() // Synopsis: Rounds arbitrary 3d objects. // SynTags: Geom -// Topics: Rounding, Mutators +// Topics: Rounding, Miscellaneous // See Also: offset3d(), minkowski_difference() // Usage: // round3d(r) CHILDREN; diff --git a/scripts/mkdocspdf.sh b/scripts/mkdocspdf.sh index c9945be..b9e81b6 100755 --- a/scripts/mkdocspdf.sh +++ b/scripts/mkdocspdf.sh @@ -2,7 +2,7 @@ OUTFILE_BASE="BOSL2_Docs" FORMATS="html5" -SOURCES="constants.scad.md transforms.scad.md attachments.scad.md shapes2d.scad.md shapes3d.scad.md drawing.scad.md masks2d.scad.md masks3d.scad.md distributors.scad.md color.scad.md partitions.scad.md mutators.scad.md paths.scad.md regions.scad.md skin.scad.md vnf.scad.md beziers.scad.md rounding.scad.md turtle3d.scad.md math.scad.md linalg.scad.md vectors.scad.md coords.scad.md geometry.scad.md trigonometry.scad.md version.scad.md comparisons.scad.md lists.scad.md utility.scad.md strings.scad.md structs.scad.md fnliterals.scad.md threading.scad.md screws.scad.md screw_drive.scad.md bottlecaps.scad.md ball_bearings.scad.md cubetruss.scad.md gears.scad.md hinges.scad.md joiners.scad.md linear_bearings.scad.md modular_hose.scad.md nema_steppers.scad.md polyhedra.scad.md sliders.scad.md tripod_mounts.scad.md walls.scad.md wiring.scad.md Tutorial-*.md Topics.md AlphaIndex.md" +SOURCES="constants.scad.md transforms.scad.md attachments.scad.md shapes2d.scad.md shapes3d.scad.md drawing.scad.md masks2d.scad.md masks3d.scad.md distributors.scad.md color.scad.md partitions.scad.md miscellaneous.scad.md paths.scad.md regions.scad.md skin.scad.md vnf.scad.md beziers.scad.md rounding.scad.md turtle3d.scad.md math.scad.md linalg.scad.md vectors.scad.md coords.scad.md geometry.scad.md trigonometry.scad.md version.scad.md comparisons.scad.md lists.scad.md utility.scad.md strings.scad.md structs.scad.md fnliterals.scad.md threading.scad.md screws.scad.md screw_drive.scad.md bottlecaps.scad.md ball_bearings.scad.md cubetruss.scad.md gears.scad.md hinges.scad.md joiners.scad.md linear_bearings.scad.md modular_hose.scad.md nema_steppers.scad.md polyhedra.scad.md sliders.scad.md tripod_mounts.scad.md walls.scad.md wiring.scad.md Tutorial-*.md Topics.md AlphaIndex.md" PANDOC="/usr/local/Cellar/pandoc/3.1/bin/pandoc" TITLE="Documentation for the Belfry OpenSCAD Library v2" AUTHOR="Garth Minette" diff --git a/std.scad b/std.scad index 7e02e6f..e41c7a0 100644 --- a/std.scad +++ b/std.scad @@ -13,7 +13,7 @@ include include include include -include +include include include include diff --git a/tests/test_mutators.scad b/tests/test_miscellaneous.scad similarity index 100% rename from tests/test_mutators.scad rename to tests/test_miscellaneous.scad diff --git a/vnf.scad b/vnf.scad index 7bd8d01..a2f7ab9 100644 --- a/vnf.scad +++ b/vnf.scad @@ -35,15 +35,17 @@ EMPTY_VNF = [[],[]]; // The standard empty VNF with no vertices or faces. // Usage: // vnf = vnf_vertex_array(points, [caps=], [cap1=], [cap2=], [style=], [reverse=], [col_wrap=], [row_wrap=], [triangulate=]); // Description: -// Creates a VNF structure from a rectangular vertex list, by dividing the vertices into columns and rows, -// adding faces to tile the surface. You can optionally have faces added to wrap the last column +// Creates a VNF structure from a rectangular vertex list, creating edges that connect the adjacent vertices in the vertex list +// and creating the faces defined by those edges. You can optionally create the edges and faces to wrap the last column // back to the first column, or wrap the last row to the first. Endcaps can be added to either // the first and/or last rows. The style parameter determines how the quadrilaterals are divided into // triangles. The default style is an arbitrary, systematic subdivision in the same direction. The "alt" style -// is the uniform subdivision in the other (alternate) direction. The "min_edge" style picks the shorter edge to +// is the uniform subdivision in the other (alternate) direction. The "flip1" style is an arbitrary division which alternates the +// direction for any adjacent pair of quadrilaterals. The "flip2" style is the alternating division that is the opposite of "flip1". +// The "min_edge" style picks the shorter edge to // subdivide for each quadrilateral, so the division may not be uniform across the shape. The "quincunx" style // adds a vertex in the center of each quadrilateral and creates four triangles, and the "convex" and "concave" styles -// chooses the locally convex/concave subdivision. Degenerate faces +// choose the locally convex/concave subdivision. The "min_area" option creates the triangulation with the minimal area. Degenerate faces // are not included in the output, but if this results in unused vertices they will still appear in the output. // Arguments: // points = A list of vertices to divide into columns and rows. @@ -54,7 +56,7 @@ EMPTY_VNF = [[],[]]; // The standard empty VNF with no vertices or faces. // col_wrap = If true, add faces to connect the last column to the first. // row_wrap = If true, add faces to connect the last row to the first. // reverse = If true, reverse all face normals. -// style = The style of subdividing the quads into faces. Valid options are "default", "alt", "min_edge", "min_area", "quincunx", "convex" and "concave". +// style = The style of subdividing the quads into faces. Valid options are "default", "alt", "flip1", "flip2", "min_edge", "min_area", "quincunx", "convex" and "concave". // triangulate = If true, triangulates endcaps to resolve possible CGAL issues. This can be an expensive operation if the endcaps are complex. Default: false // Example(3D): // vnf = vnf_vertex_array( @@ -137,7 +139,7 @@ function vnf_vertex_array( ) = assert(!(any([caps,cap1,cap2]) && !col_wrap), "col_wrap must be true if caps are requested") assert(!(any([caps,cap1,cap2]) && row_wrap), "Cannot combine caps with row_wrap") - assert(in_list(style,["default","alt","quincunx", "convex","concave", "min_edge","min_area"])) + assert(in_list(style,["default","alt","quincunx", "convex","concave", "min_edge","min_area","flip1","flip2"])) assert(is_matrix(points[0], n=3),"Point array has the wrong shape or points are not 3d") assert(is_consistent(points), "Non-rectangular or invalid point array") assert(is_bool(triangulate)) @@ -179,7 +181,7 @@ function vnf_vertex_array( style=="quincunx"? let(i5 = pcnt + r*colcnt + c) [[i1,i5,i2],[i2,i5,i3],[i3,i5,i4],[i4,i5,i1]] - : style=="alt"? + : style=="alt" || (style=="flip1" && ((r+c)%2==0)) || (style=="flip2" && ((r+c)%2==1)) || (style=="random" && rands(0,1,1)[0]<.5)? [[i1,i4,i2],[i2,i4,i3]] : style=="min_area"? let(