Hello,
I'm new to OpenSCAD and I have a little problem with Rotate. rotating around 2 axis does not work properly for me. see the source in screenshots please. I typed all objects manually to prevent any mistake in modules here is what I want to achieve here is what I get the difference is in the style how I use the rotate function. rotate(a=45,v=[1,1,0])  this rotates object improperly rotate([45,45,0])  this rotates object improperly rotate(a=1,v=[45,45,0])  this rotates object properly but i cannot use it because the X and Y angles are not the same in my project could please somebody explain the difference in these three examples? maybe they are totally different or should not be used like this. thank you! 
Hello and welcome to using
OpenSCAD!
Rotation is a pain point for many newcomers and it can certainly be unintuitive. I don't have time to go too far into the details, and there are many tutorials online, but here's a little food for thought: You can think of the standard rotate([rx,ry,rz]) command as expanding to rotate([0,0,rz]) rotate([0,ry,0]) rotate([rx,0,0]). The order of rotation matters. The rotate command first rotates around X, then Y, then Z. If you want the rotations in a different order, use multiple rotate commands. Try playing around with this to see what I mean: rx = 20;
ry = 30; rz = 50; color("white") rotate([0,0,rz]) rotate([0,ry,0]) rotate([rx,0,0]) translate([20,0,0]) cube(2, true); color("blue") rotate([rx,ry,rz]) translate([20,0,0]) cube(2, true); color("red") rotate([rz,ry,rx]) translate([20,0,0]) cube(2, true); The reason your rotate(a=45,v=[1,1,0]) example works is because you are specifically rotating around the axis defined by x=1,y=1,z=0. To help visualize this, try the following: // The axis of rotation
v = [10,10,0]; // Do the rotation for(t=[0:30:359]) rotate(t, v) translate([10,0,0]) color(t==0?"green":"blue") cube(2, true); // Visualize the plane color("red") hull() { sphere(.25); translate(v) sphere(.25, true); } It should look like this: Note: My understanding of all this isn't perfect, so forgive me if I've made a mistake here. If anyone else has corrections, please chime in :) ~ Yona
_______________________________________________ OpenSCAD mailing list [hidden email] http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org 
Hi Hypher,
thanks for the explanation, now I finally got it. So I need to create axis by defining a vector and then tilt the object on the surface defined by 0,0,0 and the new axis. this is what helped to explain The reason your rotate(a=45,v=[1,1,0]) example works is because you are specifically rotating around the axis defined by x=1,y=1,z=0. BIG THANKS!!! 
In reply to this post by s3030150
v is the axis of rotation, so the following v settings are the same: v= [1,1,0] v= [45,45,0] v= [100,100,0] They all mean a line on the xy plane, from [0,0,0] and divides xy plane by equal halves. It'd be 45degree to the xaxis and 45degree to y. So your first style is basically the same as the 3rd one, except they rotate by different angles  rotate the 3rd one 45 times would be the same as rotate the 1st one once. The second one rotates about x by 45, then rotate about y by 45.
$ Runsun Pan, PhD
$ libs: scadx, doctest, faces(git), offline doc(git), runscad.py(2,git), editor of choice: CudaText ( OpenSCAD lexer); $ Tips; $ Snippets 
I now have a better understanding of rotate() after reading this thread, and doing some research. If you compose two rotations, the result is always another rotation. As Hypher has pointed out, the order in which you compose rotations matters. Composition is not commutative. As far as I can tell, rotate([x,y,z]) specifies a rotation about some arbitrary axis by (in a way) specifying the x, y and z components of the rotation. But it's not as clean as that, because there are lots of different ways to specify a 3D rotation using 3 angles, and none of them are intuitive to me. Also, the order in which the x,y,z rotations are applied is significant: the 3 numbers aren't orthogonal in the way that Euclidean [x,y,z] coordinates are orthogonal. So this interface is quite arbitrary. The Euler theorum states that you can describe any 3D rotation using 3 angles, which are called Euler angles. There are apparently many different conventions for specifying Euler angles. I found a Python package that gives you a choice between 24 different conventions. In summary, the rotate([x,y,z]) interface is tricky to understand. I haven't worked through the math to come up with a way to predict what the resulting axis of rotation is. On 9 April 2016 at 12:13, runsun <[hidden email]> wrote: s3030150 wrote _______________________________________________ OpenSCAD mailing list [hidden email] http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org 
This post has NOT been accepted by the mailing list yet.
thank you. in the meantime I figured out how to do what I wanted to do. solution for me was adding a cosinus to the rotation in second axis.
like this: oelevate=elevate/cos(nangle); here is my source, you can try it with and without the cos(), you can see what my problem was. now it's solved, thank you very much! heght=80; wallthickness=0.7; radius=7; acount=5; heghtobject=30; widthbase=200; heghtbase=5; fine=100; xangle=atan((radiuswallthickness/2)/heght)*2; totalangle=acount*xangle; module komp() { difference() { cylinder(h=heght, r1=0, r2=radius, center=false, $fn=fine); cylinder(h=heght+1, r1=0, r2=radiuswallthickness, center=false, $fn=fine); } } module rad(elevate) { xa=0; for(angle=[0:acount1]) { nangle=angle*xangletotalangle/2+xangle/2; oelevate=elevate/cos(nangle); // try to remove the cosinus rotate(oelevate,[1,0,0]) rotate(nangle,[0,1,0]) komp(); } } module drawall() { for(rr=[0:acount1]) { fangle=rr*xangletotalangle/2+xangle/2; rad(fangle); } } module vrch() { difference() { translate([0,0,heght+heghtobject]) drawall(); translate([widthbase/2,widthbase/2, heght+heghtobject]) cube([widthbase,widthbase,heghtheghtobject]); } } r2=acount*(heghtheghtobject)*1.2*tan(xangle); echo(r2); translate([0,0,heghtbase]) vrch(); translate([0,0,heghtbase]) difference() { scale([1,1,10]) rotate(180,[1,0,0]) vrch(); translate([100,100,450heghtbase*2]) cube([200,200,450+heghtbase]); } underbase2=radius*acount*2*0.75; translate([underbase2/2,underbase2/2,0]) minkowski() { cube([underbase2,underbase2,5],$fn=4); cylinder(h=4,r1=4,r2=0,$fn=fine); } 
In reply to this post by doug.moen
On 09. april 2016 19:18, doug moen wrote:
> In summary, the rotate([x,y,z]) interface is tricky to understand. I > haven't worked through the math to come up with a way to predict what > the resulting axis of rotation is. In my opinion the interface is not usable if you consider the values angles around the global axes as you explained. the only practical way to use it is to apply one value at a time and leave the others zero. To rotate e.g. 30 degrees around Y followed by 60 degrees around X, you need to do rotate([60,0,0]) rotate([0,30,0]) cube([10,20,30]); The above is not at all the same as rotate([60,30,0]) cube([10,20,30]); For this reason I introduced a different interface in AngelScript CSG where there are rotate_x(angle), rotate_y(angle), rotate_z(angle) operators. There is however, one scenario where the OpenSCAD rotate syntax makes a lot of sense: when you rotate around some arbitrary axis. For example to rotate 60 degrees around the axis [x,y]=[1,1] rotate(a=60,v=[1,1]) cube([10,20,30]); This format makes sense and can be extended to 3d, but in practice I guess it isn't much used. Carsten Arnholm _______________________________________________ OpenSCAD mailing list [hidden email] http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org 
When using rotate with x,y & z angles, OpenSCAD first rotates about the x axis.
The result is then rotated about the y axis. Finally, this result is rotated about the z axis. for example: rotate([60,30,0]) cube([10,20,30]); is equivalent to: rotate([0,30,0]) rotate([60,0,0]) cube([10,20,30]); which is equivalent to: rotate([0,30,0]) { rotate([60,0,0]) { cube([10,20,30]); }} since the rotate nearest to cube is performed first.
Larry

In reply to this post by cacb
>In my opinion the interface is not usable if you consider the values
angles around the global axes as you explained. the only practical way
to use it is to apply one value at a time and leave the others zero. In my experience most objects get rotated by +/90 or 180 around one of more of the global axes, so I can always pick and order that is x,y,z and use a single rotate([x, y, z]). Nearly always one of those is 0. It is rare that I need to split it into two rotates because I want a different order.On 9 April 2016 at 19:17, Carsten Arnholm <[hidden email]> wrote: On 09. april 2016 19:18, doug moen wrote: _______________________________________________ OpenSCAD mailing list [hidden email] http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org 
In reply to this post by cacb
Carsten said: >In my opinion the interface is not usable if you consider the values angles >around the global axes as you explained. the only practical way to use it is >to apply one value at a time and leave the others zero. > >For this reason I introduced a different interface in AngelScript CSG where >there are rotate_x(angle), rotate_y(angle), rotate_z(angle) operators. If you define the basis vectors X = [1,0,0]; Y = [0,1,0]; Z = [0,0,1]; then rotate([a,0,0]) is rotate(a,X) rotate([0,a,0]) is rotate(a,Y) rotate([0,0,a]) is rotate(a,Z) That's a more flexible alternative to rotate_x(), rotate_y(), rotate_z(). The same arguments would work with mirror(), which takes a vector argument: mirror(X)  reflect through the origin along the X axis mirror(Y) mirror(Z) On 9 April 2016 at 14:17, Carsten Arnholm <[hidden email]> wrote: On 09. april 2016 19:18, doug moen wrote: _______________________________________________ OpenSCAD mailing list [hidden email] http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org 
On 09. april 2016 22:05, doug moen wrote:
> The same arguments would work with mirror(), which takes a vector argument: > mirror(X)  reflect through the origin along the X axis > mirror(Y) > mirror(Z) I don't think so. Regarding mirror transformations, the more interesting thing is that it unnecessarily restricted to perform mirroring only through the origin. Mirroring through an arbitrary point is useful. Carsten Arnholm _______________________________________________ OpenSCAD mailing list [hidden email] http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org 
On 09. april 2016 22:18, Carsten Arnholm wrote:
> Regarding mirror transformations, the more interesting thing is that it > is unnecessarily restricted to perform mirroring only through the origin. > Mirroring through an arbitrary point is useful. This restriction applied to AngelScript CSG as well, but it is easily removed. An OpenSCAD trivial base case serves as an example: module sph1() { translate([0,100,0])sphere(30); } sph1(); mirror([1,1,0])sph1(); As the manual says, it "Mirrors the child element on a plane through the origin". However, restricting the mirror plane to go through the origin only is unnecessary. A couple of AngelScript CSG snippets of the same case follow. First, the same "OpenSCADstyle mirroring" around origin: solid@ sph1 = translate(0,100,0)*sphere(30); solid@ sph2 = mirror(1,1,0)*sph1; second, same as above, just using explicit vector argument for the mirror normal, the mirror plane point still defaults to origin: solid@ sph2 = mirror(vec3d(1,1,0))*sph1; third, same plane normal, but using mirror plane point different from origin: solid@ sph2 = mirror(vec3d(1,1,0),pos3d(100,100,0))*sph1; The third case obviously gives a different result than the two first cases, sph2 ends up at x=100,y=200. This is a useful and practical scenario that I think isn't quite as easily expressed in OpenSCAD, so it might be something to consider. Carsten Arnholm _______________________________________________ OpenSCAD mailing list [hidden email] http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org 
In reply to this post by cacb
Carsten said: "Regarding mirror transformations, the more interesting thing is that it unnecessarily restricted to perform mirroring only through the origin. Mirroring through an arbitrary point is useful." This is equally true for rotate, scale and shear transformations. If a shape has its own local origin, then often you want to transform it relative to its local origin. In OpenSCAD, the standard idiom for transforming relative to a shape's local origin is: translate(origin) rotate(R) translate(origin) shape In OpenSCAD2, transformations will be values, so it will be possible to encapsulate this idiom using a function: at(origin,transform)(shape) = translate(origin) transform translate(origin) shape; at(origin, rotate(R)) shape On 9 April 2016 at 16:18, Carsten Arnholm <[hidden email]> wrote: On 09. april 2016 22:05, doug moen wrote: _______________________________________________ OpenSCAD mailing list [hidden email] http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org 
On 10. april 2016 18:22, doug moen wrote:
> In OpenSCAD, the standard idiom for transforming relative to a shape's > local origin is: > translate(origin) rotate(R) translate(origin) shape For rotate, yes you must do that, if rotation around the shape local origin is what you want, or if you want to rotate around some other point. For a mirror plane through an arbitrary point, both the the location of the mirror plane and the shape matters. The position specified with mirror transformation isn't a local transformation origin though, it is any point in the mirror plane, there are infinitely many such points for the same transformation. Using my previous example solid@ sph1 = translate(0,100,0)*sphere(30); The following gives identical mirror transformations, using different points in the same mirror plane: solid@ sph2 = mirror(vec3d(1,1,0),pos3d(100,100,0))*sph1; solid@ sph3 = mirror(vec3d(1,1,0),pos3d(0,200,0))*sph1; solid@ sph4 = mirror(vec3d(1,1,0),pos3d(100,300,0))*sph1; > In OpenSCAD2, transformations will be values, so it will be possible to > encapsulate this idiom using a function: > > at(origin,transform)(shape) = > translate(origin) transform translate(origin) shape; > > at(origin, rotate(R)) shape I am not quite sure how your OpenSCAD2 idiom will handle this case. Perhaps it will work the same. Building it into the mirror transformation directly is relatively straightforward and the standard method I have encountered elsewhere, so it seems natural to me. Carsten Arnholm _______________________________________________ OpenSCAD mailing list [hidden email] http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org 
Yes, I understand why your interface to mirror() could be considered more natural. But it's still true that in OpenSCAD, you use translate(origin) mirror(vec) translate(origin) shape to mirror a shape using a reflection plane passing through 'origin'. It will often be the case that the 'origin' will be located relative to the shape being reflected. On 10 April 2016 at 14:23, Carsten Arnholm <[hidden email]> wrote: On 10. april 2016 18:22, doug moen wrote: _______________________________________________ OpenSCAD mailing list [hidden email] http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org 
Free forum by Nabble  Edit this page 