You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/tutorials/2D transformations.rst
+99-119
Original file line number
Diff line number
Diff line change
@@ -55,17 +55,16 @@ Here is code that draws the rectangle in red by changing its coordinates, then d
55
55
56
56
# draw a translucent blue rectangle by translating the grid
57
57
fill(0, 0, 255, 128)
58
-
push_matrix()
59
-
translate(60, 80)
60
-
rect((20, 20), 40, 40)
61
-
pop_matrix()
58
+
with push_matrix():
59
+
translate(60, 80)
60
+
rect((20, 20), 40, 40)
62
61
63
62
if__name__=='__main__':
64
63
run()
65
64
66
-
Let’s look at the translation code in more detail. ``push_matrix()`` is a built-in function that saves the current position of the coordinate system. The ``translate(60, 80)`` moves the coordinate system 60 units right and 80 units down. The ``rect((20, 20), 40, 40)`` draws the rectangle at the same place it was originally. Remember, the things you draw don’t move—the grid moves instead. Finally, ``pop_matrix()`` restores the coordinate system to the way it was before you did the translate.
65
+
Let’s look at the translation code in more detail. ``push_matrix()`` is a built-in function that saves the current position of the coordinate system. The ``translate(60, 80)`` moves the coordinate system 60 units right and 80 units down. The ``rect((20, 20), 40, 40)`` draws the rectangle at the same place it was originally. Remember, the things you draw don’t move—the grid moves instead. Finally, when the ``with`` context ends, it "pops" and restores the coordinate system to the way it was before you did the translate.
67
66
68
-
Yes, you could have done a ``translate(-60, -80)`` to move the grid back to its original position. However, when you start doing more sophisticated operations with the coordinate system, it’s easier to use ``push_matrix()`` and ``pop_matrix()`` to save and restore the status rather than having to undo all your operations. Later on in this tutorial, you will find out why those functions seem to have such strange names.
67
+
Yes, you could have done a ``translate(-60, -80)`` to move the grid back to its original position. However, when you start doing more sophisticated operations with the coordinate system, it’s easier to use ``with push_matrix():`` to save and then later restore the status rather than having to undo all your operations. Later on in this tutorial, you will find out why those functions seem to have such strange names.
69
68
70
69
What’s the Advantage?
71
70
=====================
@@ -100,12 +99,11 @@ Compare that to the version of the function that uses translate(). In this case,
100
99
.. code:: python
101
100
102
101
defhouse(x, y):
103
-
push_matrix()
104
-
translate(x, y)
105
-
triangle((15, 0), (0, 15), (30, 15))
106
-
rect((0, 15), 30, 30)
107
-
rect((12, 30), 10, 15)
108
-
pop_matrix()
102
+
with push_matrix():
103
+
translate(x, y)
104
+
triangle((15, 0), (0, 15), (30, 15))
105
+
rect((0, 15), 30, 30)
106
+
rect((12, 30), 10, 15)
109
107
110
108
Rotation
111
109
========
@@ -134,11 +132,10 @@ Since most people think in degrees, Processing has a built-in ``radians()`` func
134
132
no_stroke()
135
133
rect((40, 40), 40, 40)
136
134
137
-
push_matrix()
138
-
rotate(radians(45))
139
-
fill(0)
140
-
rect((40, 40), 40, 40)
141
-
pop_matrix()
135
+
with push_matrix():
136
+
rotate(radians(45))
137
+
fill(0)
138
+
rect((40, 40), 40, 40)
142
139
143
140
if__name__=='__main__':
144
141
run()
@@ -179,17 +176,16 @@ And here is the code and its result, without the grid marks.
179
176
no_stroke()
180
177
rect((40, 40), 40, 40)
181
178
182
-
push_matrix()
183
-
# move the origin to the pivot point
184
-
translate(40, 40)
179
+
withpush_matrix():
180
+
# move the origin to the pivot point
181
+
translate(40, 40)
185
182
186
-
# then pivot the grid
187
-
rotate(radians(45))
183
+
# then pivot the grid
184
+
rotate(radians(45))
188
185
189
-
# and draw the square at the origin
190
-
fill(0)
191
-
rect((0, 0), 40, 40)
192
-
pop_matrix()
186
+
# and draw the square at the origin
187
+
fill(0)
188
+
rect((0, 0), 40, 40)
193
189
194
190
if__name__=='__main__':
195
191
run()
@@ -214,11 +210,10 @@ And here is a program that generates a wheel of colors by using rotation. The sc
214
210
frame_count *5%255,
215
211
frame_count *7%255)
216
212
217
-
push_matrix()
218
-
translate(100, 100)
219
-
rotate(radians(frame_count *2%360))
220
-
rect((0, 0), 80, 20)
221
-
pop_matrix()
213
+
with push_matrix():
214
+
translate(100, 100)
215
+
rotate(radians(frame_count *2%360))
216
+
rect((0, 0), 80, 20)
222
217
223
218
if__name__=='__main__':
224
219
run()
@@ -244,10 +239,9 @@ The final coordinate system transformation is scaling, which changes the size of
244
239
rect((20, 20), 40, 40)
245
240
246
241
stroke(0)
247
-
push_matrix()
248
-
scale(2.0)
249
-
rect((20, 20), 40, 40)
250
-
pop_matrix()
242
+
with push_matrix():
243
+
scale(2.0)
244
+
rect((20, 20), 40, 40)
251
245
252
246
if__name__=='__main__':
253
247
run()
@@ -279,36 +273,34 @@ When you do multiple transformations, the order makes a difference. A rotation f
279
273
line((0, 0), (200, 0)) # draw axes
280
274
line((0, 0), (0, 200))
281
275
282
-
push_matrix()
283
-
fill(255, 0, 0) # red square
284
-
rotate(radians(30))
285
-
translate(70, 70)
286
-
scale(2.0)
287
-
rect((0, 0), 20, 20)
288
-
pop_matrix()
289
-
290
-
push_matrix()
291
-
fill(255) # white square
292
-
translate(70, 70)
293
-
rotate(radians(30))
294
-
scale(2.0)
295
-
rect((0, 0), 20, 20)
296
-
pop_matrix()
276
+
with push_matrix():
277
+
fill(255, 0, 0) # red square
278
+
rotate(radians(30))
279
+
translate(70, 70)
280
+
scale(2.0)
281
+
rect((0, 0), 20, 20)
282
+
283
+
with push_matrix():
284
+
fill(255) # white square
285
+
translate(70, 70)
286
+
rotate(radians(30))
287
+
scale(2.0)
288
+
rect((0, 0), 20, 20)
297
289
298
290
if__name__=='__main__':
299
291
run()
300
292
301
293
The Transformation Matrix
302
294
=========================
303
295
304
-
Every time you do a rotation, translation, or scaling, the information required to do the transformation is accumulated into a table of numbers. This table, or matrix has only a few rows and columns, yet, through the miracle of mathematics, it contains all the information needed to do any series of transformations. And that’s why the ``push_matrix()` and ``pop_matrix()`` have that word in their name.
296
+
Every time you do a rotation, translation, or scaling, the information required to do the transformation is accumulated into a table of numbers. This table, or matrix has only a few rows and columns, yet, through the miracle of mathematics, it contains all the information needed to do any series of transformations. And that’s why ``push_matrix()`` has that word in their name.
305
297
306
-
Push and Pop
298
+
Push (and Pop)
307
299
============
308
300
309
-
What about the push and pop part of the names? These come from a computer concept known as a stack, which works like a spring-loaded tray dispenser in a cafeteria. When someone returns a tray to the stack, its weight pushes the platform down. When someone needs a tray, he takes it from the top of the stack, and the remaining trays pop up a little bit.
301
+
What about the push part of the name? It comes from a computer concept known as a stack, which works like a spring-loaded tray dispenser in a cafeteria. When someone returns a tray to the stack, its weight pushes the platform down. When someone needs a tray, he takes it from the top of the stack, and the remaining trays pop up a little bit.
310
302
311
-
In a similar manner, ``push_matrix()`` puts the current status of the coordinate system at the top of a memory area, and ``pop_matrix()`` pulls that status back out. The preceding example used ``push_matrix()`` and ``pop_matrix()`` to make sure that the coordinate system was “clean” before each part of the drawing. In all of the other examples, the calls to those two functions weren’t really necessary, but it doesn’t hurt anything to save and restore the grid status.
303
+
In a similar manner, ``push_matrix()`` puts the current status of the coordinate system at the top of a memory area. When the `with` exits the context automatically "pops" and pulls that status back out. The preceding example used ``push_matrix()`` to make sure that the coordinate system was “clean” before each part of the drawing. In all of the other examples, the calls to those two functions weren’t really necessary, but it doesn’t hurt anything to save and restore the grid status.
312
304
313
305
Note: in Processing, the coordinate system is restored to its original state (origin at the upper left of the window, no rotation, and no scaling) every time that the ``draw()`` function is executed.
314
306
@@ -381,16 +373,14 @@ Now, separate the code for drawing the left and right arms, and move the center
381
373
ellipse((47, 12), 12, 12) # right eye
382
374
383
375
defdrawLeftArm():
384
-
push_matrix()
385
-
translate(12, 32)
386
-
rect((-12, 0), 12, 37)
387
-
pop_matrix()
376
+
with push_matrix():
377
+
translate(12, 32)
378
+
rect((-12, 0), 12, 37)
388
379
389
380
defdrawRightArm():
390
-
push_matrix()
391
-
translate(66, 32)
392
-
rect((0, 0), 12, 37)
393
-
pop_matrix()
381
+
with push_matrix():
382
+
translate(66, 32)
383
+
rect((0, 0), 12, 37)
394
384
395
385
Now test to see if the arms rotate properly. Rather than attempt a full animation, we will just rotate the left side arm 135 degrees and the right side arm -45 degrees as a test. Here is the code that needs to be added, and the result. The left side arm is cut off because of the window boundaries, but we’ll fix that in the final animation.
396
386
@@ -400,18 +390,16 @@ Now test to see if the arms rotate properly. Rather than attempt a full animatio
400
390
.. code:: python
401
391
402
392
defdrawLeftArm():
403
-
push_matrix()
404
-
translate(12, 32)
405
-
rotate(radians(135))
406
-
rect((-12, 0), 12, 37)
407
-
pop_matrix()
393
+
with push_matrix():
394
+
translate(12, 32)
395
+
rotate(radians(135))
396
+
rect((-12, 0), 12, 37)z
408
397
409
398
defdrawRightArm():
410
-
push_matrix()
411
-
translate(66, 32)
412
-
rotate(radians(-45))
413
-
rect((0, 0), 12, 37)
414
-
pop_matrix()
399
+
with push_matrix():
400
+
translate(66, 32)
401
+
rotate(radians(-45))
402
+
rect((0, 0), 12, 37)
415
403
416
404
Now we complete the program by putting in the animation. The left arm has to rotate from 0° to 135° and back. Since the arm-waving is symmetric, the right-arm angle will always be the negative value of the left-arm angle. To make things simple, we will go in increments of 5 degrees.
417
405
@@ -431,18 +419,16 @@ Now we complete the program by putting in the animation. The left arm has to rot
431
419
global armAngle, angleChange, ANGLE_LIMIT
432
420
background(255)
433
421
434
-
push_matrix()
435
-
translate(50, 50) # place robot so arms are always on screen
436
-
drawRobot()
437
-
armAngle += angleChange
438
-
439
-
# if the arm has moved past its limit,
440
-
# reverse direction and set within limits.
441
-
if armAngle >ANGLE_LIMITor armAngle <0:
442
-
angleChange =-angleChange
443
-
armAngle += angleChange
422
+
with push_matrix():
423
+
translate(50, 50) # place robot so arms are always on screen
424
+
drawRobot()
425
+
armAngle += angleChange
444
426
445
-
pop_matrix()
427
+
# if the arm has moved past its limit,
428
+
# reverse direction and set within limits.
429
+
if armAngle >ANGLE_LIMITor armAngle <0:
430
+
angleChange =-angleChange
431
+
armAngle += angleChange
446
432
447
433
defdrawRobot():
448
434
no_stroke()
@@ -461,18 +447,16 @@ Now we complete the program by putting in the animation. The left arm has to rot
461
447
ellipse((47, 12), 12, 12) # right eye
462
448
463
449
defdrawLeftArm():
464
-
push_matrix()
465
-
translate(12, 32)
466
-
rotate(radians(armAngle))
467
-
rect((-12, 0), 12, 37)
468
-
pop_matrix()
450
+
with push_matrix():
451
+
translate(12, 32)
452
+
rotate(radians(armAngle))
453
+
rect((-12, 0), 12, 37)
469
454
470
455
defdrawRightArm():
471
-
push_matrix()
472
-
translate(66, 32)
473
-
rotate(radians(-armAngle))
474
-
rect((0, 0), 12, 37)
475
-
pop_matrix()
456
+
with push_matrix():
457
+
translate(66, 32)
458
+
rotate(radians(-armAngle))
459
+
rect((0, 0), 12, 37)
476
460
477
461
if__name__=='__main__':
478
462
run()
@@ -505,11 +489,10 @@ Because this is a new concept, rather than integrate it into the robot program,
505
489
angle = atan2(mouse_y -100, mouse_x -100)
506
490
507
491
background(255)
508
-
push_matrix()
509
-
translate(100, 100)
510
-
rotate(angle)
511
-
rect((0, 0), 50, 10)
512
-
pop_matrix()
492
+
with push_matrix():
493
+
translate(100, 100)
494
+
rotate(angle)
495
+
rect((0, 0), 50, 10)
513
496
514
497
if__name__=='__main__':
515
498
run()
@@ -549,37 +532,34 @@ At this point, we can write the final version of the arm-tracking program. We st
549
532
550
533
background(255)
551
534
552
-
push_matrix()
553
-
translate(ROBOT_X, ROBOT_Y) # place robot so arms are always on screen
554
-
if mouse_is_pressed:
555
-
mX = mouse_x - ROBOT_X
556
-
mY = mouse_y - ROBOT_Y
535
+
with push_matrix():
536
+
translate(ROBOT_X, ROBOT_Y) # place robot with arms always on screen
The ``drawRobot()`` function remains unchanged, but a minor change to ``drawLeftArm()`` and ``drawRightArm()`` is now necessary. Because ``leftArmAngle`` and ``rightArmAngle`` are now computed in radians, the functions don’t have to do any conversion. The changes to the two functions are in bold.
0 commit comments