discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

rotate([45,45,0])

V
vincent_mathoscope
Tue, May 15, 2018 5:16 AM

hi
i dont like this instruction because it is not clear in the formalism wether
x or y are calculated first
see this example, where tube is any module :
//rotate([0,45,0]) rotate([45,0,0]) tube();
rotate([45,0,0]) rotate([0,45,0]) tube();
rotate([45,45,0]) tube();

now, i needed something to automatically put a z-oriented object (say, a
cylinder) to any [x,y,z] direction
if it can be usegul :

module pointervers(v)
{
//v=[x,y,z]
x=v[0];
y=v[1];
z=v[2];
rho=sqrt(xx+yy+zz);
r=sqrt(x
x+y*y);
phi=acos(z/rho);
if (r!=0)
{theta=acos(x/r)*sign(asin(y/r));}
else // cas d'un vecteur v=[0,0,-1]
{theta=0;}
echo(theta);
for (i=[0,$children-1])
{
rotate([0,0,theta]) rotate([0,phi,0]) children([i]);
}
}

--
Sent from: http://forum.openscad.org/

hi i dont like this instruction because it is not clear in the formalism wether x or y are calculated first see this example, where tube is any module : //rotate([0,45,0]) rotate([45,0,0]) tube(); rotate([45,0,0]) rotate([0,45,0]) tube(); rotate([45,45,0]) tube(); now, i needed something to automatically put a z-oriented object (say, a cylinder) to any [x,y,z] direction if it can be usegul : module pointervers(v) { //v=[x,y,z] x=v[0]; y=v[1]; z=v[2]; rho=sqrt(x*x+y*y+z*z); r=sqrt(x*x+y*y); phi=acos(z/rho); if (r!=0) {theta=acos(x/r)*sign(asin(y/r));} else // cas d'un vecteur v=[0,0,-1] {theta=0;} echo(theta); for (i=[0,$children-1]) { rotate([0,0,theta]) rotate([0,phi,0]) children([i]); } } -- Sent from: http://forum.openscad.org/
T
Troberg
Tue, May 15, 2018 1:38 PM

i dont like this instruction because it is not clear in the formalism

wether
x or y are calculated first

That's one of the reasons I've made some helper modules:

xrot(angle)
yrot(angle)
zrot(angle)

Usually, I only rotate on one axis at the time, and it gives neater code. I
also have similar modules for xtran, ytran and ztran, just to get cleaner
code.

--
Sent from: http://forum.openscad.org/

> i dont like this instruction because it is not clear in the formalism wether x or y are calculated first That's one of the reasons I've made some helper modules: xrot(angle) yrot(angle) zrot(angle) Usually, I only rotate on one axis at the time, and it gives neater code. I also have similar modules for xtran, ytran and ztran, just to get cleaner code. -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Tue, May 15, 2018 2:03 PM

now, i needed something to automatically put a z-oriented object (say, a
cylinder) to any [x,y,z] direction
if it can be usegul :


​I don't like the rotation by Euler angle​s either. In general it seems
more useful something like you did. My version is a bit more general and
simpler:

module rotFromTo(di,do)
if( norm(di-do)==0 || norm(di)==0 || norm(do)==0 )
children();
else
mirror(do/norm(do)+di/norm(di)) mirror(di) children();

It applies the least angle rotation that brings vector di to vector do.

> now, i needed something to automatically put a z-oriented object (say, a > cylinder) to any [x,y,z] direction > if it can be usegul : ‌ ​I don't like the rotation by Euler angle​s either. In general it seems more useful something like you did. My version is a bit more general and simpler: module rotFromTo(di,do) if( norm(di-do)==0 || norm(di)==0 || norm(do)==0 ) children(); else mirror(do/norm(do)+di/norm(di)) mirror(di) children(); It applies the least angle rotation that brings vector di to vector do.
R
runsun
Wed, May 16, 2018 11:53 PM

@ Ronaldo, it's so amazing to me that this can be done in such a concise way.
I think it'd be good especially for alignment 'cos no knowledge of angle is
required.

In the mean time, readers are welcome to check out my version, which allows
for rotating solid obj or a list points about any axis in the space:

<blockquote> https://github.com/runsun/OpenSCAD_Tips/blob/master/snippets.md#rotate_anyaxis // Rotate an obj: rotObj( pq,a ) obj(); // Rotate points: rotPts( pts, pq, a );

function rotM(pq,a) =
(  let(
uv = ( pq[0]-pq[1])/norm(pq[1]- pq[0]) // unit vector
, x=uv[0]
, y=uv[1]
, z=uv[2]
, c=cos(a)
, s=sin(a)
, t=1-c
)
[ [ t*(xx)+c,  t(xy)-sz, t*(xz)+sy ]
, [ t*(xy)+sz, t*(yy)+c,  t(yz)-sx ]
, [ t*(xz)-sy, t*(yz)+sx, t*(z*z)+c  ]
]
);

module rotObj( pq, a )
{
translate( pq[1] )
multmatrix(m= rotM( pq,a) )
{
translate( -1pq[1] )
children();
}
}
function rotPt(pt,pq,a)= rotM(pq,a)
(pt-pq[0]) + pq[0] ;
function rotPts(pts,pq,a)= [ for(p=pts) rotPt(p,pq,a) ] ;

</blockquote>

$  Runsun Pan, PhD $ libs: scadx , doctest , faces ( git ), offline doc ( git ), runscad.py ( 2 , git ), editor of choice: CudaText  ( OpenSCAD lexer ); $ Tips ; $ Snippets

--
Sent from: http://forum.openscad.org/

@ Ronaldo, it's so amazing to me that this can be done in such a concise way. I think it'd be good especially for alignment 'cos no knowledge of angle is required. In the mean time, readers are welcome to check out my version, which allows for rotating solid obj or a list points about any axis in the space: <blockquote> https://github.com/runsun/OpenSCAD_Tips/blob/master/snippets.md#rotate_anyaxis // Rotate an obj: rotObj( pq,a ) obj(); // Rotate points: rotPts( pts, pq, a ); function rotM(pq,a) = ( let( uv = ( pq[0]-pq[1])/norm(pq[1]- pq[0]) // unit vector , x=uv[0] , y=uv[1] , z=uv[2] , c=cos(a) , s=sin(a) , t=1-c ) [ [ t*(x*x)+c, t*(x*y)-s*z, t*(x*z)+s*y ] , [ t*(x*y)+s*z, t*(y*y)+c, t*(y*z)-s*x ] , [ t*(x*z)-s*y, t*(y*z)+s*x, t*(z*z)+c ] ] ); module rotObj( pq, a ) { translate( pq[1] ) multmatrix(m= rotM( pq,a) ) { translate( -1*pq[1] ) children(); } } function rotPt(pt,pq,a)= rotM(pq,a)*(pt-pq[0]) + pq[0] ; function rotPts(pts,pq,a)= [ for(p=pts) rotPt(p,pq,a) ] ; </blockquote> ----- $ Runsun Pan, PhD $ libs: scadx , doctest , faces ( git ), offline doc ( git ), runscad.py ( 2 , git ), editor of choice: CudaText ( OpenSCAD lexer );&nbsp;$ Tips ;&nbsp;$ Snippets -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Thu, May 17, 2018 11:15 AM

From runsun runsun@gmail.com:

@ Ronaldo, it's so amazing to me that this can be done in such a concise
way.
I think it'd be good especially for alignment 'cos no knowledge of angle is
required.


​The principle behind is that any rotation may expressed by composing two
reflections (mirror)​. In this case, you don't need to compute angles to
find the reflections.

Besides the operator rotFromTo, I have a functional version of it that
computes the rotation matrix:

function TrotFromTo(di,do) =
norm(di-do)==0 || norm(di)==0 || norm(do)==0 ?
[[1,0,0],[0,1,0],[0,0,1]] :
Tmirror(do/norm(do)+di/norm(di)) * Tmirror(di);

As expected, it requires a function returning the mirror transformation
matrix:

function Tmirror(v) =
norm(v)==0 ?
[[1,0,0],[0,1,0],[0,0,1]] :

   let(u = v/norm(v))
   [ [1,0,0] - 2*u[0]*u, [0,1,0] - 2*u[1]*u, [0,0,1] - 2*u[2]*u ];
>From runsun <runsun@gmail.com>: > @ Ronaldo, it's so amazing to me that this can be done in such a concise > way. > I think it'd be good especially for alignment 'cos no knowledge of angle is > required. ‌ ​The principle behind is that any rotation may expressed by composing two reflections (mirror)​. In this case, you don't need to compute angles to find the reflections. Besides the operator rotFromTo, I have a functional version of it that computes the rotation matrix: function TrotFromTo(di,do) = norm(di-do)==0 || norm(di)==0 || norm(do)==0 ? [[1,0,0],[0,1,0],[0,0,1]] : Tmirror(do/norm(do)+di/norm(di)) * Tmirror(di); As expected, it requires a function returning the mirror transformation matrix: function Tmirror(v) = norm(v)==0 ? [[1,0,0],[0,1,0],[0,0,1]] : let(u = v/norm(v)) [ [1,0,0] - 2*u[0]*u, [0,1,0] - 2*u[1]*u, [0,0,1] - 2*u[2]*u ];
VD
Vincent Douce Mathoscope
Fri, May 18, 2018 7:18 AM

hi
i am working on your codes, but i enconter something that i dont understand :
if (3!=0) {a=2;echo(a);}
echo(a);
the second echo(a); returns "undef" as if the variable a was defined only inside the {if}
how shall i understand this ?
Vincent

hi i am working on your codes, but i enconter something that i dont understand : if (3!=0) {a=2;echo(a);} echo(a); the second echo(a); returns "undef" as if the variable a was defined only inside the {if} how shall i understand this ? Vincent
JB
Jordan Brown
Fri, May 18, 2018 2:51 PM

On 5/18/2018 12:18 AM, Vincent Douce Mathoscope wrote:

hi
i am working on your codes, but i enconter something that i dont understand :
if (3!=0) {a=2;echo(a);}
echo(a);
the second echo(a); returns "undef" as if the variable a was defined only inside the {if}
how shall i understand this ?

This might well be the most common OpenSCAD question.

OpenSCAD variables... aren't variables.  They're constants, sort of,
with the last assignment winning and with inner scopes able to override
values from outer scopes.  You can't change them, or at least not
exactly, and you especially can't change them inside an "if".

x=1;
echo(x=x);
x=2;
echo(x=x);

produces

ECHO: x = 2
ECHO: x = 2

and

x=1;
echo(x=x);
if (true) {
    x=2;
    echo (x=x);
}
echo (x=x);

produces

ECHO: x = 1
ECHO: x = 2
ECHO: x = 1

If you need to set a value conditionally, you need to use the ? :
operator, e.g.

a = (3 != 0) ? 2 : 1;
On 5/18/2018 12:18 AM, Vincent Douce Mathoscope wrote: > hi > i am working on your codes, but i enconter something that i dont understand : > if (3!=0) {a=2;echo(a);} > echo(a); > the second echo(a); returns "undef" as if the variable a was defined only inside the {if} > how shall i understand this ? This might well be the most common OpenSCAD question. OpenSCAD variables... aren't variables.  They're constants, sort of, with the last assignment winning and with inner scopes able to override values from outer scopes.  You can't change them, or at least not exactly, and you especially can't change them inside an "if". x=1; echo(x=x); x=2; echo(x=x); produces ECHO: x = 2 ECHO: x = 2 and x=1; echo(x=x); if (true) { x=2; echo (x=x); } echo (x=x); produces ECHO: x = 1 ECHO: x = 2 ECHO: x = 1 If you need to set a value conditionally, you need to use the ? : operator, e.g. a = (3 != 0) ? 2 : 1;
R
runsun
Sat, May 19, 2018 2:24 AM

@ Ronaldo, Thx for sharing. Your code, as usual, is concise and elegant. It's
also much easier to use than mine for rotations around the origin.


$  Runsun Pan, PhD $ libs: scadx , doctest , faces ( git ), offline doc ( git ), runscad.py ( 2 , git ), editor of choice: CudaText  ( OpenSCAD lexer ); $ Tips ; $ Snippets

--
Sent from: http://forum.openscad.org/

@ Ronaldo, Thx for sharing. Your code, as usual, is concise and elegant. It's also much easier to use than mine for rotations around the origin. ----- $ Runsun Pan, PhD $ libs: scadx , doctest , faces ( git ), offline doc ( git ), runscad.py ( 2 , git ), editor of choice: CudaText ( OpenSCAD lexer );&nbsp;$ Tips ;&nbsp;$ Snippets -- Sent from: http://forum.openscad.org/
R
runsun
Sat, May 19, 2018 4:16 AM

@ vincent,

Your issue with the variable can be solved by changing this part of your
code,

if (r!=0)
{theta=acos(x/r)*sign(asin(y/r));}
else // cas d'un vecteur v=[0,0,-1]
{theta=0;}

to

theta= r!=0? acos(x/r)*sign(asin(y/r)):0;

Also, note that your code is not a one-step rotation as you described in
"put a z-oriented object (say, a
cylinder) to any [x,y,z] direction". There's an extra twist other than the
rotation from z to [x,y,z].

Suppose we want to rotate a cube from P=[0,0,4] to Q=[2,2,2]. This would
imply a rotation about axis [[-1,1,0],[0,0,0],[1,-1,0]] (red line below) by
an angle= 54.7356 :

http://forum.openscad.org/file/t602/180518_rotation_test_starting_cube.png

Both of Ranaldo's and my codes,

module C(){ translate([-2,0,0]) cube([2,1,3]); }
P= [0,0,4];
Q= [2,2,2];
color("green") rotFromTo( di=P, do=Q) C();  // Ronaldo's code
color("green") rotObj( axis=[[-1,1,0],[1,-1,0]], a= 54.7356 ) C();  //
runsun's code

color("red") pointervers(Q)  C();

results in :
http://forum.openscad.org/file/t602/180518_rotation_test_vincent_mathoscope.png

I'm not sure if that's intended. The twist is hard to spot if the starting
obj is a cylinder aligning w/ the z-axis. IMO, the extra twist makes it
harder to use in the context of "put a z-oriented objec to any [x,y,z]
direction".


$  Runsun Pan, PhD $ libs: scadx , doctest , faces ( git ), offline doc ( git ), runscad.py ( 2 , git ), editor of choice: CudaText  ( OpenSCAD lexer ); $ Tips ; $ Snippets

--
Sent from: http://forum.openscad.org/

@ vincent, Your issue with the variable can be solved by changing this part of your code, > if (r!=0) > {theta=acos(x/r)*sign(asin(y/r));} > else // cas d'un vecteur v=[0,0,-1] > {theta=0;} to > theta= r!=0? acos(x/r)*sign(asin(y/r)):0; Also, note that your code is not a one-step rotation as you described in "put a z-oriented object (say, a cylinder) to any [x,y,z] direction". There's an extra twist other than the rotation from z to [x,y,z]. Suppose we want to rotate a cube from *P=[0,0,4]* to *Q=[2,2,2]*. This would imply a rotation about axis [[-1,1,0],[0,0,0],[1,-1,0]] (red line below) by an angle= *54.7356* : <http://forum.openscad.org/file/t602/180518_rotation_test_starting_cube.png> Both of Ranaldo's and my codes, > module C(){ translate([-2,0,0]) cube([2,1,3]); } > P= [0,0,4]; > Q= [2,2,2]; > color("green") rotFromTo( di=P, do=Q) C(); // Ronaldo's code > color("green") rotObj( axis=[[-1,1,0],[1,-1,0]], a= 54.7356 ) C(); // > runsun's code result in the same outcome: <http://forum.openscad.org/file/t602/180518_rotation_test_Ronaldo_runsun.png> Your code: > color("red") pointervers(Q) C(); results in : <http://forum.openscad.org/file/t602/180518_rotation_test_vincent_mathoscope.png> I'm not sure if that's intended. The twist is hard to spot if the starting obj is a cylinder aligning w/ the z-axis. IMO, the extra twist makes it harder to use in the context of "put a z-oriented objec to any [x,y,z] direction". ----- $ Runsun Pan, PhD $ libs: scadx , doctest , faces ( git ), offline doc ( git ), runscad.py ( 2 , git ), editor of choice: CudaText ( OpenSCAD lexer );&nbsp;$ Tips ;&nbsp;$ Snippets -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Sat, May 19, 2018 10:12 AM

​​
Module ​pointervers(v) produces a rotation that brings [0,0,1] to v.
My module rotFromTo(di,do) produces a rotation that brings di to do.
​The point is that there is an infinite set of rotations that bring a
vector to another.​ For instance,

rotFromTo(w,d0) rotFromTo(di,w)

​is able to bring di to do with a different rotation for (almost) any
​other vector w.

rotFromTo chooses one specific rotation among that set: the rotation with
the minimum angle. The minimum rotation is unique and well defined: its
axis is cross(di,do).

In general, module pointvers(v) does not compute the minimum rotation
(except in trivial cases). That is fine but it has a major drawback: it is
not continuous in v. I would expect that for v very near to [0,0,1],
pointvers(v)
be very near to the identity and that is not true. For v near to [0,0,1],
the internally computed angle phi is near to 0 but theta is not.

​​ Module ​pointervers(v) produces a rotation that brings [0,0,1] to v. My module rotFromTo(di,do) produces a rotation that brings di to do. ​The point is that there is an infinite set of rotations that bring a vector to another.​ For instance, rotFromTo(w,d0) rotFromTo(di,w) ​is able to bring di to do with a different rotation for (almost) any ​other vector w. rotFromTo chooses one specific rotation among that set: the rotation with the minimum angle. The minimum rotation is unique and well defined: its axis is cross(di,do). In general, module pointvers(v) does not compute the minimum rotation (except in trivial cases). That is fine but it has a major drawback: it is not continuous in v. I would expect that for v very near to [0,0,1], pointvers(v) be very near to the identity and that is not true. For v near to [0,0,1], the internally computed angle phi is near to 0 but theta is not. ‌