The previous chapter made brief mention of the Current Transformation Matrix (CTM) that is part of the graphics state of a CGContext. The CTM is a coordinate system transformation that maps from user space to device space. Before you can draw any of the graphics primitives supported by Quartz, you have to first place the primitive into a graphics context. If you want to apply a transformation to the graphics you draw, you have two choices. You can either transform the graphic primitives before you draw them, or you can transform the coordinate axes of user space and then draw the graphics. The difference between these two approaches is illustrated in Figure 5.9. Figure 5.9. Geometry Transforms versus Coordinate System Transformations
Figure 5.9 illustrates the process of drawing a heart in the middle of the graphic of a card. The heart path is similar to the one used in Chapter 3, "Introduction to Quartz 2D." The geometry of the heart path is centered on the origin as shown on the left side of Figure 5.9. The first approach to centering the heart is to transform the geometry and then draw it in the context. This approach is shown in the center of Figure 5.9. The transformation moves the heart away from the origin. The second approach is to transform the coordinate system first and then draw the geometry with the new coordinate location. This technique is the one we used to position the heart in the sample code of Chapter 3, which is also illustrated on the right side of Figure 5.9. In this case, the origin has been translated to the center of the card, and when the geometry is drawn (centered around the origin), the heart shape comes along for the ride. Transforming the geometry of the path is a fairly destructive operation. You are actually changing the path itself. If you are trying to draw the path in multiple locations, this can be a problem. Consider if you wanted to use the same path to draw each of the hearts on the image of the playing card in Figure 5.9. If you were transforming the geometry each time you drew a heart, you would have to either copy the path and make changes to the copies, or you would have to carefully calculate relative transformations needed to position the heart each time. If you transform the coordinate system instead, you can reuse the same geometry many times. Quartz 2D provides routines that allow you to directly transform paths. You can use the text matrix to modify text as you draw it. When Quartz draws images, however, it always draws them oriented to the coordinate axes. If you want to transform an image, you will have to modify the coordinate system. Taking all of these facts into consideration, it should be no surprise changing the relationship between the user space and device space coordinate systems, by modifying the CTM, is the most popular technique Quartz 2D applications use to transform graphics. Transforming coordinate systems is not nearly as intuitive as transforming objects. We are all conditioned by our experience with the physical world to think, "I want to 'grab' this graphic and move it here, then twist it like so... and stretch it just a bit." It's easy for us to think about graphics as objects and intuit the proper way to manipulate them to achieve a desired effect. Apart from Star Trek fans, or the occasional astrophysicist, however, we rarely think of achieving the same effects by manipulating the space that our graphics live in. With that in mind, let us explore a model of user space that may make it a bit easier to visualize how working with the CTM affects your graphics. To do that, let's try and create a model for manipulating user space that might make it appeal a bit more to our physical model of the world. Figure 5.10 is a sketch of just such a physical model. Figure 5.10. Illustration of the Physical Model of Transforming the Coordinate System
Imagine for a moment that user space is a boundless, exceedingly flexible sheet. The sheet in question has a horizontal (x) axis and a vertical (y) axis that are marked with a particular scale. In the diagram shown, the coordinate axes and a dotted rectangle helps you see the sheet, but the actual sheet is boundless. When you apply a transformation to the user space coordinate system, you are manipulating the flexible sheet. Translating the coordinate system is the same as sliding the flexible sheet a certain number of rule marks in the direction of its horizontal and vertical axes. Scaling the coordinate system up will stretch the sheet so, moving its rule marks farther apart. Scaling down the coordinate system compresses the flexible sheet, which moves the rule marks closer together. Rotating the user space is the same as turning the sheet about its origin. On top of the sheet sits a viewing window, a hole cut into cardboard if you will, through which you can view user space. This is illustrated in the figure by the rectangular hole in the solid white rectangle. This viewing window represents the graphics device. When the computer first sets up the graphics context, it establishes a relationship between the viewing window and the coordinate axes on the sheet. (Usually the computer will set things up so that the lower left corner of our "viewing window" is over the origin of the user space coordinate system). When you apply transformations to user space, the masking window stays in place, and the flexible sheet "moves" underneath it. After you have finished making your transformations, you draw onto the flexible sheet. You use the rule markings of the sheet's coordinate system as a guide and plot points in that coordinate system to create a graphic. When you have finished drawing, the computer takes any of the graphics you've created that are directly underneath the viewing window and reproduces them, as faithfully as possible, on the device. This model of the user space transformation may help you understand how transformations in user space affect the graphics you draw. The CGContext opaque data type contains three routines that allow you to apply the basic transformations to the user space coordinate system:
In addition to the three basic routines, the CGContext API also includes the method CGContextConcatCTM, which allows you to take a pre-constructed transformation and concatenate it on to the transformation already in the context. Should you ever need to retrieve the transformation in the CTM, you can use the CGContextGetCTM routine. Examining how an application can use these routines when drawing into a context is covered shortly. Before getting to that, however, following is a more in-depth look at what the computer can do with transformations that are not associated with a graphics context. |