图形变幻矩阵 Transforms
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.
Function |
Use |
---|---|
|
To construct a new translation matrix from x and y values that specify how much to move the origin. |
|
To apply a translation operation to an existing affine transform. |
|
To construct a new rotation matrix from a value that specifies in radians how much to rotate the coordinate system. |
|
To apply a rotation operation to an existing affine transform. |
|
To construct a new scaling matrix from x and y values that specify how much to stretch or shrink coordinates. |
|
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
.
Points. The functions
CGContextConvertPointToDeviceSpace
andCGContextConvertPointToUserSpace
transform aCGPoint
data type from one space to the other.Sizes. The functions
CGContextConvertSizeToDeviceSpace
andCGContextConvertSizeToUserSpace
transform aCGSize
data type from one space to the other.Rectangles. The functions
CGContextConvertRectToDeviceSpace
andCGContextConvertRectToUserSpace
transform aCGRect
data type from one space to the other.
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的更多相关文章
- Unity手游之路<四>3d旋转-四元数,欧拉角和变幻矩阵
http://blog.csdn.net/janeky/article/details/17272625 今天我们来谈谈关于Unity中的旋转.主要有三种方式.变换矩阵,四元数和欧拉角. 定义 变换矩 ...
- iOS开发之Quarz2D:九:图形上下文矩阵操作
#import "VCView.h" @implementation VCView - (void)drawRect:(CGRect)rect { // Drawing code ...
- hdu1542矩阵的并 线段树+扫描线
求矩阵的并,也就是要求所有的面积.那可以吧总的图形按照矩阵来切割.使其为一块一块. 输入的时候用坐标表示,这里扫描线从下到上扫描.初始时让下面的边为1,上面的为-1: 用一条先从下面开始想上扫描.遇到 ...
- canvas新属性
lineCap默认值是butt,还有aquare,round 使用:context.lineCap="butt" lineJoin miter是默认 还可以是round,bevel ...
- unity--------------------四元数的旋转与原理
[Unity技巧]四元数(Quaternion)和旋转 原文:http://blog.csdn.net/candycat1992/article/details/41254799 四元数介绍 旋转,应 ...
- 【转载】3D/2D中的D3DXMatrixPerspectiveFovLH和D3DXMatrixOrthoLH投影函数详解
原文:3D/2D中的D3DXMatrixPerspectiveFovLH和D3DXMatrixOrthoLH投影函数详解 3D中z值会影响屏幕坐标系到世界坐标系之间的转换,2D中Z值不会产生影响(而只 ...
- MATLAB命令大全
一.常用对象操作:除了一般windows窗口的常用功能键外.1.!dir 可以查看当前工作目录的文件. !dir& 可以在dos状态下查看.2.who 可以查看当前工作空间变量名, whos ...
- (转)如何学好C语言,一个成功人士的心得!
zidier111发表于 2013-1-26 08:59:05 今 天,我能够自称是一个混IT的人,并能以此谋生,将来大家能一次谋生,都要感谢两个人:克劳德.香农和约翰.冯.诺依曼,是他们发现了所 ...
- [转] MATLAB快捷键
原文地址:MATLAB快捷键大全 (转载)作者:掷地有声 一.索引混排版 备注:删除了如F1(帮助)等类型的常见快捷命令 SHIFT+DELETE永久删除 DELETE删除 ALT+ENTER属性 A ...
随机推荐
- count(*),count(1)和count(主键) 区别
看如下数据: SQL> select count(*) from ysgl_compile_reqsub; COUNT(*) ---------- 已用时间: : : 07.51 SQL) fr ...
- Java SE Java EE Java ME 的区别
Java SE(Java Platform,Standard Edition) Java SE 以前称为 J2SE.它允许开发和部署在桌面.服务器.嵌入式环境和实时环境中使用的 Java 应用程序.J ...
- Maven3(笔记一)
第一节:Maven 简介 百度百科:Maven 官网:http://maven.apache.org/ 第二节:Maven 安装与配置 Maven 下载:http://maven.apache.org ...
- 各大浏览器内核(Rendering Engine)
记得刚开始写网页的时候,听童鞋们说各大浏览器的内核,也是懵懵懂懂的,知一不知其二,今天特地查一下: 内核只是一个通俗的说法,其英文名称为“Layout engine”,翻译过来就是“排版引擎”,也被称 ...
- js 高级函数 之示例
js 高级函数作用域安全构造函数 function Person(name, age) { this.name = name; this.age = age; ...
- CSS一级导航-天蓝色(带阴影)
一款亮丽的导航,能给网站一个画龙点睛的作用.导航在指引用户搜寻内容时,还能改变用户浏览网站的心情,浏览网站也像一场旅行,有创意的导航栏让用户欣赏起来也会更加愉悦,增加对网站的兴趣. 本人不擅长美工制作 ...
- javascript图片预先加载
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- WPF Navigation导航
WPF导航这个话题,网上的解决方法有很多种,有点吃猪脚的感觉,弃之可惜,食之乏味. 不过还是简单聊聊吧. 常见的导航: 利用HyperLink导航,可以到某一个Page页面,也可以是外部链接,当然也可 ...
- 在Docker下部署Nginx
在Docker下部署Nginx 在Docker下部署Nginx,包括: 部署一个最简单的Nginx,可以通过80端口访问默认的网站 设置记录访问和错误日志的路径 设置静态网站的路径 通过proxy_p ...
- DBA - 我的学习
DBA - 我的学习 1. df -k 检查oracle 分区硬盘使用情况 2. 检查alert_<SID名称>.log, alert日志文件,检查是否新增错误日志 3. 检查数据文件的状 ...