Transformations Unleashed


Earlier in the chapter, when presenting the way that your application can combine the basic transformations to create more complex ones, the code snippets also broached the subject of Quartz 2D transformations not tied to the CTM of a graphics context.

CGAffineTransforms

The Quartz 2D API represents a transformation using the CGAffineTransform. CGAffineTransform is a structure, not an opaque data type (and, therefore, is not referenced through data fields whose type includes Ref as a suffix). The fields of the CGAffineTransform structure are related to the matrix representation of the transformation, which is discussed a bit later.

If your application needs to keep track of a particular transform, all it needs to do is create a variable whose type is CGAffineTransform. From there it can populate the fields of the transform using the routines that appear in the code snippets. The three easiest routines are

CGAffineTransformMakeTranslation CGAffineTransformMakeRotation CGAffineTransformMakeScale 


No surprisingly, these three routines create the basic transformations that have been discussed throughout the chapter. In the code snippets you also saw the routine CGAffineTransformConcat, which combines any two affine transform structures and returns a new structure with the results.

The other routines in previous discussions were

CGAffineTransformTranslate CGAffineTransformRotate CGAffineTransformScale 


The three routines take an existing transform and apply the specified transformation to it. As noted before, when discussing the ordering of transformations, these routines combine the transformations in the opposite from as CGAffineTransformConcat.

We've also already seen the identity transform represented by the symbolic constant CGAffineTransformIdentity. The identity transform gets its name from the fact that if you apply the identity transform to anything (an object, a coordinate system) what you get back out is exactly what you put in. The effect is exactly the same as multiplying any number by one. The transform preserves the "identity" of whatever you provide to it. This makes the identity matrix a good starting point for any other transformations you want to apply.

If you create a CGAffineTransform whose fields are all zeros and use that transformation, the results are undefined. This is a bit like multiplying any number by zero. The entire coordinate system collapses a single point at the origin. Graphics that have been reduced down to nothing with a zero transform cannot be seen and aren't very interesting. Your code should start its transformation work with the identity transformation instead.


Another useful routine is CGAffineTransformInvert which calculates the transformation needed to undo the transformation that you pass to it. All of the affine transformations matrices you create with Quartz 2D should be invertible as long as you construct them using the routines in the Core Graphics APIs and avoid filling in the fields of CGAffineTransform structure directly.

The last three API routines that we will mention here are

CGPointApplyAffineTransform CGSizeApplyAffineTransform CGRectApplyAffineTransform 


In spite of the fact that these routines apply to geometric shapes, these three are defined in the CGAffineTransform.h header file. Your application can uses these three transformations to manipulate basic geometry. The CGRectApplyAffineTransform may require a bit of explanation. If you rotate a rectangle 47 degrees, you no longer have a rectangle. You have a shape that probably resembles something like a diamond. Because the computer cannot represent the resulting, diamond-shaped object as a rectangle, what it can do is calculate the bounding box of such a shape and return that. If you use CGRectAffineTransform, what you get back is the smallest rectangle that could hold the four transformed corners of the original rectangle.

NSAffineTransform

When working through Cocoa, your application can represent an affine transformation using an instance of the NSAffineTransform class. Looking through the interface of this class you will find routines that very closely match those found in the CGAffineTransform interface. When you first create an instance of NSAffineTransform, you will receive an object that represents an identity transformation. You can then modify that transformation using the following methods:

- (void) translateXBy: (float) deltaX yBy: (float) deltaY; - (void) rotateByDegrees: (float) angle; - (void) rotateByRadians: (float) angle; - (void) scaleBy: (float) scale; - (void) scaleXBy: (float) scaleX yBy: (float) scaleY; - (void) invert; 


Using these methods, you can create the basic transformations. When you want to combine the transformations, there are additional methods:

- (void) appendTransform: (NSAffineTransform *) transform; - (void) prependTransform: (NSAffineTransform *)transform; 


These two routines allow you to combine the transformation passed as a parameter with the current object by multiplying in either direction. This can make it easier for your application to select the multiplication order that makes the most sense for the effect you are trying to achieve.

Transforming a Path

Transforming an entire path using the Cocoa APIs is a very straightforward operation. The NSBezierPath class contains a method, transformUsingAffineTransform:, which applies a transformation to all the points that make up a path.

Notably missing from the Quartz 2D API is a single routine that can transform a path using a particular CGAffineTransform. As a general rule, the absence of this routine is not a problem. Most of the time your application will probably construct paths in the context and the computer will apply the CTM to the path before drawing it. In addition, if you build a path using the construction routines of the CGPathRef obscure data type, you will find that each of those routines accepts a CGAffineTransform. If you specify a transformation in that parameter, the computer will apply that transform to each point as it moves into the path.

For the umbrella example, however, a goal was to create a copy of a path with an arbitrary affine transform already applied to it. A placeholder routine was used to represent that operation without any discussion of why it was necessary or how to implement it. The sample code for Chapter 5, "Transformations," includes the transformPaths code sample. This code sample includes a tool, or a class, for applying transformations to a path called, simply enough, the PathTransformer.

The PathTransformer, in turn, is a subclass of a path known as the PathApplier. A PathApplier object is simply a wrapper around the CGPathApply routine. In the next chapter the way an application can construct a path is discussed. The important thing to know about CGPathApply is that this routine allows you to visit each of the parts in the path and examine them. The PathApplier simply takes each of those pieces and passes them to a virtual method. Because the methods are virtual, you can change the behavior of the applier simply by overriding the virtual methods. This is precisely what the PathTransformer object does.

The PathTransformer keeps track of a transformation and the path that it is constructing. The virtual methods of the PathTransformer object use the transformation and the geometry information provided by the CGPathApply routine, to construct a new, transformed path.




Quartz 2D Graphics for Mac OS X Developers
Quartz 2D Graphics for Mac OS X Developers
ISBN: 0321336631
EAN: 2147483647
Year: 2006
Pages: 100

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net