I wish OpenSCAD had a rotation function which operates on a vector, mimicking
the existing rotate operator which operates on 3-D model material. Like
this:
rotatev(deg_a, [x, y, z], v)
It would transform v into another vector which is rotated around the given
axis by the given number of degrees, as we are accustomed to. Even better if
it could take a list of vectors and rotate them all in the same manner.
This can be written as user code. But before I go and figure out the math
for myself, has anyone out there written it already?
--
View this message in context: http://forum.openscad.org/Wanted-rotate-function-on-vectors-tp11218.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
On Jan 25, 2015, at 00:50 AM, Joymaker kb@sparklight.com wrote:
This can be written as user code. But before I go and figure out the math
for myself, has anyone out there written it already?
Should be quite simple. To do individual rotations on each axis would be
like this:
http://en.wikipedia.org/wiki/Rotation_matrix#In_three_dimensions
http://en.wikipedia.org/wiki/Rotation_matrix#In_three_dimensions
function rotate(rv) =
[[1,0,0],[0,cos(rv[0]),-sin(rv[0])],[0,sin(rv[0]),cos(rv[0])]] *
[[cos(rv[1]),0,sin(rv[1])],[0,1,0],[-sin(rv[1]),0,cos(rv[1])]] *
[[cos(rv[2]),-sin(rv[2]),0],[sin(rv[2]),cos(rv[2]),0],[0,0,1]];
So to do arbitrary, you'd do this:
http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle
http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle
identity = [[1,0,0],[0,1,0],[0,0,1]];function length(v) =
sqrt(pow(v[0],2)+pow(v[1],2)+pow(v[2],2));function unit_vector(v) =
[v[0]/length(v), v[1]/length(v), v[2]/length(v)];function uv(v) =
unit_vector(v);function rotate(a, v) = cos(a)*identity +
sin(a)*unit_vector(v) + cross((1 - cos(a))*unit_vector(v), unit_vector(v));
To join these together, you'd need a way to determine if a is an array.
There are a few ways to do this, but there's no built in function that does
this definitively that I've found. So I wrote my own that should work in
all cases:
// FUNCTION: is_String(x)// Returns true if x is a string, false
otherwise.function is_string(x) = x == undef || len(x) == undef ? false //
if undef, a boolean or a number : len(str(x,x)) == len(x)*2; // if an
array, this is false// FUNCTION: is_array(x)// Returns true if x is an
array, false otherwise.function is_array(x) = is_string(x) ? false : len(x)
!= undef;
With that you can join the two rotation functions like this:
function rotate(a, v) = is_vector(a) ?
[[1,0,0],[0,cos(a[0]),-sin(a[0])],[0,sin(a[0]),cos(a[0])]] *
[[cos(a[1]),0,sin(a[1])],[0,1,0],[-sin(a[1]),0,cos(a[1])]] *
[[cos(a[2]),-sin(a[2]),0],[sin(a[2]),cos(a[2]),0],[0,0,1]] : cos(a)*identity
--
View this message in context: http://forum.openscad.org/Wanted-rotate-function-on-vectors-tp11218p11223.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
Sorry, I meant:
function rotate(a, v) = is_array(a) ?
[[1,0,0],[0,cos(a[0]),-sin(a[0])],[0,sin(a[0]),cos(a[0])]] *
[[cos(a[1]),0,sin(a[1])],[0,1,0],[-sin(a[1]),0,cos(a[1])]] *
[[cos(a[2]),-sin(a[2]),0],[sin(a[2]),cos(a[2]),0],[0,0,1]] : cos(a)*identity
--
View this message in context: http://forum.openscad.org/Wanted-rotate-function-on-vectors-tp11218p11224.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
This sort of response is why the OpenSCAD community is so
[great/fantastic/cooperative/friendly/intelligent/supportive/etc].
Unless specifically shown otherwise above, my contribution is in the Public Domain; To the extent possible under law, I have waived all copyright and related or neighbouring rights to this work. This work is published globally via the internet. :) Inclusion of works of previous authors is not included in the above.
View this message in context: http://forum.openscad.org/Wanted-rotate-function-on-vectors-tp11218p11226.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
Oh, looks like I've not done vector algebra is a looooooooong time as I
didn't understand the notation. For getting the arbitrary rotation, it
would look like this:
function identity(d) = d == 0 ? 1 : [for(y=[1:d]) [for(x=[1:d]) x ==
y ? 1 : 0] ];function length(v) = let(x=v[0], y=v[1], z=v[2])
sqrt(xx + yy + zz);function unit_vector(v) = let(x=v[0], y=v[1],
z=v[2]) [x/length(v), y/length(v), z/length(v)];function skew_symmetric(v)
= let(x=v[0], y=v[1], z=v[2]) [[0, -z, y], [z, 0, -x], [-y, x, 0]];function
tensor_product1(u) = let(x=u[0], y=u[1], z=u[2]) [[xx, xy, xz], [xy,
yy, yz], [xz, yz, zz]];function rotate(a, v) = is_array(a) ?
let(rx=a[0], ry=a[1], rz=a[2]) [[1, 0, 0], [0, cos(rx),
-sin(rx)], [0, sin(rx), cos(rx)]] * [[cos(ry), 0, sin(ry)], [0, 1, 0],
[-sin(ry), 0, cos(ry)]] * [[cos(rz), -sin(rz), 0], [sin(rz), cos(rz), 0],
[0, 0, 1]] : let(uv=unit_vector(v)) cos(a)*identity(3) +
sin(a)*skew_symmetric(uv) + (1 - cos(a))*tensor_product1(uv);
If you'll note, I've updated my notation to the new one as it is more
flexible and I find clearer. Make sure you download 2015.01.23 from the
development snapshots. I didn't and didn't understand why some of the newer
features weren't working.
Also, you wanted:
rotatev(deg_a, [x, y, z], v)
but I gave you
rotate(a, v)
To use the rotate function I stated, you would multiply the vector that
comes out of the rotate function. I.e.
echo(rotate(90, [1,0,0]) * [1, 0, 0]);echo(rotate(90, [1,0,0]) * [0, 1,
0]);echo(rotate(90, [1,0,0]) * [0, 0, 1]);
would give you:
ECHO: [1, 0, 0]ECHO: [0, 0, 1]ECHO: [0, -1, 0]
If you want to do against a list of vectors, you'd do this:
echo([for(i=[[1,0,0],[0,1,0],[0,0,1]]) rotate(90, [1,0,0]) * i ]);
which happens to be the same as:
echo([for(i=identity(3)) rotate(90, [1,0,0]) * i ]);
which would give you a similar result as before:
ECHO: [[1, 0, 0], [0, 0, 1], [0, -1, 0]]
This language is new to me and I've learned quite a bit from answering this
question. Hopefully I've not totally confused you in the process. o.O :)
A
--
View this message in context: http://forum.openscad.org/Wanted-rotate-function-on-vectors-tp11218p11227.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
Oh, looks like I've not done vector algebra is a looooooooong time
I suspect not as long as I... at least the seeds are still there until
Alzheimers kicks in...
But your post just reinforces my above post. ;)
Unless specifically shown otherwise above, my contribution is in the Public Domain; To the extent possible under law, I have waived all copyright and related or neighbouring rights to this work. This work is published globally via the internet. :) Inclusion of works of previous authors is not included in the above.
View this message in context: http://forum.openscad.org/Wanted-rotate-function-on-vectors-tp11218p11231.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
Note: norm(v) is a built-in function for vectors of any dimension, so you can replace your length(v) function with it.
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#norm https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#norm
For a pair of 3D vectors, cross(v) is also built in:
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#cross https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#cross
Andrew.
On Jan 25, 2015, at 5:17 AM, adrian adrianh.bsc@gmail.com wrote:
Oh, looks like I've not done vector algebra is a looooooooong time as I didn't understand the notation. For getting the arbitrary rotation, it would look like this:
function identity(d) = d == 0 ? 1 : [for(y=[1:d]) [for(x=[1:d]) x == y ? 1 : 0] ];
function length(v) = let(x=v[0], y=v[1], z=v[2]) sqrt(xx + yy + zz);
function unit_vector(v) = let(x=v[0], y=v[1], z=v[2]) [x/length(v), y/length(v), z/length(v)];
function skew_symmetric(v) = let(x=v[0], y=v[1], z=v[2]) [[0, -z, y], [z, 0, -x], [-y, x, 0]];
function tensor_product1(u) = let(x=u[0], y=u[1], z=u[2]) [[xx, xy, xz], [xy, yy, yz], [xz, yz, zz]];
function rotate(a, v)
= is_array(a)
? let(rx=a[0], ry=a[1], rz=a[2])
[[1, 0, 0], [0, cos(rx), -sin(rx)], [0, sin(rx), cos(rx)]]
* [[cos(ry), 0, sin(ry)], [0, 1, 0], [-sin(ry), 0, cos(ry)]]
* [[cos(rz), -sin(rz), 0], [sin(rz), cos(rz), 0], [0, 0, 1]]
: let(uv=unit_vector(v))
cos(a)*identity(3) + sin(a)*skew_symmetric(uv) + (1 - cos(a))*tensor_product1(uv);
If you'll note, I've updated my notation to the new one as it is more flexible and I find clearer. Make sure you download 2015.01.23 from the development snapshots. I didn't and didn't understand why some of the newer features weren't working.
Also, you wanted:
rotatev(deg_a, [x, y, z], v)
but I gave you
rotate(a, v)
To use the rotate function I stated, you would multiply the vector that comes out of the rotate function. I.e.
echo(rotate(90, [1,0,0]) * [1, 0, 0]);
echo(rotate(90, [1,0,0]) * [0, 1, 0]);
echo(rotate(90, [1,0,0]) * [0, 0, 1]);
would give you:
ECHO: [1, 0, 0]
ECHO: [0, 0, 1]
ECHO: [0, -1, 0]
If you want to do against a list of vectors, you'd do this:
echo([for(i=[[1,0,0],[0,1,0],[0,0,1]]) rotate(90, [1,0,0]) * i ]);
which happens to be the same as:
echo([for(i=identity(3)) rotate(90, [1,0,0]) * i ]);
which would give you a similar result as before:
ECHO: [[1, 0, 0], [0, 0, 1], [0, -1, 0]]
This language is new to me and I've learned quite a bit from answering this question. Hopefully I've not totally confused you in the process. o.O :)
A
View this message in context: Re: Wanted: rotate function on vectors http://forum.openscad.org/Wanted-rotate-function-on-vectors-tp11218p11227.html
Sent from the OpenSCAD mailing list archive http://forum.openscad.org/ at Nabble.com.
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
--
"The future is already here. It's just not very evenly distributed" -- William Gibson
clothbot wrote
Note: norm(v) is a built-in function for vectors of any dimension, so you
can replace your length(v) function with it.
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#norm
<https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#norm
Cool. And here I had figured out another way to compute the unit vector:
function length(v) = sqrt(([v]*v)[0]);function unit_vector(v) =
v/length(v);
:) I'll swap out my length(v) function for norm(v). Thanks. Though I am a
little surprised that there's no unit(v) function.
clothbot wrote
For a pair of 3D vectors, cross(v) is also built in:
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#cross
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#cross
As for cross(v), I know about it. I used it in my first implementation
above when I thought that the x with a circle around it (
http://forum.openscad.org/file/n11233/e9dd9013ec300ceba41484dfc2c9a876.png
) meant cross product. Did I miss a cross product in my functions somewhere?
They appear to be working...
 
A
--
View this message in context: http://forum.openscad.org/Wanted-rotate-function-on-vectors-tp11218p11233.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
I like the way you spaced the text to clearly show the rotation matrix.
--
View this message in context: http://forum.openscad.org/Wanted-rotate-function-on-vectors-tp11218p11236.html
Sent from the OpenSCAD mailing list archive at Nabble.com.