From a5b20180083ba8d3014bc298cf0e28c20e6be437 Mon Sep 17 00:00:00 2001 From: Chris Palmer Date: Sun, 21 Apr 2024 08:47:44 +0100 Subject: [PATCH] Added offset_paths() to sweep.scad. show_path() now takes an optional radius. --- readme.md | 3 ++- utils/sweep.scad | 34 +++++++++++++++++++--------------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/readme.md b/readme.md index ac962ad..10cb87c 100644 --- a/readme.md +++ b/readme.md @@ -7451,6 +7451,7 @@ Each vertex, apart from the first and the last, has an associated radius and the | `cap(facets, segment = 0, end)` | Create the mesh for an end cap | | `circle_points(r = 1, z = 0, dir = -1)` | Generate the points of a circle, setting z makes a single turn spiral | | `helical_twist_per_segment(r, pitch, sides)` | Calculate the twist around Z that rotate_from_to() introduces | +| `offset_paths(path, offsets, twists = 0)` | Create new paths offset from the original, optionally spiralling around it | | `rectangle_points(w, h)` | Generate the points of a rectangle | | `rounded_path(path)` | Convert a rounded_path, consisting of a start coordinate, vertex / radius pairs and then an end coordinate, to a path of points for sweep. | | `rounded_path_vertices(path)` | Show the unrounded version of a rounded_path for debug | @@ -7462,7 +7463,7 @@ Each vertex, apart from the first and the last, has an associated radius and the ### Modules | Module | Description | |:--- |:--- | -| `show_path(path)` | Show a path using a chain of hulls for debugging, duplicate points are highlighted. | +| `show_path(path, r = 0.1)` | Show a path using a chain of hulls for debugging, duplicate points are highlighted. | | `sweep(path, profile, loop = false, twist = 0, convexity = 1)` | Draw a polyhedron that is the swept volume | ![sweep](tests/png/sweep.png) diff --git a/utils/sweep.scad b/utils/sweep.scad index 6f371ef..d978425 100644 --- a/utils/sweep.scad +++ b/utils/sweep.scad @@ -111,7 +111,7 @@ function helical_twist_per_segment(r, pitch, sides) = //! Calculate the twist ar // // Generate all the transforms for the profile of the swept volume. // -function sweep_transforms(path, loop = false, twist = 0) = +function sweep_transforms(path, loop = false, twist = 0, initial_rotation = undef) = let(len = len(path), last = len - 1, @@ -122,7 +122,7 @@ function sweep_transforms(path, loop = false, twist = 0) = lengths = [for(i = 0, t = 0; i < len; t = t + norm(path[min(i + 1, last)] - path[i]), i = i + 1) t], length = lengths[last], - rotations = [for(i = 0, rot = fs_frame(tangents); + rotations = [for(i = 0, rot = is_undef(initial_rotation) ? fs_frame(tangents) : rot3_z(initial_rotation); i < len; i = i + 1, rot = i < len ? rotate_from_to(tangents[i - 1], tangents[i]) * rot : undef) rot], @@ -169,7 +169,7 @@ function sweep(path, profile, loop = false, twist = 0) = //! Generate the point points = skin_points(profile, path, loop, twist), skin_faces = skin_faces(points, npoints, facets, loop), faces = loop ? skin_faces : concat([cap(facets)], skin_faces, [cap(facets, npoints - 1)]) - ) [points, faces]; + ) [points, faces]; module sweep(path, profile, loop = false, twist = 0, convexity = 1) { //! Draw a polyhedron that is the swept volume mesh = sweep(path, profile, loop, twist); @@ -229,16 +229,20 @@ function rounded_path(path) = //! Convert a rounded_path, consisting of a start function segmented_path(path, min_segment) = [ //! Add points to a path to enforce a minimum segment length for(i = [0 : len(path) - 2]) - let(delta = - assert(path[i] != path[i + 1], str("Coincident points at path[", i, "] = ", path[i])) - path[i+1] - path[i], - segs = ceil(norm(delta) / min_segment) - ) - for(j = [0 : segs - 1]) - path[i] + delta * j / segs, // Linear interpolation - path[len(path) - 1] + let(delta = + assert(path[i] != path[i + 1], str("Coincident points at path[", i, "] = ", path[i])) + path[i+1] - path[i], + segs = ceil(norm(delta) / min_segment) + ) + for(j = [0 : segs - 1]) + path[i] + delta * j / segs, // Linear interpolation + path[len(path) - 1] ]; +function offset_paths(path, offsets, twists = 0) = let( //! Create new paths offset from the original, optionally spiralling around it + transforms = sweep_transforms(path, twist = 360 * twists, initial_rotation = 0) + ) [for(o = offsets) let(initial = [o.x, o.y, o.z, 1]) [for(t = transforms) initial * t]]; + function spiral_paths(path, n, r, twists, start_angle) = let( //! Create a new paths which spiral around the given path. Use for making twisted cables segment = twists ? path_length(path) / twists / r2sides(2 * r) : inf, transforms = sweep_transforms(segmented_path(path, segment), twist = 360 * twists) @@ -246,16 +250,16 @@ function spiral_paths(path, n, r, twists, start_angle) = let( //! Create a new p function rounded_path_vertices(path) = [path[0], for(i = [1 : 2 : len(path) - 1]) path[i]]; //! Show the unrounded version of a rounded_path for debug -module show_path(path) //! Show a path using a chain of hulls for debugging, duplicate points are highlighted. +module show_path(path, r = 0.1) //! Show a path using a chain of hulls for debugging, duplicate points are highlighted. for(i = [0 : len(path) - 2]) { hull($fn = 16) { translate(path[i]) - sphere(0.1); + sphere(r); translate(path[i + 1]) - sphere(0.1); + sphere(r); } if(path[i] == path[i + 1]) translate(path[i]) - color("red") sphere(1); + color("red") sphere($fn = 16, r * 4); }