You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
177 lines
5.7 KiB
177 lines
5.7 KiB
/**
|
|
* path_extrude.scad
|
|
*
|
|
* @copyright Justin Lin, 2017
|
|
* @license https://opensource.org/licenses/lgpl-3.0.html
|
|
*
|
|
* @see https://openhome.cc/eGossip/OpenSCAD/lib3x-path_extrude.html
|
|
*
|
|
**/
|
|
|
|
use <__to3d.scad>
|
|
use <__angy_angz.scad>
|
|
use <sweep.scad>
|
|
use <matrix/m_scaling.scad>
|
|
use <matrix/m_translation.scad>
|
|
use <matrix/m_rotation.scad>
|
|
|
|
module path_extrude(shape_pts, path_pts, triangles = "SOLID", twist = 0, scale = 1.0, closed = false, method = "AXIS_ANGLE") {
|
|
sh_pts = len(shape_pts[0]) == 3 ? [for(p = shape_pts) [each p, 1]] : [for(p = shape_pts) [p.x, p.y, 0, 1]];
|
|
pth_pts = len(path_pts[0]) == 3 ? path_pts : [for(p = path_pts) __to3d(p)];
|
|
|
|
len_path_pts = len(pth_pts);
|
|
len_path_pts_minus_one = len_path_pts - 1;
|
|
|
|
m_rot_90_0_n90 = m_rotation([90, 0, -90]);
|
|
one = [1, 1, 1];
|
|
|
|
module axis_angle_path_extrude() {
|
|
twist_step_a = twist / len_path_pts;
|
|
|
|
function translate_pts(pts, t) = [for(p = pts) p + t];
|
|
|
|
scale_step_vt = (
|
|
is_num(scale) ?
|
|
let(s = scale - 1) [s, s, s] :
|
|
len(scale) == 2 ? [each (scale - [1, 1]), 0]:
|
|
scale - one
|
|
) / len_path_pts_minus_one;
|
|
|
|
identity_matrix = [
|
|
[1, 0, 0, 0],
|
|
[0, 1, 0, 0],
|
|
[0, 0, 1, 0],
|
|
[0, 0, 0, 1]
|
|
];
|
|
|
|
// get rotation matrice for sections
|
|
rot_matrice = [
|
|
for(i = len_path_pts - 2; i > 0; i = i - 1)
|
|
let(
|
|
vt0 = pth_pts[i] - pth_pts[i - 1],
|
|
vt1 = pth_pts[i + 1] - pth_pts[i],
|
|
a = acos((vt0 * vt1) / sqrt(vt0 * vt0 * vt1 * vt1)),
|
|
v = cross(vt0, vt1)
|
|
)
|
|
m_rotation(a, v)
|
|
];
|
|
|
|
leng_rot_matrice = len(rot_matrice);
|
|
cumu_rot_matrice = leng_rot_matrice <= 1 ?
|
|
[each rot_matrice, identity_matrix] :
|
|
[
|
|
for(
|
|
i = leng_rot_matrice - 1, m = rot_matrice[i];
|
|
i > -1;
|
|
i = i - 1, m = i == -1 ? undef : rot_matrice[i] * m
|
|
)
|
|
m
|
|
];
|
|
|
|
// get all sections
|
|
angleyz_pts01 = __angy_angz(pth_pts[0], pth_pts[1]);
|
|
function init_section(a, s) =
|
|
let(transform_m = m_rotation([0, -angleyz_pts01[0], angleyz_pts01[1]]) * m_rot_90_0_n90 * m_rotation(a) * m_scaling(s))
|
|
[
|
|
for(p = sh_pts)
|
|
let(transformed = transform_m * p)
|
|
[transformed.x, transformed.y, transformed.z]
|
|
];
|
|
|
|
function local_rotate_section(j, init_a, init_s) =
|
|
let(
|
|
ms = cumu_rot_matrice[j - 1],
|
|
ms0 = ms[0],
|
|
ms1 = ms[1],
|
|
ms2 = ms[2],
|
|
ms0p = [ms0[0], ms0[1], ms0[2]],
|
|
ms1p = [ms1[0], ms1[1], ms1[2]],
|
|
ms2p = [ms2[0], ms2[1], ms2[2]]
|
|
)
|
|
[
|
|
for(p = init_section(init_a, init_s))
|
|
[ms0p * p, ms1p * p, ms2p * p]
|
|
];
|
|
|
|
sections =
|
|
let(
|
|
fst_section = translate_pts(init_section(0, one), pth_pts[0]),
|
|
snd_section = translate_pts(init_section(0, one + scale_step_vt), pth_pts[1]),
|
|
end_i = len_path_pts - 1,
|
|
remain_sections = [
|
|
for(i = 1; i < end_i; i = i + 1)
|
|
translate_pts(
|
|
local_rotate_section(i, i * twist_step_a, one + scale_step_vt * (i + 1)),
|
|
pth_pts[i + 1]
|
|
)
|
|
]
|
|
) [fst_section, snd_section, each remain_sections];
|
|
|
|
calculated_sections =
|
|
closed && pth_pts[0] == pth_pts[len_path_pts_minus_one] ?
|
|
[each sections, sections[0]] : // round-robin
|
|
sections;
|
|
|
|
sweep(
|
|
calculated_sections,
|
|
triangles
|
|
);
|
|
|
|
// hook for testing
|
|
test_path_extrude(sections, method);
|
|
}
|
|
|
|
module euler_angle_path_extrude() {
|
|
scale_step_vt = ((is_num(scale) ? [scale, scale] : scale) - [1, 1]) / len_path_pts_minus_one;
|
|
|
|
twist_step = twist / len_path_pts_minus_one;
|
|
|
|
function section(p1, p2, i) =
|
|
let(
|
|
angy_angz = __angy_angz(p1, p2),
|
|
ay = -angy_angz[0],
|
|
az = angy_angz[1],
|
|
transform_m = m_translation(p1) *
|
|
m_rotation([0, ay, az]) *
|
|
m_translation([i == 0 ? 0 : norm(p1 - p2), 0, 0]) *
|
|
m_rot_90_0_n90 *
|
|
m_rotation(twist_step * i) *
|
|
m_scaling([1 + scale_step_vt.x * i, 1 + scale_step_vt.y * i, 1])
|
|
)
|
|
[
|
|
for(p = sh_pts)
|
|
let(transformed = transform_m * p)
|
|
[transformed.x, transformed.y, transformed.z]
|
|
];
|
|
|
|
path_extrude_inner = [
|
|
for(i = 1; i < len_path_pts; i = i + 1)
|
|
section(pth_pts[i - 1], pth_pts[i], i)
|
|
];
|
|
|
|
calculated_sections =
|
|
closed && pth_pts[0] == pth_pts[len_path_pts_minus_one] ?
|
|
[each path_extrude_inner, path_extrude_inner[0]] : // round-robin
|
|
[section(pth_pts[0], pth_pts[1], 0), each path_extrude_inner];
|
|
|
|
sweep(
|
|
calculated_sections,
|
|
triangles
|
|
);
|
|
|
|
// hook for testing
|
|
test_path_extrude(calculated_sections, method);
|
|
}
|
|
|
|
if(method == "AXIS_ANGLE") {
|
|
axis_angle_path_extrude();
|
|
}
|
|
else if(method == "EULER_ANGLE") {
|
|
euler_angle_path_extrude();
|
|
}
|
|
}
|
|
|
|
// override to test
|
|
module test_path_extrude(sections, method) {
|
|
|
|
}
|