Question about rotations and math and variables.

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

Question about rotations and math and variables.

kdtop

I want to have a series of labels positioned around a center like spokes on a bicycle wheel.  

So I could do this:

for (angle = [0:15:359])
rotate([0,0,angle])
translate([30,0,0])
text("MyLabel");

When I do this, the text "MyLabel" is rotated in addition to the position being rotated.  But I want them all facing the same way.  So what I really want is just for the position to be rotated.

It seems that this ought to be possible (but it is a syntax error):

for (angle = [0:15:359]) {
  pos = rotate([0,0,angle]) [30,0,0];
  translate(pos)
    text("MyLabel");
}

I know the code below works, but it seems clunky to me.    What I really want is to be able to calculate the rotated position, and then put whatever I want at that point.

for (angle = [0:15:359])
rotate([0,0,angle])
translate([30,0,0])
rotate([0,0,-angle])
text("MyLabel");

At one point, I figured out how to build up an array at run-time.  But it involved recursive code and I can't remember now how I did it.  But if I figured that out again, I suppose I could build up the rotated points in the array, and then iterate through that. 

Questions:
  1. How would I best achieve this?  

  2.  Why doesn't my solution of pos = rotate([0,0,angle]) [30,0,0]; work?  Does Rotate() only act on objects?  What makes an object?

  3. What can be assigned to a variable?  

Thanks in advance

Kevin T


_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: Question about rotations and math and variables.

nophead
1. I would do that as rotate, translate, rotate as you have done but I would use rotate(angle) as a shortcut. When passed a single number rotate rotates around z.

You could make a module that does it.

module rotate_to(pos, angle)
    rotate(angle)
      translate(pos)
        rotate(-angle)
         children();

for (angle = [0:15:359])
   rotate_to([0, 0, 30], angle)
    text("MyLabel");

2. It does not work because you can only assign an expression to a variable but rotate() is a module that acts on its children. Its children are other modules that do transformations or create geometry. You can't assign geometry to variables but you can encapsulate it a module and reuse it. Similarly you can put expressions in functions and reuse them.

3. Only expressions can be assigned to variables. The result must be a number or a string, list, range, etc.

On Wed, 20 Feb 2019 at 16:27, Kevin Toppenberg <[hidden email]> wrote:

I want to have a series of labels positioned around a center like spokes on a bicycle wheel.  

So I could do this:

for (angle = [0:15:359])
rotate([0,0,angle])
translate([30,0,0])
text("MyLabel");

When I do this, the text "MyLabel" is rotated in addition to the position being rotated.  But I want them all facing the same way.  So what I really want is just for the position to be rotated.

It seems that this ought to be possible (but it is a syntax error):

for (angle = [0:15:359]) {
  pos = rotate([0,0,angle]) [30,0,0];
  translate(pos)
    text("MyLabel");
}

I know the code below works, but it seems clunky to me.    What I really want is to be able to calculate the rotated position, and then put whatever I want at that point.

for (angle = [0:15:359])
rotate([0,0,angle])
translate([30,0,0])
rotate([0,0,-angle])
text("MyLabel");

At one point, I figured out how to build up an array at run-time.  But it involved recursive code and I can't remember now how I did it.  But if I figured that out again, I suppose I could build up the rotated points in the array, and then iterate through that. 

Questions:
  1. How would I best achieve this?  

  2.  Why doesn't my solution of pos = rotate([0,0,angle]) [30,0,0]; work?  Does Rotate() only act on objects?  What makes an object?

  3. What can be assigned to a variable?  

Thanks in advance

Kevin T

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: Question about rotations and math and variables.

Ronaldo
In reply to this post by kdtop
  1. How would I best achieve this?  

function rotZ(a,p) = [[cos(a), sin(a),0],[-sin(a),cos(a),0],[0,0,1]]*p;

for (angle = [0:15:359]) {
  pos = rotZ(angle,[30,0,0]);
  translate(pos)
    text("MyLabel");
}

  2.  Why doesn't my solution of pos = rotate([0,0,angle]) [30,0,0]; work?  Does Rotate() only act on objects?  What makes an object?

rotate() is a module and only applies to objects, things like modules or primitive solids (like cube()).
  3. What can be assigned to a variable?  

Just values like numbers, strings, lists.

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: Question about rotations and math and variables.

adrianv
In reply to this post by kdtop
I see that others have already answered, so at the risk of repetition here's
my approach which has some things in common with previously posted answers
but is also a little bit different.  

module circle_distribute(radius, number)
{
  for(angle=[0:360/number:359])
    translate([radius*cos(angle), radius*sin(angle)])
      children();
}

circle_distribute(30,24) text("label");

The circle_distribute module can operate on any object or collection of
objects in braces and will distribute them around the circle.    





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

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: Question about rotations and math and variables.

JordanBrown
In reply to this post by kdtop
On 2/20/2019 8:25 AM, Kevin Toppenberg wrote:
I know the code below works, but it seems clunky to me.    What I really want is to be able to calculate the rotated position, and then put whatever I want at that point.

for (angle = [0:15:359])
rotate([0,0,angle])
translate([30,0,0])
rotate([0,0,-angle])
text("MyLabel");

That's the simplest answer I come up with.  For more complex scenarios involving multiple transformations, I'm not sure but a scheme like you describe might be simpler.

OpenSCAD could, but does not, have a way to feed a point through a series of translations to return a new point.  You can do the math yourself.  If you want to do the math yourself, read up on transformation matrices.  The Wikipedia article is a bit math-heavy but gives some examples.  The OpenSCAD documentation on multmatrix gives a few examples in the context of the multmatrix operator.  OpenSCAD will do the matrix multiplication required.

It would be easy to build up a function library that did transformations.  The various transformation matrices are straightforward to look up, and you combine them and apply them to points with matrix multiplication.  At the risk of betraying my somewhat weak math, just for fun, I threw together such a library at the end of this message.  I supply only rotate, translate, and scale; the rest are left as an exercise for the reader.

At one point, I figured out how to build up an array at run-time.  But it involved recursive code and I can't remember now how I did it.  But if I figured that out again, I suppose I could build up the rotated points in the array, and then iterate through that.

You could.  And there's a decent chance that you could do it with a list comprehension rather than recursion.

But I suspect that building up an array and then walking through it would be more work than just generating the objects while you iterate the first time.

Questions:
  1. How would I best achieve this? 

The double rotate scheme is the best I come up with for this simple case.

  2.  Why doesn't my solution of pos = rotate([0,0,angle]) [30,0,0]; work?  Does Rotate() only act on objects?  What makes an object?

Rotate is a transformation operator, not a function.  Yes, it acts only on objects.  Objects are the 3D and 2D primitives (cube, sphere, et cetera) and user-defined modules made up of those things.

This is a fundamental dichotomy in OpenSCAD.  Objects represent 2D and 3D "things" in the resulting model.  Values are ... not; although you can echo them out to the console they don't directly represent results in the model.

  3. What can be assigned to a variable?  

Values :-)

Numbers, strings, booleans, ranges, vectors, and the undefined value.

Not objects, though of course you can represent proto-objects in coordinate form in vectors.

Here's that library...

//
// Library to perform various transformations on an [x,y,z] point.
//
// Define the various transformation matrices.
function matrix_rotate_x(a) = [
    [  1,       0,       0,      0 ],
    [  0,       cos(a), -sin(a), 0 ],
    [  0,       sin(a),  cos(a), 0 ],
    [  0,       0,       0,      1 ]
];
function matrix_rotate_y(a) = [
    [  cos(a),  0,       sin(a), 0 ],
    [  0,       1,       0,      0 ],
    [ -sin(a),  0,       cos(a), 0 ],
    [  0,       0,       0,      1 ]
];
function matrix_rotate_z(a) = [
    [  cos(a), -sin(a),  0,      0 ],
    [  sin(a),  cos(a),  0,      0 ],
    [  0,       0,       1,      0 ],
    [  0,       0,       0,      1 ]
];
function matrix_translate(o) = [
    [ 1, 0, 0, o.x ],
    [ 0, 1, 0, o.y ],
    [ 0, 0, 1, o.z ],
    [ 0, 0, 0, 1   ]
];
function matrix_scale(s) = [
    [ s.x, 0,   0,   0 ],
    [ 0,   s.y, 0,   0 ],
    [ 0,   0,   s.z, 0 ],
    [ 0,   0,   0,   1 ]
];

// Transform a point to and from the 1x4 form needed for transformation.
function p34(p) = concat(p, 1);
function p43(p4) = [ for(i=[0:2]) p4[i] ];

// Rotate a point around the origin according to the specified angles.
// Angles are rotation around the x axis, y axis, and z axis.
// Rotations are applied in that order.
// The right-hand rule is used.
function rotate(p, angles) = p43(
    matrix_rotate_z(angles.z)
    *matrix_rotate_y(angles.y)
    *matrix_rotate_x(angles.x)
    *p34(p));

// Translate a point by a specified offset.
function translate(p, o) = p43(matrix_translate(o) * p34(p));

// Translate a point by a specified [scalex, scaley, scalez].
function scale(p, s) = p43(matrix_scale(s) * p34(p));

angles = [0, -90, 0];
p = [1,1,1];
echo(rotate(p, [0, 0, 90]));
echo(translate(p, [1, 2, 3]));
echo(scale(p, [1, 2, 3]));


My transformation matrix math is really rusty... I'd be interested in code review of the above.


_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: Question about rotations and math and variables.

lar3ry
In reply to this post by nophead
nophead wrote

> 1. I would do that as rotate, translate, rotate as you have done but I
> would use rotate(angle) as a shortcut. When passed a single number rotate
> rotates around z.
>
> module rotate_to(pos, angle)
>     rotate(angle)
>       translate(pos)
>         rotate(-angle)
>          children();
>
> for (angle = [0:15:359])
>    rotate_to([0, 0, 30], angle)
>     text("MyLabel");

Nice! I already made something useful with it.

module rotate_to(pos, angle) {
    rotate(angle)
      translate(pos)
        rotate(-angle)
         children();
}
for (angle = [1:1:12])
   rotate_to([0, 100, 0], -(angle * 30))
scale([2,2,2])
      text(str(angle));




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

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: Question about rotations and math and variables.

JordanBrown
On 3/5/2019 8:38 AM, lar3ry wrote:
Nice! I already made something useful with it.
module rotate_to(pos, angle) {
    rotate(angle)
      translate(pos)
        rotate(-angle)
         children();
}
for (angle = [1:1:12]) 
   rotate_to([0, 100, 0], -(angle * 30))
scale([2,2,2])
      text(str(angle));


Cool.  Suggest adding halign="center" and valign="center" to the text( ) invocation so that the numbers are centered on their target locations.


_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org