Transformations

Meet the Cylinder

Everything from the last lesson (position, size, align=, center=) works exactly the same for a new shape: Cylinder(radius, height, x=0, y=0, z=0). Same base-at-z, centered-on-x/y rule as Box. Try it:

We’re using a cylinder for this lesson on purpose, not just for variety. A box that’s rotated often looks almost the same as before, especially if it’s close to a cube. A cylinder standing up and a cylinder lying down look nothing alike, so it’s much easier to actually see what a transformation did.

Turning Things: rotate()

rotate(shape, angle, axis="z") takes a shape and gives back a new, rotated one. angle is in degrees. axis is "x", "y", or "z" – which direction you’re turning around.

Notice standing never shows up on its own here. That’s on purpose: rotate() consumes the shape you give it, the same way you’d expect if you handed someone a piece of paper and they folded it – you don’t also still have an unfolded copy. Only the result of rotate(...) renders.

You run a = Cylinder(1, 3) then b = rotate(a, 90, axis="x"), and nothing else. What shows up in the scene?

If you rotate a standing cylinder 90° around axis="z", what happens to how it looks?

Try it yourself below before reading on.

A standing cylinder’s own axis is z. Spinning something around its own axis doesn’t change its silhouette at all – it’s the same reason spinning a can of soup in place doesn’t make it look any different, even though it really is turning. This is worth remembering: rotating around the axis a shape is already lined up with is often invisible.

Moving Things: translate()

You already know how to move a shape: give Box/Cylinder their own x=/y=/z=. So why would you ever need translate(shape, x=0, y=0, z=0) too?

Because once you’ve rotated something, its own sense of “up” has changed. A cylinder lying on its side doesn’t have a clean z= to lift it off the ground with any more – its height now runs sideways. translate() moves the finished shape in the scene’s real x/y/z, no matter what it’s been rotated into.

Why does the example above use translate(lying, z=1) instead of just building the cylinder with z=1 in the first place?

Order Matters

translate() and rotate() nest like any other function calls, and like CMU’s own nested function calls, the inside runs first. That means translate(rotate(shape, 90, axis="x"), z=3) and rotate(translate(shape, z=3), 90, axis="x") are not the same thing, even though they use the exact same two operations.

Run that, then look closely at a and b. Try swapping which one has x=4 if you want to line them up side by side for an easier comparison.

translate(rotate(cyl, 90, axis="x"), z=3) -- which happens first?

Checking Your Work

Exercise: build a cylinder that's lying down instead of standing up (its long axis running sideways, not vertically). Any axis, any position -- just make it lie down.

Curve Resolution

A cylinder’s curved side isn’t actually curved – it’s a bunch of flat faces standing close enough together to look round. segments= controls how many:

6 segments makes a hexagon, not a circle. The default is 32, which is usually enough to look smooth. This is the same idea as OpenSCAD’s $fn, if you’ve ever heard of that – just under a name that’s actually legal in Python ($ can’t start a variable name here).

If you’re about to build several cylinders and want them all a little chunkier or a little smoother, you don’t have to repeat segments= on every single one. Set the global SEGMENTS once, and every Cylinder after that point picks it up automatically:

That last one still comes out smooth – giving a shape its own segments= always wins over the global default.

If you set SEGMENTS = 4 before making a Cylinder, what shape do you actually get?

Practice

That’s rotate(), translate(), how they compose, and how to control curve resolution. One more thing worth knowing, in the cheatsheet if you want the details: rotate() can also take a list of three angles instead of one angle and an axis: rotate(shape, [30, 0, 45]) rotates around x, then y, then z, all in one call. Everything in this lesson used the angle, axis="x" form on purpose, since it doesn’t require knowing what a list is yet – but if you’ve used lists before, the list form is there when you want more than one axis at once.