1
0
mirror of https://github.com/nophead/NopSCADlib.git synced 2025-03-14 19:59:45 +01:00

Added rounded_path() function to sweep.scad.

This commit is contained in:
Chris Palmer 2022-02-06 23:44:23 +00:00
parent d341ce499e
commit 225ea9b451
4 changed files with 46 additions and 6 deletions

View File

@ -6565,6 +6565,10 @@ Subsequent rotations use the minimum rotation method.
The path can be open or closed. If closed sweep ensures that the start and end have the same rotation to line up.
An additional twist around the path can be specified. If the path is closed this should be a multiple of 360.
`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.
[utils/sweep.scad](utils/sweep.scad) Implementation.
[tests/sweep.scad](tests/sweep.scad) Code for this example.
@ -6580,6 +6584,7 @@ An additional twist around the path can be specified. If the path is closed this
| `helical_twist_per_segment(r, pitch, sides)` | Calculate the twist around Z that rotate_from_to() introduces |
| `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. |
| `skin_faces(points, npoints, facets, loop, offset = 0)` | Create the mesh for the swept volume without end caps |
| `sweep(path, profile, loop = false, twist = 0)` | Generate the point list and face list of the swept volume |

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 KiB

After

Width:  |  Height:  |  Size: 124 KiB

View File

@ -32,22 +32,25 @@ loop_y = transform_points(loop, rotate([0, -90, $t * 360]));
loop_z = transform_points(loop, rotate([$t * 360, 0, 0]));
sweep(loop_z, L_points, loop = true);
color("yellow") {
sweep(loop_z, L_points, loop = true);
sweep(loop_x, L_points, loop = true);
sweep(loop_y, L_points, loop = true);
sweep(loop_x, L_points, loop = true);
sweep(loop_y, L_points, loop = true);
}
knot = [ for(i=[0:.2:359])
[ (19*cos(3*i) + 40)*cos(2*i),
(19*cos(3*i) + 40)*sin(2*i),
19*sin(3*i) ] ];
sweep(knot, L_points, loop = true);
color("red") sweep(knot, L_points, loop = true);
p = transform_points([[0,0,0], [20,0,5], [10,30,4], [0,0,0], [0,0,20]], scale(10));
n = 100;
path = bezier_path(p, n);
rotate(45) sweep(path, circle_points(5, $fn = 64));
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));

View File

@ -25,6 +25,10 @@
//!
//! The path can be open or closed. If closed sweep ensures that the start and end have the same rotation to line up.
//! An additional twist around the path can be specified. If the path is closed this should be a multiple of 360.
//!
//! `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.
//
include <../utils/core/core.scad>
@ -179,3 +183,31 @@ function before(path1, path2) = //! Translate `path1` so its end meets the star
function after(path1, path2) = //! Translate `path2` so its start meets the end of `path1` and then concatenate
let(end1 = len(path1) - 1, end2 = len(path2) - 1, offset = path1[end1] - path2[0])
concat(path1, [for(i = [1 : end2]) path2[i] + offset]);
function 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.
let(len = len(path)) assert(len > 3 && len % 2 == 0) [
path[0], // First point has no radius
for(i = [1 : 2 : len - 3]) let( // Step through the vertices with radii, i.e. not the first or last
prev = max(i - 2, 0), // Index of previous point, might be the first point, which is a special case
p0 = path[prev], // Point before the vertex
p1 = path[i], // Vertex
r = path[i + 1], // Radius of shortcut curve
p2 = path[i + 2], // Point after the vertex
v1 = assert(Len(p0) == 3, str("expected path[", prev, "] to be a vertex coordinate, got ", p0))
assert(Len(p1) == 3, str("expected path[", i, "] to be a vertex coordinate, got ", p1))
assert(Len(p2) == 3, str("expected path[", i + 2, "] to be a vertex coordinate, got ", p2))
assert(is_num(r), str("expected path[", i + 1, "] to be a radius, got ", r))
p0 - p1, // Calculate vectors between vertices
v2 = p2 - p1,
a = angle_between(v1, -v2), // Angle turned through
arc_start = p1 + unit(v1) * r * tan(a / 2), // Calc the start position
z_axis = unit(cross(v1, v2)), // z_axis is perpendicular to both vectors
centre = arc_start + unit(cross(z_axis, v1)) * r, // Arc center is a radius away, and perpendicular to v1 and the z_axis.
x_axis = arc_start - centre, // Make the x_axis along the radius to the start point, includes radius a scale factor
y_axis = cross(x_axis, z_axis), // y_axis perpendicular to the other two
sides = r2sides(ceil(r2sides(r) * a / 360)) // Sides needed to make the arc
)
for(j = [0 : sides], t = a * j / sides) // For each vertex in the arc
cos(t) * x_axis + sin(t) * y_axis + centre, // Circular arc in the tiled xy plane.
path[len - 1], // Last point has no radius
];