From 1b5555060a82e3c517ec2ed168b7652e0f56527c Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Wed, 25 Jun 2025 20:51:56 -0400 Subject: [PATCH 1/4] vnf_vertex_array bugfix for flip styles & doc improvement --- vnf.scad | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/vnf.scad b/vnf.scad index abc82f02..bc127f48 100644 --- a/vnf.scad +++ b/vnf.scad @@ -40,15 +40,18 @@ EMPTY_VNF = [[],[]]; // The standard empty VNF with no vertices or faces. // 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 "flip1" style is an arbitrary division that 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 -// choose the locally convex/concave subdivision. The "min_area" option creates the triangulation with the minimal area. -// The "quad" style makes quadrilateral edges, which may not be coplanar, relying on OpensCAD to decide how to handle them. Degenerate faces -// are not included in the output, but if this results in unused vertices, those unused vertices do still appear in the output. +// triangles. The styles are: +// * "default" — arbitrary, systematic subdivision in the same direction +// * "alt" — uniform subdivision in the other (alternate) direction +// * "flip1" — arbitrary division that alternates the direction adjacent pairs of quadrilaterals. +// * "flip2" — the alternating division that is the opposite of "flip1". +// * "min_edge" — subdivide each quadrilateral on its shorter edge, so the division may not be uniform across the shape +// * "min_area" — creates the triangulation with the minimal area. +// * "quincunx" — adds a vertex in the center of each quadrilateral and creates four triangles +// * "convex" — choose the locally convex division +// * "concave" — choose the locally concave division +// * "quad" — makes quadrilateral edges, which may not be coplanar, relying on OpensCAD to decide how to handle them. +// Degenerate faces are not included in the output, but if this results in unused vertices, those unused vertices do still appear in the output. // . // You can apply a texture to the vertex array VNF using the usual texture parameters. // See [Texturing](skin.scad#section-texturing) for more details on how textures work. @@ -388,9 +391,6 @@ 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=="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=="default" ? [[i1,i3,i2],[i1,i4,i3]] : style=="min_area"? let( area42 = norm(cross(pts[i2]-pts[i1], pts[i4]-pts[i1]))+norm(cross(pts[i4]-pts[i3], pts[i2]-pts[i3])), @@ -429,7 +429,10 @@ function vnf_vertex_array( : [[i1,i3,i2],[i1,i4,i3]] ) concavefaces - : [[i1,i2,i3,i4]], + : style=="quad" ? [[i1,i2,i3,i4]] + : 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]] + : [[i1,i3,i2],[i1,i4,i3]], // remove degenerate faces culled_faces= [for(face=faces) if (norm(cross(verts[face[1]]-verts[face[0]], From e08d2ec2b3225301bfefc76bc40c9813f67594b9 Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Wed, 25 Jun 2025 20:52:37 -0400 Subject: [PATCH 2/4] doc fix for turtle3d --- turtle3d.scad | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/turtle3d.scad b/turtle3d.scad index 49aa6f64..eb39f35f 100644 --- a/turtle3d.scad +++ b/turtle3d.scad @@ -31,10 +31,16 @@ 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 +// for the state input to change the starting direction. You can also give a transformation for the state. +// For example, if you want the turtle to start its trajectory at the coordinate [3,4,5] you could +// give `state=move([3,4,5])`. +// . +// Because of the complexity of object positioning // in three space, some types of movement require compound commands. These compound commands are lists that specify several operations // all applied to one turtle step. For example: ["move", 4, "twist", 25] executes a twist while moving, and // the command ["arc", 4, "grow", 2, "right", 45, "up", 30] turns to the right and up while also growing the object. @@ -163,7 +169,7 @@ function _rotpart(T) = [for(i=[0:3]) [for(j=[0:3]) j<3 || i==3 ? T[i][j] : 0]]; // the results are very strange if larger angles are permitted.) // Arguments: // commands = List of turtle3d commands -// state = Starting turtle direction or full turtle state (from a previous call). Default: RIGHT +// state = Starting turtle direction, starting turtle transformation (e.g. move(pt)), or full turtle state (from a previous call). Default: RIGHT // transforms = If true teturn list of transformations instead of points. Default: false // full_state = If true return full turtle state for continuing the path in subsequent turtle calls. Default: false // repeat = Number of times to repeat the command list. Default: 1 From efa08a090ad53d7daa0d2ddbeea9b57943d9a0d6 Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Wed, 25 Jun 2025 20:53:44 -0400 Subject: [PATCH 3/4] tutorial tweak --- tutorials/Attachment-Parts.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorials/Attachment-Parts.md b/tutorials/Attachment-Parts.md index f128c736..9aadb2c7 100644 --- a/tutorials/Attachment-Parts.md +++ b/tutorials/Attachment-Parts.md @@ -1,6 +1,6 @@ [Prev: Using attach()](Tutorial-Attachment-Attach) -# Attachment Parts +# Attachable Parts Some objects provide named attachable parts that you can select instead of using the main geometry for the object. One important kind From 011dc54d467b941c131ed0d300d297c7c63cde4a Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Wed, 25 Jun 2025 21:27:55 -0400 Subject: [PATCH 4/4] Make rotate sweep allow approximate x=0 in input shape --- skin.scad | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/skin.scad b/skin.scad index ba969bfc..332fde06 100644 --- a/skin.scad +++ b/skin.scad @@ -1311,7 +1311,7 @@ function rotate_sweep( : tex_reps, tex_depth = is_def(tex_scale)? echo("In rotate_sweep() the 'tex_scale' parameter is deprecated and has been replaced by 'tex_depth'")tex_scale : default(tex_depth,1), - region = force_region(shape) + region = _force_xplus(force_region(shape)) ) assert(is_region(region), "\nshape is not a region or path.") let( @@ -1360,6 +1360,9 @@ function rotate_sweep( ) vnf; +function _force_xplus(data) = + [for(part=data) [for(pt=part) approx(pt.x,0) ? [0,pt.y] : pt]]; + module rotate_sweep( shape, angle=360, texture, tex_size=[5,5], tex_counts, tex_reps, @@ -1388,7 +1391,7 @@ module rotate_sweep( : tex_reps; tex_depth = is_def(tex_scale)? echo("In rotate_sweep() the 'tex_scale' parameter is deprecated and has been replaced by 'tex_depth'")tex_scale : default(tex_depth,1); - region = force_region(shape); + region = _force_xplus(force_region(shape)); check = assert(is_region(region), "\nInput is not a region or polygon."); bounds = pointlist_bounds(flatten(region)); min_x = bounds[0].x;