Quartz 2D编程指南(5) - 变换(Transforms)
Quartz 2D 绘制模型定义了两种独立的坐标空间:用户空间(用于表现文档页)和设备空间(用于表现设备的本地分辨率)。用户坐标空间用浮点数表示坐标,与设备空间的像素分辨率没有关系。当我们需要一个点或者显示文档时, Quartz会将用户空间坐标系统映射到设备空间坐标系统。因此,我们不需要重写应用程序或添加额外的代码来调整应用程序的输出以适应不同的设备。
我们可以通过操作CTM(current transformation matrix)来修改默认的用户空间。在创建图形上下文后,CTM是单位矩阵,我们可以使用 Quartz的变换函数来修改CTM,从而修改用户空间中的绘制操作。
本章内容包括:
- 变换操作函数概览
- 如何修改CTM
- 如何创建一个仿射变换
- 如何选择两个相同的变换
- 如何获取user-to-device-space变换
Quartz变换函数
我们可能使用Quartz内置的变换函数方便的平移、旋转和缩放我们的绘图。只需要短短几行代码,我们便可以按顺序应用变换或结合使用变换。图5-1显示了缩放和旋转一幅图片的效果。我们使用的每个变换操作都更新了CTM。CTM总是用于表示用户空间和设备空间的当前映射关系。这种映射确保了应用程序的输出在任何显示器或打印机上看上去都很棒。

Quartz 2D API提供了5个函数,以允许我们获取和修改CTM。我们可以旋转、平移、缩放CTM。我们还可以联结一个仿射变换矩阵。
有时我们可以不想操作用户空间,直到我们决定将变换应用到CTM时,Quartz为此允许我们创建应用于此的仿射矩阵。我们可以使用另外一组函数来创建仿射变换,这些变换可以与CTM联结在一起。
我们可以不需要了解矩阵的数学含义而使用这些函数。
修改CTM
我们在绘制图像前操作CTM来旋转、缩放或平移page,从而变换我们将要绘制的对象。以变换CTM之前,我们需要保存图形状态,以便绘制后能恢复。我们同样能用仿射矩阵来联结CTM。在本节中,我们将介绍与CTM函数相关的四种操作--平移、旋转、缩放和联结。
假设我们提供了一个可用的图形上下文、一个指向可绘制图像的矩形的指针和一个可用的CGImage对象,则下面一行代码绘制了一个图像。该行代码可以绘制如图5-2所示的图片。在阅读了本节余下的部分后,我们将看到如何将变换应用于图像。
CGContextDrawImage (myContext, rect, myImage);

平移变换根据我们指定的x, y轴的值移动坐标系统的原点。我们通过调用CGContextTranslateCTM函数来修改每个点的x, y坐标值。如图5-3显示了一幅图片沿x轴移动了100个单位,沿y轴移动了50个单位。具体代码如下:
CGContextTranslateCTM (myContext, 100, 50);

旋转变换根据指定的角度来移动坐标空间。我们调用CGContextRotateCTM函数来指定旋转角度(以弧度为单位)。图5-4显示了图片以原点(左下角)为中心旋转45度,代码所下所示:
CGContextRotateCTM (myContext, radians(–45.));

由于旋转操作使图片的部分区域置于上下文之外,所以区域外的部分被裁减。我们用弧度来指定旋转角度。如果需要进行旋转操作,下面的代码将会很有用
#include <math.h>
static inline double radians (double degrees) {
return degrees * M_PI/180;
}
缩放操作根据指定的x, y因子来改变坐标空间的大小,从而放大或缩小图像。x, y因子的大小决定了新的坐标空间是否比原始坐标空间大或者小。另外,通过指定x因子为负数,可以倒转x轴,同样可以指定y因子为负数来倒转y轴。通过调用CGContextScaleCTM函数来指定x, y缩放因子。图5-5显示了指定x因子为0.5,y因子为0.75后的缩放效果。代码如下:
CGContextScaleCTM (myContext, .5, .75);

联合变换将两个矩阵相乘来联接现价变换操作。我们可以联接多个矩阵来得到一个包含所有矩阵累积效果矩阵。通过调用CGContextConcatCTM来联接CTM和仿射矩阵。
另外一种得到累积效果的方式是执行两个或多个变换操作而不恢复图形状态。图5-6显示了先平移后旋转一幅图片的效果,代码如下:
CGContextTranslateCTM (myContext, w,h);
CGContextRotateCTM (myContext, radians(-180.));

图5-7显示了平移、缩放和旋转一幅图片,代码如下:
CGContextTranslateCTM (myContext, w/4, 0);
CGContextScaleCTM (myContext, .25, .5);
CGContextRotateCTM (myContext, radians ( 22.));

变换操作的顺序会影响到最终的效果。如果调换顺序,将得到不同的结果。调换上面代码的顺序将得到如图5-8所示的效果,代码如下:
CGContextRotateCTM (myContext, radians ( 22.));
CGContextScaleCTM (myContext, .25, .5);
CGContextTranslateCTM (myContext, w/4, 0);

创建仿射变换
仿射变换操作在矩阵上,而不是在CTM上。我们可以使用这些函数来构造一个之后用于CTM(调用函数CGContextConcatCTM)的矩阵。仿射变换函数使用或者返回一个CGAffineTransform数据对象。我们可以构建简单或复杂的仿射变换。
仿射变换函数能实现与CTM函数相同的操作--平移、旋转、缩放、联合。表5-1列出了仿射变换函数及其用途。注意每种变换都有两个函数。
表5-1 仿射变换函数
|
函数 |
用途 |
|
CGAffineTransformMakeTranslation |
通过指定x, y值来创建一个平移矩阵 |
|
CGAffineTransformTranslate |
在已存在的矩阵中使用平移 |
|
CGAffineTransformMakeRotation |
通过指定角度来创建一个旋转矩阵 |
|
CGAffineTransformRotate |
在已存在的矩阵中使用旋转 |
|
CGAffineTransformMakeScale |
通过指定x, y缩放因子来创建一个缩放矩阵 |
|
CGAffineTransformScale |
在已存在的矩阵中使用缩放 |
Quartz同样提供了一个仿射变换函数(CGAffineTransformInvert)来倒置矩阵。倒置操作通常用于在变换对象中提供点的倒置变换。当我们需要恢复一个被矩阵变换的值时,可以使用倒置操作。将值与倒置矩阵相乘,就可得到原先的值。我们通常不需要倒置操作,因为我们可以通过保存和恢复图形状态来倒置CTM的效果。
在一些情况下,我们可能不需要变换整修空间,而只是一个点或一个大小。我们通过调用CGPointApplyAffineTransform在CGPoint结构上执行变换操作。调用CGSizeApplyAffineTransform在CGSize结构上执行变换操作。调用CGRectApplyAffineTransform在CGRect结构上执行变换操作。CGRectApplyAffineTransform返回一个最小的矩形,该矩形包含了被传递给CGRectApplyAffineTransform的矩形对象的角点。如果矩形上的仿射变换操作只有缩放和平移操作,则返回的矩形与四个变换后的角组成的矩形是一致的。
可以通过调用函数CGAffineTransformMake来创建一个新的仿射变换,但与其它函数不同的是,它需要提供一个矩阵实体。
评价仿射变换
我们可以通过调用CGAffineTransformEqualToTransform函数来决定一个仿射变换是否与另一个相同。如果两个变换相同,则返回true;否则返回false。
函数CGAffineTransformIsIdentity用于确认一个变换是否是单位变换。单位变换没有平移、缩放和旋转操作。Quartz常量CGAffineTransformIdentity表示一个单位变换。
获取用户空间到设备空间的变换
当使用Quartz 2D时,我们只是在用户空间下工作。Quartz为我们处理用户空间和设备空间的转换。如果我们的应用程序需要获取Quartz转换用户空间和设备空间的仿射变换,我们可以调用函数CGContextGetUserSpaceToDeviceSpaceTransform。
Quartz提供了一系列的函数来转换用户空间和设备空间的几何体。我们会发现这些函数使用起来比使用CGContextGetUserSpaceToDeviceSpaceTransform函数返回的仿射变换更好用。
- 点:函数CGContextConvertPointToDeviceSpace和CGContextConvertPointToUserSpace将一个CGPoint数据结构从一个空间变换到另一个空间。
- 大小:函数CGContextConvertSizeToDeviceSpace和CGContextConvertSizeToUserSpace将一个CGSize数据结构从一个空间变换到另一个空间。
- 矩形:函数CGContextConvertRectToDeviceSpace和CGContextConvertRectToUserSpace将一个CGPoint数据结构从一个空间变换到另一个空间。
Quartz 2D编程指南(5) - 变换(Transforms)的更多相关文章
- Quartz 2D编程指南(1) - 概览
Quartz 2D编程指南是论坛会员德鲁伊翻译的国外的Quartz 2D一系列学习资料,供大家参考 Quartz 2D是一个二维图形绘制引擎,支持iOS环境和Mac OS X环境.我们可以使用Quar ...
- Quartz 2D编程指南(7) - 阴影(Shadows)
阴影是绘制在一个图形对象下的且有一定偏移的图片,它用于模拟光源照射到图形对象上所形成的阴影效果,如果7-1所示.文本也可以有阴影.阴影可以让一幅图像看上去是立体的或者是浮动的. 阴影有三个属性: 1. ...
- Quartz 2D编程指南(4) - 颜色和颜色空间
不同的设备(显示器.打印机.扫描仪.摄像头)处理颜色的方式是不同的.每种设备都有其所能支持的颜色值范围.一种设备能支持的颜色可能在其它设备中无法支持.为了有效的使用颜色及理解Quartz 2D中用于颜 ...
- Quartz 2D编程指南(2) - 图形上下文
一个Graphics Context表示一个绘制目标.它包含绘制系统用于完成绘制指令的绘制参数和设备相关信息.Graphics Context定义了基本的绘制属性,如颜色.裁减区域.线条宽度和样式信息 ...
- Quartz 2D编程指南(2)图形上下文(Graphics Contexts)
Graphics Contexts 一个Graphics Context表示一个绘制目标(也能够理解为图形上下文).它包括绘制系统用于完毕绘制指令的绘制參数和设备相关信息.Graphics ...
- Quartz 2D编程指南- PDF文档的创建、显示及转换
PDF文档存储依赖于分辨率的向量图形.文本和位图,并用于程序的一系列指令中.一个PDF文档可以包含多页的图形和文本.PDF可用于创建跨平台.只读的文档,也可用于绘制依赖于分辨率的图形. ...
- Quartz 2D Programming Guide
Quartz 2D Programming Guide 官方文档: Quartz 2D Programming Guide 译文: Quartz 2D编程指南(1) - 概览 Quartz 2D编程 ...
- View Programming Guide for iOS ---- iOS 视图编程指南(四)---Views
Views Because view objects are the main way your application interacts with the user, they have many ...
- iPhone之Quartz 2D系列--编程指南(1)概览
以下几遍关于Quartz 2D博文都是转载自:http://www.cocoachina.com/bbs/u.php?action=topic&uid=38018 iPhone之Quartz ...
随机推荐
- HttpServletResponse response详解
//内容类型和编码格式可以被调用多次,最后一次将覆盖之前的设置 //内容类型和编码格式必须在 //设置内容类型getWriter和getOutputStream方法之前调用,否则不起作用 //若未设置 ...
- JavaScript声明全局变量三种方式的异同
JavaScript中声明变量很简单var(关键字)+变量名(标识符). 方式1 1 2 var test; var test = 5; 需注意的是该句不能包含在function内,否则是局部变量.这 ...
- ZOJ 2599 Graduated Lexicographical Ordering ★(数位DP)
题意 定义两个数的比较方法,各位数字之和大的数大,如果数字和相等则按字典序比较两个数的大小.输入n,k,求:1.数字k的排名:2.排名为k的数. 思路 算是一类经典的统计问题的拓展吧~ 先来看第一问. ...
- OpenStack Mitaka Neutron SR-IOV配置
### 一.在所有节点(控制节点.计算节点) 1.修改BIOS ``` BOIS里面开启SR-IOV功能 开启 VT-d (inter virtualization technology)和 SR-I ...
- 添加resx文件过程笔记
为了测试资源文件,今天上午耗掉了.终于实现了,原来是要按照它自动建文件夹,不可以手动建.下图 见其他语言的时候一定要:Mytest.zh-CN.resx 这样,加上后缀名字 代码中获取资源 http: ...
- java程序设计基础篇 复习笔记 第四单元
1 think before coding code incrementally 2 sentinel value sentinel-controlled loop 3 输入输出重定向 > &l ...
- CF 914
照例看A 然后A了 看B 似乎博弈一下就可以了 然后看C 似乎是DP 然后看了room woc似乎有黑红名 赶紧hack 然后没有人有问题 思考为什么 突然看到房间有15hack... 好吧我做D 然 ...
- 自研发RPC调用框架
自主研发设计RPC远程调用框架,实现服务自动注册,服务发现,远程RPC调用,后续实现服务负载均衡 主要包括:客户端服务,服务端,服务发现,服务注册 github地址:https://github.co ...
- AndroidStudio构建常见错误解答解决思路
一.Error:Configuration with name 'default' not found.解决思路 出现这问题的原因是你依赖的工程没有make project,意思是你导入项目的工程没有 ...
- C++面向对象高级编程(三)基础篇
技术在于交流.沟通,转载请注明出处并保持作品的完整性. 概要 一.拷贝构造 二.拷贝赋值 三.重写操作符 四.生命周期 本节主要介绍 Big Three 即析构函数,拷贝构造函数,赋值拷贝函数,前面主 ...