diff --git a/readme.md b/readme.md index b349e50..7b03c98 100644 --- a/readme.md +++ b/readme.md @@ -6569,6 +6569,8 @@ An additional twist around the path can be specified. If the path is closed this The vertices specify where the the path would be without any rounding. Each vertex, apart from the first and the last, has an associated radius and the path shortcuts the vertex with an arc specified by the radius. +`spiral_paths()` makes a list of new paths that spiral around a given path. It can be used to make twisted wires that follow a rounded_path, for example. + [utils/sweep.scad](utils/sweep.scad) Implementation. [tests/sweep.scad](tests/sweep.scad) Code for this example. @@ -6585,12 +6587,16 @@ Each vertex, apart from the first and the last, has an associated radius and the | `path_length(path, i = 0, length = 0)` | Calculated the length along a path | | `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 | +| `segmented_path(path, min_segment)` | Add points to a path to enforce a minimum segment length | | `skin_faces(points, npoints, facets, loop, offset = 0)` | Create the mesh for the swept volume without end caps | +| `spiral_paths(path, n, r, twists, start_angle)` | Create a new paths which sprial around the given path. Use for making twisted cables | | `sweep(path, profile, loop = false, twist = 0)` | Generate the point list and face list of the swept volume | ### Modules | Module | Description | |:--- |:--- | +| `show_path(path)` | 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/tests/png/bearing_blocks.png b/tests/png/bearing_blocks.png index f47638b..5cf8921 100644 Binary files a/tests/png/bearing_blocks.png and b/tests/png/bearing_blocks.png differ diff --git a/tests/png/bldc_motors.png b/tests/png/bldc_motors.png index e8d3eee..f8e7ee3 100644 Binary files a/tests/png/bldc_motors.png and b/tests/png/bldc_motors.png differ diff --git a/tests/png/blowers.png b/tests/png/blowers.png index 2ccd3b8..0a69c8f 100644 Binary files a/tests/png/blowers.png and b/tests/png/blowers.png differ diff --git a/tests/png/bom.png b/tests/png/bom.png index 02d4521..67ff35c 100644 Binary files a/tests/png/bom.png and b/tests/png/bom.png differ diff --git a/tests/png/camera_housing.png b/tests/png/camera_housing.png index 068416a..3112de5 100644 Binary files a/tests/png/camera_housing.png and b/tests/png/camera_housing.png differ diff --git a/tests/png/components.png b/tests/png/components.png index 7e4f45f..6f73899 100644 Binary files a/tests/png/components.png and b/tests/png/components.png differ diff --git a/tests/png/corner_block.png b/tests/png/corner_block.png index 384449f..fd507ad 100644 Binary files a/tests/png/corner_block.png and b/tests/png/corner_block.png differ diff --git a/tests/png/d_connectors.png b/tests/png/d_connectors.png index b2d6ba2..0a35014 100644 Binary files a/tests/png/d_connectors.png and b/tests/png/d_connectors.png differ diff --git a/tests/png/fixing_block.png b/tests/png/fixing_block.png index 5fb6078..f49507e 100644 Binary files a/tests/png/fixing_block.png and b/tests/png/fixing_block.png differ diff --git a/tests/png/flat_hinge.png b/tests/png/flat_hinge.png index a4f617c..1c61808 100644 Binary files a/tests/png/flat_hinge.png and b/tests/png/flat_hinge.png differ diff --git a/tests/png/foot.png b/tests/png/foot.png index 3092479..c908a00 100644 Binary files a/tests/png/foot.png and b/tests/png/foot.png differ diff --git a/tests/png/inserts.png b/tests/png/inserts.png index 9383143..fcbb0e7 100644 Binary files a/tests/png/inserts.png and b/tests/png/inserts.png differ diff --git a/tests/png/knob.png b/tests/png/knob.png index 4bdb749..73a0006 100644 Binary files a/tests/png/knob.png and b/tests/png/knob.png differ diff --git a/tests/png/leadnuts.png b/tests/png/leadnuts.png index 6ac490f..5ce1a79 100644 Binary files a/tests/png/leadnuts.png and b/tests/png/leadnuts.png differ diff --git a/tests/png/modules.png b/tests/png/modules.png index ce644a2..38e6a51 100644 Binary files a/tests/png/modules.png and b/tests/png/modules.png differ diff --git a/tests/png/nuts.png b/tests/png/nuts.png index 7f6f8cc..96c1b19 100644 Binary files a/tests/png/nuts.png and b/tests/png/nuts.png differ diff --git a/tests/png/opengrab.png b/tests/png/opengrab.png index 150e34c..4badfc0 100644 Binary files a/tests/png/opengrab.png and b/tests/png/opengrab.png differ diff --git a/tests/png/pcb_mount.png b/tests/png/pcb_mount.png index 24a5ae3..716a33a 100644 Binary files a/tests/png/pcb_mount.png and b/tests/png/pcb_mount.png differ diff --git a/tests/png/pillars.png b/tests/png/pillars.png index a211eb5..3332f0a 100644 Binary files a/tests/png/pillars.png and b/tests/png/pillars.png differ diff --git a/tests/png/potentiometers.png b/tests/png/potentiometers.png index 1cc10ad..3ff23b5 100644 Binary files a/tests/png/potentiometers.png and b/tests/png/potentiometers.png differ diff --git a/tests/png/pulleys.png b/tests/png/pulleys.png index c3cc4e7..8551585 100644 Binary files a/tests/png/pulleys.png and b/tests/png/pulleys.png differ diff --git a/tests/png/ribbon_clamp.png b/tests/png/ribbon_clamp.png index 6b5a800..4efc003 100644 Binary files a/tests/png/ribbon_clamp.png and b/tests/png/ribbon_clamp.png differ diff --git a/tests/png/ring_terminals.png b/tests/png/ring_terminals.png index b1c431f..b7653cf 100644 Binary files a/tests/png/ring_terminals.png and b/tests/png/ring_terminals.png differ diff --git a/tests/png/screw_knob.png b/tests/png/screw_knob.png index 62b4d14..1e6364d 100644 Binary files a/tests/png/screw_knob.png and b/tests/png/screw_knob.png differ diff --git a/tests/png/screws.png b/tests/png/screws.png index 2f39316..856a400 100644 Binary files a/tests/png/screws.png and b/tests/png/screws.png differ diff --git a/tests/png/sweep.png b/tests/png/sweep.png index c3bb870..114149b 100644 Binary files a/tests/png/sweep.png and b/tests/png/sweep.png differ diff --git a/tests/png/thread.png b/tests/png/thread.png index cd5010d..963036d 100644 Binary files a/tests/png/thread.png and b/tests/png/thread.png differ diff --git a/tests/png/veroboard.png b/tests/png/veroboard.png index f253f93..eecc3db 100644 Binary files a/tests/png/veroboard.png and b/tests/png/veroboard.png differ diff --git a/tests/sweep.scad b/tests/sweep.scad index 7818e96..cb57b0c 100644 --- a/tests/sweep.scad +++ b/tests/sweep.scad @@ -53,4 +53,12 @@ path = bezier_path(p, n); color("blue") rotate(45) sweep(path, circle_points(5, $fn = 64)); -color("green") sweep(rounded_path([[-170, 0, 0], [-170, 170, 0], 10, [-170, 170, 30], 20, [-50, 170, 30], 10, [-130, 100, 40]]), circle_points(3, $fn = 64)); +vertices = [[-170, 0, 0], [-170, 170, 0], 10, [-170, 170, 30], 20, [-50, 170, 31], 10, [-130, 100, 40]]; +rounded_path = rounded_path(vertices); + +show_path(rounded_path_vertices(vertices)); + +paths = spiral_paths(rounded_path, 2, 1.5, 15, 0); +for(i = [0 : len(paths) - 1]) + color(["red", "green"][i]) + sweep(paths[i], circle_points(1.5, $fn = 64)); diff --git a/utils/sweep.scad b/utils/sweep.scad index 8e6636a..40e30ef 100644 --- a/utils/sweep.scad +++ b/utils/sweep.scad @@ -29,6 +29,8 @@ //! `rounded_path()` can be used to generate a path of lines connected by arcs, useful for wire runs, etc. //! The vertices specify where the the path would be without any rounding. //! Each vertex, apart from the first and the last, has an associated radius and the path shortcuts the vertex with an arc specified by the radius. +//! +//! `spiral_paths()` makes a list of new paths that spiral around a given path. It can be used to make twisted wires that follow a rounded_path, for example. // include <../utils/core/core.scad> @@ -107,18 +109,19 @@ function helical_twist_per_segment(r, pitch, sides) = //! Calculate the twist ar ) step_angle * sin(slope); // angle tangent should rotate around z projected onto axis rotate_from_to() uses // -// Generate all the surface points of the swept volume. +// Generate all the transforms for the profile of the swept volume. // -function skin_points(profile, path, loop, twist = 0) = +function sweep_transforms(path, loop = false, twist = 0) = let(len = len(path), last = len - 1, - profile4 = [for(p = profile) [p.x, p.y, p.z, 1]], - tangents = [tangent(path, loop ? last : 0, 0, 1), for(i = [1 : last - 1]) tangent(path, i - 1, i, i + 1), tangent(path, last - 1, last, loop ? 0 : last)], + 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); i < len; i = i + 1, @@ -128,8 +131,20 @@ function skin_points(profile, path, loop, twist = 0) = rotation = missmatch + twist ) [for(i = [0 : last]) - let(za = rotation * i / last) - each profile4 * orientate(path[i], rotations[i] * rot3_z(za)) + let(za = rotation * lengths[i] / length) + orientate(path[i], rotations[i] * rot3_z(za)) + ]; + +// +// Generate all the surface points of the swept volume. +// +function skin_points(profile, path, loop, twist = 0) = + let(profile4 = [for(p = profile) [p.x, p.y, p.z, 1]], + + transforms = sweep_transforms(path, loop, twist) + ) + [for(t = transforms) + each profile4 * t ]; function cap(facets, segment = 0, end) = //! Create the mesh for an end cap @@ -211,3 +226,37 @@ function rounded_path(path) = //! Convert a rounded_path, consisting of a start cos(t) * x_axis + sin(t) * y_axis + centre, // Circular arc in the tiled xy plane. path[len - 1], // Last point has no radius ]; + +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] +]; + +function spiral_paths(path, n, r, twists, start_angle) = let( //! Create a new paths which sprial around the given path. Use for making twisted cables + segment = path_length(path) / twists / r2sides(2 * r), + transforms = sweep_transforms(segmented_path(path, segment), twist = 360 * twists), + initial = [r, 0, 0, 1] * rotate(start_angle) + ) [for(i = [0 : n - 1]) let(initial = [r, 0, 0, 1] * rotate(start_angle + i * 360 / n)) [for(t = transforms) initial * t]]; + +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. + for(i = [0 : len(path) - 2]) { + hull($fn = 16) { + translate(path[i]) + sphere(0.1); + + translate(path[i + 1]) + sphere(0.1); + } + if(path[i] == path[i + 1]) + translate(path[i]) + color("red") sphere(1); + }