https://developer.apple.com/library/mac/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_affine/dq_affine.html#//apple_ref/doc/uid/TP30001066-CH204-CJBECIAD

The Quartz 2D drawing model defines two completely separate coordinate spaces: user space, which represents the document page, and device space, which represents the native resolution of a device. User space coordinates are floating-point numbers that are unrelated to the resolution of pixels in device space. When you want to print or display your document, Quartz maps user space coordinates to device space coordinates. Therefore, you never have to rewrite your application or write additional code to adjust the output from your application for optimum display on different devices.

You can modify the default user space by operating on the current transformation matrix, or CTM. After you create a graphics context, the CTM is the identity matrix. You can use Quartz transformation functions to modify the CTM and, as a result, modify drawing in user space.

This chapter:

  • Provides an overview of the functions you can use to perform transformations

  • Shows how to modify the CTM

  • Describes how to create an affine transform

  • Shows how to determine if two transforms are equivalent

  • Describes how to obtain the user-to-device-space transform

  • Discusses the math behind affine transforms

About Quartz Transformation Functions

You can easily translate, scale, and rotate your drawing using the Quartz 2D built-in transformation functions. With just a few lines of code, you can apply these transformations in any order and in any combination. Figure 5-1 illustrates the effects of scaling and rotating an image. Each transformation you apply updates the CTM. The CTM always represents the current mapping between user space and device space. This mapping ensures that the output from your application looks great on any display screen or printer.

Figure 5-1  Applying scaling and rotation

The Quartz 2D API provides five functions that allow you to obtain and modify the CTM. You can rotate, translate, and scale the CTM, and you can concatenate an affine transformation matrix with the CTM. See Modifying the Current Transformation Matrix.

Quartz also allows you to create affine transforms that don’t operate on user space until you decide to apply the transform to the CTM. You use another set of functions to create affine transforms, which can then be concatenated with the CTM. See Creating Affine Transforms.

You can use either set of functions without understanding anything about matrix math. However if you want to understand what Quartz does when you call one of the transform functions, read The Math Behind the Matrices.

Modifying the Current Transformation Matrix

You manipulate the CTM to rotate, scale, or translate the page before drawing an image, thereby transforming the object you are about to draw. Before you transform the CTM, you need to save the graphics state so that you can restore it after drawing. You can also concatenate the CTM with an affine transform (see Creating Affine Transforms). Each of these four operations—translation, rotation, scaling, and concatenation—is described in this section along with the CTM functions that perform each operation.

The following line of code draws an image, assuming that you provide a valid graphics context, a pointer to the rectangle to draw the image to, and a valid CGImage object. The code draws an image, such as the sample rooster image shown in Figure 5-2. As you read the rest of this section, you’ll see how the image changes as you apply transformations.

CGContextDrawImage (myContext, rect, myImage);

Figure 5-2  An image that is not transformed

Translation moves the origin of the coordinate space by the amount you specify for the x and y axes. You call the function CGContextTranslateCTM to modify the x and y coordinates of each point by a specified amount. Figure 5-3 shows an image translated by 100 units in the x-axis and 50 units in the y-axis, using the following line of code:

CGContextTranslateCTM (myContext, 100, 50);

Figure 5-3  A translated image

Rotation moves the coordinate space by the angle you specify. You call the function CGContextRotateCTM to specify the rotation angle, in radians. Figure 5-4 shows an image rotated by –45 degrees about the origin, which is the lower left of the window, using the following line of code:

CGContextRotateCTM (myContext, radians(–45.));

The image is clipped because the rotation moved part of the image to a location outside the context. You need to specify the rotation angle in radians.

It’s useful to write a radians routine if you plan to perform many rotations.

#include <math.h>
static inline double radians (double degrees) {return degrees * M_PI/180;}

Figure 5-4  A rotated image

Scaling changes the scale of the coordinate space by the x and y factors you specify, effectively stretching or shrinking the image. The magnitude of the x and y factors governs whether the new coordinates are larger or smaller than the original. In addition, by making the x factor negative, you can flip the coordinates along the x-axis; similarly, you can flip coordinates horizontally, along the y-axis, by making the y factor negative. You call the function CGContextScaleCTM to specify the x and y scaling factors. Figure 5-5 shows an image whose x values are scaled by .5 and whose y values are scaled by .75, using the following line of code:

CGContextScaleCTM (myContext, .5, .75);

Figure 5-5  A scaled image

Concatenation combines two matrices by multiplying them together. You can concatenate several matrices to form a single matrix that contains the cumulative effects of the matrices. You call the function CGContextConcatCTM to combine the CTM with an affine transform. Affine transforms, and the functions that create them, are discussed in Creating Affine Transforms.

Another way to achieve a cumulative effect is to perform two or more transformations without restoring the graphics state between transformation calls. Figure 5-6 shows an image that results from translating an image and then rotating it, using the following lines of code:

CGContextTranslateCTM (myContext, w,h);
CGContextRotateCTM (myContext, radians(-180.));

Figure 5-6  An image that is translated and rotated

Figure 5-7 shows an image that is translated, scaled, and rotated, using the following lines of code:

CGContextTranslateCTM (myContext, w/4, 0);
CGContextScaleCTM (myContext, .25,  .5);
CGContextRotateCTM (myContext, radians ( 22.));

Figure 5-7  An image that is translated, scaled, and then rotated

The order in which you perform multiple transformations matters; you get different results if you reverse the order. Reverse the order of transformations used to create Figure 5-7 and you get the results shown in Figure 5-8, which is produced with this code:

CGContextRotateCTM (myContext, radians ( 22.));
CGContextScaleCTM (myContext, .25,  .5);
CGContextTranslateCTM (myContext, w/4, 0);

Figure 5-8  An image that is rotated, scaled, and then translated

Creating Affine Transforms

The affine transform functions available in Quartz operate on matrices, not on the CTM. You can use these functions to construct a matrix that you later apply to the CTM by calling the function CGContextConcatCTM. The affine transform functions either operate on, or return, a CGAffineTransform data structure. You can construct simple or complex affine transforms that are reusable.

The affine transform functions perform the same operations as the CTM functions—translation, rotation, scaling, and concatenation. Table 5-1 lists the functions that perform these operations along with information on their use. Note that there are two functions for each of the translation, rotation, and scaling operations.

Table 5-1  Affine transform functions for translation, rotation, and scaling

Function

Use

CGAffineTransformMakeTranslation

To construct a new translation matrix from x and y values that specify how much to move the origin.

CGAffineTransformTranslate

To apply a translation operation to an existing affine transform.

CGAffineTransformMakeRotation

To construct a new rotation matrix from a value that specifies in radians how much to rotate the coordinate system.

CGAffineTransformRotate

To apply a rotation operation to an existing affine transform.

CGAffineTransformMakeScale

To construct a new scaling matrix from x and y values that specify how much to stretch or shrink coordinates.

CGAffineTransformScale

To apply a scaling operation to an existing affine transform.

Quartz also provides an affine transform function that inverts a matrix, CGAffineTransformInvert. Inversion is generally used to provide reverse transformation of points within transformed objects. Inversion can be useful when you need to recover a value that has been transformed by a matrix: Invert the matrix, and multiply the value by the inverted matrix, and the result is the original value. You usually don’t need to invert transforms because you can reverse the effects of transforming the CTM by saving and restoring the graphics state.

In some situations you might not want to transform the entire space, but just a point or a size. You operate on a CGPoint structure by calling the function CGPointApplyAffineTransform. You operate on a CGSize structure by calling the function CGSizeApplyAffineTransform. You can operate on a CGRect structure by calling the function CGRectApplyAffineTransform. This function returns the smallest rectangle that contains the transformed corner points of the rectangle passed to it. If the affine transform that operates on the rectangle performs only scaling and translation operations, the returned rectangle coincides with the rectangle constructed from the four transformed corners.

You can create a new affine transform by calling the function CGAffineTransformMake, but unlike the other functions that make new affine transforms, this one requires you to supply matrix entries. To effectively use this function, you need to have an understanding of matrix math. See The Math Behind the Matrices.

Evaluating Affine Transforms

You can determine whether one affine transform is equal to another by calling the function CGAffineTransformEqualToTransform. This function returns true if the two transforms passed to it are equal and false otherwise.

The function CGAffineTransformIsIdentity is a useful function for checking whether a transform is the identity transform. The identity transform performs no translation, scaling, or rotation. Applying this transform to the input coordinates always returns the input coordinates. The Quartz constant CGAffineTransformIdentity represents the identity transform.

Getting the User to Device Space Transform

Typically when you draw with Quartz 2D, you work only in user space. Quartz takes care of transforming between user and device space for you. If your application needs to obtain the affine transform that Quartz uses to convert between user and device space, you can call the function CGContextGetUserSpaceToDeviceSpaceTransform.

Quartz provides a number of convenience functions to transform the following geometries between user space and device space. You might find these functions easier to use than applying the affine transform returned from the function CGContextGetUserSpaceToDeviceSpaceTransform.

The Math Behind the Matrices

The only Quartz 2D function for which you need an understanding of matrix math is the function CGAffineTransformMake, which makes an affine transform from the six critical entries in a 3 x 3 matrix. Even if you never plan to construct an affine transformation matrix from scratch, you might find the math behind the transform functions interesting. If not, you can skip the rest of this chapter.

The six critical values of a 3 x 3 transformation matrix —a, b, c, d, tx and ty— are shown in the following matrix:

Note: The rightmost column of the matrix always contains the constant values 0, 0, 1. Mathematically, this third column is required to allow concatenation, which is explained later in this section. It appears in this section for the sake of mathematical correctness only.

Given the 3 x 3 transformation matrix described above, Quartz uses this equation to transform a point (x, y) into a resultant point (x’, y’):

The result is in a different coordinate system, the one transformed by the variable values in the transformation matrix. The following equations are the definition of the previous matrix transform:

The following matrix is the identity matrix. It performs no translation, scaling, or rotation. Multiplying this matrix by the input coordinates always returns the input coordinates.

Using the formulas discussed earlier, you can see that this matrix would generate a new point (x’, y’) that is the same as the old point (x, y):

This matrix describes a translation operation:

These are the resulting equations that Quartz uses to apply the translation:

This matrix describes a scaling operation on a point (x, y):

These are the resulting equations that Quartz uses to scale the coordinates:

This matrix describes a rotation operation, rotating the point (x, y) counterclockwise by an angle a:

These are the resulting equations that Quartz uses to apply the rotation:

This equation concatenates a rotation operation with a translation operation:

These are the resulting equations that Quartz uses to apply the transform:

Note that the order in which you concatenate matrices is important—matrix multiplication is not commutative. That is, the result of multiplying matrix A by matrix B does not necessarily equal the result of multiplying matrix B by matrix A.

As previously mentioned, concatenation is the reason the affine transformation matrix contains a third column with the constant values 0, 0, 1. To multiply one matrix against another matrix, the number of columns of one matrix must match the number of rows of the other. This means that a 2 x 3 matrix cannot be multiplied against a 2 x 3 matrix. Thus we need the extra column containing the constant values.

An inversion operation produces original coordinates from transformed ones. Given the coordinates (x, y), which have been transformed by a given matrix A to new coordinates (x’, y’), transforming the coordinates (x’, y’) by the inverse of matrix A produces the original coordinates (x, y). When a matrix is multiplied by its inverse, the result is the identity matrix.

图形变幻矩阵 Transforms的更多相关文章

  1. Unity手游之路<四>3d旋转-四元数,欧拉角和变幻矩阵

    http://blog.csdn.net/janeky/article/details/17272625 今天我们来谈谈关于Unity中的旋转.主要有三种方式.变换矩阵,四元数和欧拉角. 定义 变换矩 ...

  2. iOS开发之Quarz2D:九:图形上下文矩阵操作

    #import "VCView.h" @implementation VCView - (void)drawRect:(CGRect)rect { // Drawing code ...

  3. hdu1542矩阵的并 线段树+扫描线

    求矩阵的并,也就是要求所有的面积.那可以吧总的图形按照矩阵来切割.使其为一块一块. 输入的时候用坐标表示,这里扫描线从下到上扫描.初始时让下面的边为1,上面的为-1: 用一条先从下面开始想上扫描.遇到 ...

  4. canvas新属性

    lineCap默认值是butt,还有aquare,round 使用:context.lineCap="butt" lineJoin miter是默认 还可以是round,bevel ...

  5. unity--------------------四元数的旋转与原理

    [Unity技巧]四元数(Quaternion)和旋转 原文:http://blog.csdn.net/candycat1992/article/details/41254799 四元数介绍 旋转,应 ...

  6. 【转载】3D/2D中的D3DXMatrixPerspectiveFovLH和D3DXMatrixOrthoLH投影函数详解

    原文:3D/2D中的D3DXMatrixPerspectiveFovLH和D3DXMatrixOrthoLH投影函数详解 3D中z值会影响屏幕坐标系到世界坐标系之间的转换,2D中Z值不会产生影响(而只 ...

  7. MATLAB命令大全

    一.常用对象操作:除了一般windows窗口的常用功能键外.1.!dir 可以查看当前工作目录的文件. !dir& 可以在dos状态下查看.2.who 可以查看当前工作空间变量名, whos ...

  8. (转)如何学好C语言,一个成功人士的心得!

    zidier111发表于 2013-1-26 08:59:05   今 天,我能够自称是一个混IT的人,并能以此谋生,将来大家能一次谋生,都要感谢两个人:克劳德.香农和约翰.冯.诺依曼,是他们发现了所 ...

  9. [转] MATLAB快捷键

    原文地址:MATLAB快捷键大全 (转载)作者:掷地有声 一.索引混排版 备注:删除了如F1(帮助)等类型的常见快捷命令 SHIFT+DELETE永久删除 DELETE删除 ALT+ENTER属性 A ...

随机推荐

  1. jsp中<c:if>与<s:if>的区别

    <c:if>时jstl标签,一般与el表达式一起使用,参考http://www.360doc.com/content/11/1121/16/7874148_166229306.shtml ...

  2. 通过html5的range属性动态改变图片的大小

    range属性已经是很成熟的属性了,我们可以使用这个属性进行动态调整图片的宽度,其中原理在于通过不断获取range的值,并赋予给所需要的图片,进而达到动态改变图片的效果.下面贴出具体的代码,主要参照了 ...

  3. 左偏树(Leftist Heap/Tree)简介及代码

    左偏树是一种常用的优先队列(堆)结构.与二叉堆相比,左偏树可以高效的实现两个堆的合并操作. 左偏树实现方便,编程复杂度低,而且有着不俗的效率表现. 它的一个常见应用就是与并查集结合使用.利用并查集确定 ...

  4. [学习笔记]设计模式之Chain of Responsibility

    为方便读者,本文已添加至索引: 设计模式 学习笔记索引 写在前面 最近时间比较紧,所以发文的速度相对较慢了.但是看到园子里有很多朋友对设计模式感兴趣,我感觉很高兴,能够和大家一起学习这些知识. 之前的 ...

  5. ffmpeg与RTMP流媒体连接用法(翻译) http://www.chinavideo.org/forum.php?mod=viewthread&tid=15423

    最近浏览国外网站时候发现,翻译不准确的敬请谅解. 1.将文件当做直播送至liveffmpeg -re -i localFile.mp4 -c copy -f flv rtmp://server/liv ...

  6. Git (2)

    要使用Git首先遇到的问题是怎么把文件加到库中. 很简单. 新建一个目录,然后git init. 完成上述工作之后的唯一改动是在当前目录下生成了一个.git的子目录.这个子目录是一个集中的数据库,包含 ...

  7. Java学习----不该初始化的class(抽象类)

    1. 抽象类声明有abstract 2.抽象类中有抽象方法,没有方法体的方法 // 抽象类 public abstract class Animal { public String name; pub ...

  8. 细介Nigix配置与反向代理

    Nginx(发 音同 engine x)是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下 发行.由俄罗斯的程序设计师Igor S ...

  9. Cloudera Impala 之 ORDER BY without LIMIT currently not supported

    ERROR: NotImplementedException: ORDER BY without LIMIT currently not supported   impala中order by 需要l ...

  10. 指令发email

    win7下指令发送email:(telnet:不为内部指令时控制面板 -> 程序和功能 -> 打开或关闭Windows功能,如下“telnet客户端”) telnet smtp.sina. ...