CoreGraphics QuartzCore CGContextTranslateCTM 用法
2015-09-15 16:13
405 查看
原点是: 左下角
旋转: 逆时针
位移: 右上为正, 左下为负
CGContextTranslateCTM
CGContextRotateCTM
CGContextScaleCTM
而且, 以上几个操作都是累积的
CGContext的转换于UIView的转换不一样, 不要混淆
CoreGraphics.h一些常用旋转常量
#define M_E 2.71828182845904523536028747135266250 e
#define M_LOG2E 1.44269504088896340735992468100189214 log 2e
#define M_LOG10E 0.434294481903251827651128918916605082 log 10e
#define M_LN2 0.693147180559945309417232121458176568 log e2
#define M_LN10 2.30258509299404568401799145468436421 log e10
#define M_PI 3.14159265358979323846264338327950288 pi
#define M_PI_2 1.57079632679489661923132169163975144 pi/2
#define M_PI_4 0.785398163397448309615660845819875721 pi/4
#define M_1_PI 0.318309886183790671537767526745028724 1/pi
#define M_2_PI 0.636619772367581343075535053490057448 2/pi
#define M_2_SQRTPI 1.12837916709551257389615890312154517 2/sqrt(pi) #define M_SQRT2 1.41421356237309504880168872420969808 sqrt(2)
#define M_SQRT1_2 0.707106781186547524400844 362104849039 1/sqrt(2)
CGAffineTransformMakeTranslation(width, 0.0);是改变位置的,
CGAffineTransformRotate(transform, M_PI);是旋转的。
CGAffineTransformMakeRotation(-M_PI);也是旋转的
transform = CGAffineTransformScale(transform, -1.0, 1.0);是缩放的。
view.transform = CGAffineTransformIdentity;线性代数里面讲的矩阵变换,这个是恒等变换 当你改变过一个view.transform属性或者view.layer.transform的时候需要恢复默认状态的话,记得先把他们重置可以使用 view.transform = CGAffineTransformIdentity, 或者view.layer.transform = CATransform3DIdentity。
假设你一直不断的改变一个view.transform的属性,而每次改变之前没有重置的话,你会发现后来的改变和你想要的发生变化了,不是你真正想要的结果
Quartz转换实现的原理:Quartz把绘图分成两个部分,
用户空间,即和设备无关,
设备空间,
用户空间和设备空间中间存在一个转换矩阵 : CTM
本章实质是讲解CTM
Quartz提供的3大功能
移动,旋转,缩放
演示如下,首先加载一张图片
void CGContextDrawImage (
CGContextRef c,
CGRect rect,
CGImageRef image
);
移动函数
CGContextTranslateCTM (myContext, 100, 50);
旋转函数
include
static inline double radians (double degrees) {return degrees * M_PI/180;}
CGContextRotateCTM (myContext, radians(–45.));
缩放
CGContextScaleCTM (myContext, .5, .75);
翻转, 两种转换合成后的效果,先把图片移动到右上角,然后旋转180度
CGContextTranslateCTM (myContext, w,h);
CGContextRotateCTM (myContext, radians(-180.));
Quartz 2D编程指南(5)
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 static inline double radians (double degrees) {return degrees * M_PI/180;} |
复制代码 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 仿射变换函数
函数 | 用途 |
CGAffineTransformMakeTra nslation | 通过指定x, y值来创建一个平移矩阵 |
CGAffineTransformTransla te | 在已存在的矩阵中使用平移 |
CGAffineTransformMakeRot ation | 通过指定角度来创建一个旋转矩阵 |
CGAffineTransformRotate | 在已存在的矩阵中使用旋转 |
CGAffineTransformMakeSca le | 通过指定x, y缩放因子来创建一个缩放矩阵 |
CGAffineTransformScale | 在已存在的矩阵中使用缩放 |
在一些情况下,我们可能不需要变换整修空间,而只是一个点或一个大小。我们通过调用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数据结构从一个空间变换到另一个空间。
CALayer简单教程
首先要说的是CALayers 是屏幕上的一个具有可见内容的矩形区域,每个UIView都有一个根CALayer,其所有的绘制(视觉效果)都是在这个layer上进行的。(译者注:为验证这点,我写下了如下代码:
1 2 3 4 5 6 7 8 9 10 | UILabel * lable = [ [ UILabel alloc ] initWithFrame : CGRectMake ( 0, 0, 100, 30 ) ] ; lable.text = @ "test" ; [ self.view addSubview : lable ] ; lable.backgroundColor = [ UIColor clearColor ] ; [ lable release ] ; // 设定CALayer self.view.layer.backgroundColor = [ UIColor orangeColor ] .CGColor; self.view.layer.cornerRadius = 20.0 ; self.view.layer.frame = CGRectInset ( self.view.layer.frame, 20, 20 ) ; |
其次,CALayer的可以影响其外观的特性有:
层的大小尺寸
背景色
内容(比如图像或是使用 Core Graphics 绘制的内容)
是否使用圆角
是否使用阴影
等等
需要说明的是CALayer的大部分属性都可以用来实现动画效果。
另外,你可以直接使用CALayer,也可以使用其子类,如CAGradientLayer,CATextLayer, CAShapeLayer等等。
示例
首先在Xcode中创建一个View-based App,CALayer是属于QuartzCore framework的,所以需要引入QuartzCore framework,另外在程序中包括QuartzCore.h 。第一个例子是创建一个带圆角的层,在你的ViewController中的ViewDidLoad中加入下面代码:
1 2 3 4 5 6 7 | // Import QuartzCore.h at the top of the file #import // Uncomment viewDidLoad and add the following lines self.view.layer.backgroundColor = [ UIColor orangeColor ] .CGColor; self.view.layer.cornerRadius = 20.0 ; self.view.layer.frame = CGRectInset ( self.view.layer.frame, 20, 20 ) ; |
1 2 3 4 5 6 7 8 | CALayer * sublayer = [ CALayer layer ] ; sublayer.backgroundColor = [ UIColor blueColor ] .CGColor; sublayer.shadowOffset = CGSizeMake ( 0, 3 ) ; sublayer.shadowRadius = 5.0 ; sublayer.shadowColor = [ UIColor blackColor ] .CGColor; sublayer.shadowOpacity = 0.8 ; sublayer.frame = CGRectMake ( 30, 30, 128, 192 ) ; [ self.view.layer addSublayer : sublayer ] ; |
1 2 3 | sublayer.contents = ( id ) [ UIImage imageNamed : @"BattleMapSplashScreen.png" ] .CGImage; sublayer.borderColor = [ UIColor blackColor ] .CGColor; sublayer.borderWidth = 2.0 ; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | CALayer * sublayer = [ CALayer layer ] ; sublayer.backgroundColor = [ UIColor blueColor ] .CGColor; sublayer.shadowOffset = CGSizeMake ( 0, 3 ) ; sublayer.shadowRadius = 5.0 ; sublayer.shadowColor = [ UIColor blackColor ] .CGColor; sublayer.shadowOpacity = 0.8 ; sublayer.frame = CGRectMake ( 30, 30, 128, 192 ) ; sublayer.borderColor = [ UIColor blackColor ] .CGColor; sublayer.borderWidth = 2.0 ; sublayer.cornerRadius = 10.0 ; [ self.view.layer addSublayer : sublayer ] ; CALayer * imageLayer = [ CALayer layer ] ; imageLayer.frame = sublayer.bounds; imageLayer.cornerRadius = 10.0 ; imageLayer.contents = ( id ) [ UIImage imageNamed : @"BattleMapSplashScreen.png" ] .CGImage; imageLayer.masksToBounds = YES ; [ sublayer addSublayer : imageLayer ] ; |
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | void MyDrawColoredPattern ( void * info, CGContextRef context ) { CGColorRef dotColor = [ UIColor colorWithHue : 0 saturation : 0 brightness :0.07 alpha : 1.0 ] .CGColor; CGColorRef shadowColor = [ UIColor colorWithRed : 1 green : 1 blue : 1 alpha :0.1 ] .CGColor; CGContextSetFillColorWit hColor ( context, dotColor ) ; CGContextSetShadowWithCo lor ( context, CGSizeMake ( 0, 1 ) , 1, shadowColor ) ; CGContextAddArc ( context, 3, 3, 4, 0, radians ( 360 ) , 0 ) ; CGContextFillPath ( context ) ; CGContextAddArc ( context, 16, 16, 4, 0, radians ( 360 ) , 0 ) ; CGContextFillPath ( context ) ; } - ( void ) drawLayer : ( CALayer * ) layer inContext : ( CGContextRef ) context { CGColorRef bgColor = [ UIColor colorWithHue : 0.6 saturation : 1.0 brightness :1.0 alpha : 1.0 ] .CGColor; CGContextSetFillColorWit hColor ( context, bgColor ) ; CGContextFillRect ( context, layer.bounds ) ; staticconst CGPatternCallbacks callbacks = { 0, & MyDrawColoredPattern, NULL } ; CGContextSaveGState ( context ) ; CGColorSpaceRef patternSpace = CGColorSpaceCreatePatter n ( NULL ) ; CGContextSetFillColorSpa ce ( context, patternSpace ) ; CGColorSpaceRelease ( patternSpace ) ; CGPatternRef pattern = CGPatternCreate ( NULL , layer.bounds, CGAffineTransformIdentit y, 24, 24, kCGPatternTilingConstant Spacing, true , & callbacks ) ; CGFloat alpha = 1.0 ; CGContextSetFillPattern ( context, pattern, & alpha ) ; CGPatternRelease ( pattern ) ; CGContextFillRect ( context, layer.bounds ) ; CGContextRestoreGState ( context ) ; } |
1 | static inline double radians ( double degrees ) { return degrees * M_PI /180 ; } |
相关文章推荐
- HUD 5256 序列变换
- XMLHttpRequest cannot load"url"Cross origin requests are only supported. send @ jquery-2.1.4.js:8630
- linux命令之top
- cocos studio2.x 对象绑定
- 数据库连接字符串简析
- Quartz实现定时任务的配置方法
- ASP.NET MVC 缓存使用示例
- hibernate核心开发接口
- android+ADT+SDK开发环境及变量配置
- hdu5446(2015长春网络赛J题)
- MongoDB常用操作
- 简单工厂
- 黑马程序员学习(五)Final、接口、多态
- NHibernate从入门到精通系列(2)——NHibernate环境与结构体系
- PLC实现重复定时
- 蚁群算法、遗传算法、模拟退火算法介绍
- Friendship (poj 1815 最小点割集+枚举)
- exec家族
- 正则表达式的使用
- PLC实现重复定时