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:
How would I best achieve this?
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?
What can be assigned to a variable?
Thanks in advance
Kevin T
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");
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.
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 kdtop3@gmail.com 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:
How would I best achieve this?
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?
What can be assigned to a variable?
Thanks in advance
Kevin T
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
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");
}
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()).
Just values like numbers, strings, lists.
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([radiuscos(angle), radiussin(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/
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
https://en.wikipedia.org/wiki/Transformation_matrix#Examples_in_2D_computer_graphics
is a bit math-heavy but gives some examples. The OpenSCAD documentation
on multmatrix
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Transformations#multmatrixgives
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
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#List_Comprehensions
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.
nophead wrote
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/
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.