2017-04-23 11:16:34 +08:00
|
|
|
/**
|
|
|
|
* along_with.scad
|
|
|
|
*
|
|
|
|
* @copyright Justin Lin, 2017
|
|
|
|
* @license https://opensource.org/licenses/lgpl-3.0.html
|
|
|
|
*
|
2021-02-21 22:47:09 +08:00
|
|
|
* @see https://openhome.cc/eGossip/OpenSCAD/lib3x-along_with.html
|
2017-04-23 11:16:34 +08:00
|
|
|
*
|
|
|
|
**/
|
2019-05-07 17:35:32 +08:00
|
|
|
|
2020-01-27 08:55:23 +08:00
|
|
|
use <__comm__/__angy_angz.scad>;
|
|
|
|
use <__comm__/__to3d.scad>;
|
|
|
|
use <matrix/m_rotation.scad>;
|
2019-05-04 10:04:50 +08:00
|
|
|
|
2019-05-31 10:12:59 +08:00
|
|
|
module along_with(points, angles, twist = 0, scale = 1.0, method = "AXIS_ANGLE") {
|
2021-10-01 10:28:42 +08:00
|
|
|
pts = len(points[0]) == 3 ? points : [for(p = points) __to3d(p)];
|
2017-05-19 11:24:43 +08:00
|
|
|
leng_points = len(points);
|
2017-05-19 13:42:34 +08:00
|
|
|
leng_points_minus_one = leng_points - 1;
|
2017-05-19 13:19:03 +08:00
|
|
|
twist_step_a = twist / leng_points;
|
2019-05-31 09:55:02 +08:00
|
|
|
|
2019-06-11 08:39:57 +08:00
|
|
|
scale_step_vt = is_num(scale) ?
|
2019-06-16 21:09:41 +08:00
|
|
|
let(s = (scale - 1) / leng_points_minus_one) [s, s, s] :
|
2017-05-19 13:42:34 +08:00
|
|
|
[
|
2021-12-04 11:52:25 +08:00
|
|
|
(scale.x - 1) / leng_points_minus_one,
|
|
|
|
(scale.y - 1) / leng_points_minus_one,
|
|
|
|
is_undef(scale.z) ? 0 : (scale.z - 1) / leng_points_minus_one
|
2019-05-15 19:35:42 +08:00
|
|
|
];
|
2019-05-04 10:04:50 +08:00
|
|
|
|
2019-05-31 10:19:33 +08:00
|
|
|
/*
|
|
|
|
Sadly, children(n) cannot be used with inner modules
|
|
|
|
so I have to do things in the first level. Ugly!!
|
|
|
|
*/
|
|
|
|
|
|
|
|
// >>> begin: modules and functions for "AXIS-ANGLE"
|
|
|
|
|
|
|
|
// get rotation matrice for sections
|
2019-05-13 09:50:53 +08:00
|
|
|
identity_matrix = [
|
|
|
|
[1, 0, 0, 0],
|
|
|
|
[0, 1, 0, 0],
|
|
|
|
[0, 0, 1, 0],
|
|
|
|
[0, 0, 0, 1]
|
|
|
|
];
|
|
|
|
|
2021-10-01 09:54:47 +08:00
|
|
|
function axis_angle_local_ang_vects(j, pts) =
|
2019-06-15 10:56:33 +08:00
|
|
|
[
|
|
|
|
for(i = j; i > 0; i = i - 1)
|
|
|
|
let(
|
2021-10-01 09:54:47 +08:00
|
|
|
vt0 = pts[i] - pts[i - 1],
|
|
|
|
vt1 = pts[i + 1] - pts[i],
|
2022-03-01 15:52:17 +08:00
|
|
|
a = acos((vt0 * vt1) / sqrt((vt0 * vt0) * (vt1 * vt1))),
|
2019-06-15 10:56:33 +08:00
|
|
|
v = cross(vt0, vt1)
|
|
|
|
)
|
|
|
|
[a, v]
|
|
|
|
];
|
2019-05-04 10:04:50 +08:00
|
|
|
|
2019-05-31 10:09:49 +08:00
|
|
|
function axis_angle_cumulated_rot_matrice(i, rot_matrice) =
|
2019-05-04 10:04:50 +08:00
|
|
|
let(
|
|
|
|
leng_rot_matrice = len(rot_matrice),
|
|
|
|
leng_rot_matrice_minus_one = leng_rot_matrice - 1,
|
|
|
|
leng_rot_matrice_minus_two = leng_rot_matrice - 2
|
|
|
|
)
|
2022-03-07 10:17:38 +08:00
|
|
|
leng_rot_matrice == 0 ? [identity_matrix] :
|
|
|
|
leng_rot_matrice == 1 ? [rot_matrice[0], identity_matrix] :
|
|
|
|
i == leng_rot_matrice_minus_two ?
|
|
|
|
[
|
|
|
|
rot_matrice[leng_rot_matrice_minus_one],
|
|
|
|
rot_matrice[leng_rot_matrice_minus_two] * rot_matrice[leng_rot_matrice_minus_one]
|
|
|
|
]
|
|
|
|
: axis_angle_cumulated_rot_matrice_sub(i, rot_matrice);
|
2019-05-04 10:04:50 +08:00
|
|
|
|
2019-05-31 10:09:49 +08:00
|
|
|
function axis_angle_cumulated_rot_matrice_sub(i, rot_matrice) =
|
2019-05-04 10:04:50 +08:00
|
|
|
let(
|
2019-05-31 10:09:49 +08:00
|
|
|
matrice = axis_angle_cumulated_rot_matrice(i + 1, rot_matrice),
|
2019-05-04 10:04:50 +08:00
|
|
|
curr_matrix = rot_matrice[i],
|
|
|
|
prev_matrix = matrice[len(matrice) - 1]
|
|
|
|
)
|
2022-02-27 18:53:03 +08:00
|
|
|
[each matrice, curr_matrix * prev_matrix];
|
2019-05-04 10:04:50 +08:00
|
|
|
|
|
|
|
// align modules
|
|
|
|
|
2019-05-31 10:09:49 +08:00
|
|
|
module axis_angle_align_with_pts_angles(i) {
|
2021-10-01 10:28:42 +08:00
|
|
|
translate(pts[i])
|
2022-03-30 09:17:27 +08:00
|
|
|
rotate(twist_step_a * i + angles[i])
|
2019-09-26 08:12:43 +08:00
|
|
|
scale([1, 1, 1] + scale_step_vt * i)
|
|
|
|
children(0);
|
2017-05-19 13:42:34 +08:00
|
|
|
}
|
2017-05-03 16:21:49 +08:00
|
|
|
|
2021-10-01 14:17:53 +08:00
|
|
|
module axis_angle_align_with_pts_rs(a, s) {
|
2021-10-01 10:28:42 +08:00
|
|
|
angleyz = __angy_angz(pts[0], pts[1]);
|
2019-04-29 10:49:27 +08:00
|
|
|
rotate([0, -angleyz[0], angleyz[1]])
|
2021-10-01 13:39:12 +08:00
|
|
|
rotate([0, 0, a - 90])
|
2019-09-26 08:12:43 +08:00
|
|
|
scale(s)
|
|
|
|
children(0);
|
2019-04-29 10:49:27 +08:00
|
|
|
}
|
|
|
|
|
2021-10-01 14:17:53 +08:00
|
|
|
module axis_angle_align_with_local_rotate(j, a, s, cumu_rot_matrice) {
|
2019-04-29 10:49:27 +08:00
|
|
|
if(j == 0) { // first child
|
2021-10-01 14:17:53 +08:00
|
|
|
axis_angle_align_with_pts_rs(a, s)
|
2019-04-29 10:49:27 +08:00
|
|
|
children(0);
|
|
|
|
}
|
|
|
|
else {
|
2019-05-04 10:04:50 +08:00
|
|
|
multmatrix(cumu_rot_matrice[j - 1])
|
2021-10-01 14:17:53 +08:00
|
|
|
axis_angle_align_with_pts_rs(a, s)
|
2019-09-26 08:12:43 +08:00
|
|
|
children(0);
|
2017-04-23 11:16:34 +08:00
|
|
|
}
|
2019-05-04 10:48:38 +08:00
|
|
|
}
|
2019-04-29 10:49:27 +08:00
|
|
|
|
2019-05-31 10:19:33 +08:00
|
|
|
// <<< end: modules and functions for "AXIS-ANGLE"
|
|
|
|
|
|
|
|
|
|
|
|
// >>> begin: modules and functions for "EULER-ANGLE"
|
|
|
|
|
2019-06-15 11:04:16 +08:00
|
|
|
function _euler_angle_path_angles(pts, end_i) =
|
2019-06-17 08:18:40 +08:00
|
|
|
[for(i = 0; i < end_i; i = i + 1) __angy_angz(pts[i], pts[i + 1])];
|
2019-05-31 10:19:33 +08:00
|
|
|
|
|
|
|
function euler_angle_path_angles(children) =
|
|
|
|
let(
|
|
|
|
end_i = children == 1 ? leng_points_minus_one : children - 1,
|
|
|
|
angs = _euler_angle_path_angles(pts, end_i)
|
|
|
|
)
|
2022-02-27 18:53:03 +08:00
|
|
|
[
|
|
|
|
[0, -angs[0][0], angs[0][1]],
|
|
|
|
each[for(a = angs) [0, -a[0], a[1]]]
|
|
|
|
];
|
2019-05-31 10:19:33 +08:00
|
|
|
|
2022-03-30 14:37:00 +08:00
|
|
|
module euler_angle_align(i, angs, look_at) {
|
|
|
|
translate(pts[i])
|
|
|
|
rotate(angs[i])
|
|
|
|
rotate(look_at)
|
|
|
|
rotate(twist_step_a * i)
|
|
|
|
scale([1, 1, 1] + scale_step_vt * i)
|
|
|
|
children(0);
|
2019-05-31 10:19:33 +08:00
|
|
|
}
|
|
|
|
|
2022-03-30 16:58:54 +08:00
|
|
|
angles_defined = !is_undef(angles);
|
|
|
|
|
2019-05-31 10:19:33 +08:00
|
|
|
// <<< end: modules and functions for "EULER-ANGLE"
|
|
|
|
|
2019-05-31 10:12:59 +08:00
|
|
|
if(method == "AXIS_ANGLE") {
|
|
|
|
if(angles_defined) {
|
|
|
|
if($children == 1) {
|
|
|
|
for(i = [0:leng_points_minus_one]) {
|
|
|
|
axis_angle_align_with_pts_angles(i) children(0);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for(i = [0:min(leng_points, $children) - 1]) {
|
|
|
|
axis_angle_align_with_pts_angles(i) children(i);
|
|
|
|
}
|
2019-04-29 10:49:27 +08:00
|
|
|
}
|
2017-04-23 11:16:34 +08:00
|
|
|
}
|
2019-05-31 10:12:59 +08:00
|
|
|
else {
|
|
|
|
cumu_rot_matrice = axis_angle_cumulated_rot_matrice(0, [
|
2021-10-01 10:28:42 +08:00
|
|
|
for(ang_vect = axis_angle_local_ang_vects(leng_points - 2, pts))
|
2020-01-27 08:57:47 +08:00
|
|
|
m_rotation(ang_vect[0], ang_vect[1])
|
2019-05-31 10:12:59 +08:00
|
|
|
]);
|
|
|
|
|
2021-10-01 10:28:42 +08:00
|
|
|
translate(pts[0])
|
2021-10-01 14:17:53 +08:00
|
|
|
axis_angle_align_with_local_rotate(0, 0, [1, 1, 1], cumu_rot_matrice)
|
2022-03-30 09:17:27 +08:00
|
|
|
rotate([90, 0, 0])
|
2019-09-26 08:12:43 +08:00
|
|
|
children(0);
|
2019-05-31 10:12:59 +08:00
|
|
|
|
|
|
|
if($children == 1) {
|
|
|
|
for(i = [0:leng_points - 2]) {
|
2021-10-01 10:28:42 +08:00
|
|
|
translate(pts[i + 1])
|
2021-10-01 14:17:53 +08:00
|
|
|
axis_angle_align_with_local_rotate(i, i * twist_step_a, [1, 1, 1] + scale_step_vt * i, cumu_rot_matrice)
|
2022-03-30 09:17:27 +08:00
|
|
|
rotate([90, 0, 0])
|
2019-09-26 08:12:43 +08:00
|
|
|
children(0);
|
2019-05-31 10:12:59 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for(i = [0:min(leng_points, $children) - 2]) {
|
2021-10-01 10:28:42 +08:00
|
|
|
translate(pts[i + 1])
|
2021-10-01 14:17:53 +08:00
|
|
|
axis_angle_align_with_local_rotate(i, i * twist_step_a, [1, 1, 1] + scale_step_vt * i, cumu_rot_matrice)
|
2022-03-30 09:17:27 +08:00
|
|
|
rotate([90, 0, 0])
|
2019-09-26 08:12:43 +08:00
|
|
|
children(i + 1);
|
2019-05-31 10:12:59 +08:00
|
|
|
}
|
2019-04-29 10:49:27 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-05-31 10:19:33 +08:00
|
|
|
else if(method == "EULER_ANGLE") {
|
2022-03-30 14:37:00 +08:00
|
|
|
angs = angles_defined ?
|
|
|
|
(is_list(angles) ? angles : [for(angle = angles) [0, 0, angle]]) :
|
|
|
|
euler_angle_path_angles($children);
|
2019-06-17 08:18:40 +08:00
|
|
|
|
2022-03-30 14:37:00 +08:00
|
|
|
look_at = angles_defined ? [0, 0, 0] : [90, 0, -90];
|
|
|
|
|
2019-05-31 10:19:33 +08:00
|
|
|
if($children == 1) {
|
|
|
|
for(i = [0:leng_points_minus_one]) {
|
2022-03-30 14:37:00 +08:00
|
|
|
euler_angle_align(i, angs, look_at) children(0);
|
2019-05-31 10:19:33 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for(i = [0:min(leng_points, $children) - 1]) {
|
2022-03-30 14:37:00 +08:00
|
|
|
euler_angle_align(i, angs, look_at) children(i);
|
2019-05-31 10:19:33 +08:00
|
|
|
}
|
2019-06-17 08:18:40 +08:00
|
|
|
}
|
|
|
|
|
2020-01-27 08:55:23 +08:00
|
|
|
test_along_with_angles(angs, $children);
|
2019-05-31 10:19:33 +08:00
|
|
|
}
|
2019-06-17 07:36:17 +08:00
|
|
|
}
|
|
|
|
|
2020-01-27 08:55:23 +08:00
|
|
|
module test_along_with_angles(angles, children) {
|
2019-06-17 07:36:17 +08:00
|
|
|
|
2017-04-23 11:16:34 +08:00
|
|
|
}
|