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.707106781186547524400844362104849039 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所看到的的图片。

在阅读了本节余下的部分后,我们将看到怎样将变换应用于图像。

复制代码

  1. CGContextDrawImage (myContext, rect, myImage);

 

平移变换依据我们指定的x, y轴的值移动坐标系统的原点。

我们通过调用CGContextTranslateCTM函数来改动每一个点的x, y坐标值。如图5-3显示了一幅图片沿x轴移动了100个单位,沿y轴移动了50个单位。详细代码例如以下:

复制代码

  1. CGContextTranslateCTM (myContext, 100, 50);

 

旋转变换依据指定的角度来移动坐标空间。

我们调用CGContextRotateCTM函数来指定旋转角度(以弧度为单位)。图5-4显示了图片以原点(左下角)为中心旋转45度。代码所下所看到的:

复制代码

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

 

因为旋转操作使图片的部分区域置于上下文之外。所以区域外的部分被裁减。我们用弧度来指定旋转角度。假设须要进行旋转操作,以下的代码将会非常实用

复制代码

  1. #include
  2. 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后的缩放效果。代码例如以下:

复制代码

  1. CGContextScaleCTM (myContext, .5, .75);

 

联合变换将两个矩阵相乘来联接现价变换操作。

我们能够联接多个矩阵来得到一个包括全部矩阵累积效果矩阵。通过调用CGContextConcatCTM来联接CTM和仿射矩阵。

第二种得到累积效果的方式是运行两个或多个变换操作而不恢复图形状态。

图5-6显示了先平移后旋转一幅图片的效果。代码例如以下:

复制代码

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

 

图5-7显示了平移、缩放和旋转一幅图片。代码例如以下:

复制代码

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

 

变换操作的顺序会影响到终于的效果。

假设调换顺序,将得到不同的结果。

调换上面代码的顺序将得到如图5-8所看到的的效果,代码例如以下:

复制代码

  1. CGContextRotateCTM (myContext, radians ( 22.));
  2. CGContextScaleCTM (myContext, .25, .5);
  3. 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数据结构从一个空间变换到还有一个空间。
 
 
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);

请注意。我创建的UILable始终随着UIView的根CALayer的缩放而改变位置。)

其次,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;

假设你希望子层也是圆角怎么办?你可能说非常easy设置cornerRadius属性即可。

实际上你即算是设置了cornerRadius属性,图片仍然不会显示圆角。

你还须要设置masksToBounds为YES。可是这样做还是不够的,由于假设是这样,这个层的阴影显示就没有了。

简单的实现方法例如以下(通过两个层来实现):

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];

最后,还介绍一下自画图型的实现,其要点是要设置所绘制层的delegate。比方在我们的样例中使用ViewController作为delegate,那么就须要在ViewController中实现drawLayer:inContext方法,对层进行绘制工作。另外,还须要调用setNeedsDisplay,来通知层须要进行绘制了,于是层才会通过对delegate的drawLayer:inContext方法进行调用。

代码例如以下:

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;



CGContextSetFillColorWithColor(context, dotColor);

CGContextSetShadowWithColor(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;

CGContextSetFillColorWithColor(context, bgColor);

CGContextFillRect(context, layer.bounds);



staticconst CGPatternCallbacks callbacks ={0, &MyDrawColoredPattern, NULL};



CGContextSaveGState(context);

CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL);

CGContextSetFillColorSpace(context, patternSpace);

CGColorSpaceRelease(patternSpace);



CGPatternRef pattern = CGPatternCreate(NULL,

layer.bounds,

CGAffineTransformIdentity,

24,

24,

kCGPatternTilingConstantSpacing,

true,

&callbacks);

CGFloat alpha =1.0;

CGContextSetFillPattern(context, pattern, &alpha);

CGPatternRelease(pattern);

CGContextFillRect(context, layer.bounds);

CGContextRestoreGState(context);

}

还须要注意。radians是一个自己定义函数:

1
static inline double radians (double degrees) { return degrees * M_PI/180; }

版权声明:本文博主原创文章。博客,未经同意不得转载。

CoreGraphics QuartzCore CGContextTranslateCTM 说明的更多相关文章

  1. CoreGraphics QuartzCore CGContextTranslateCTM 用法

      原点是: 左下角 旋转: 逆时针 位移: 右上为正, 左下为负 CGContextTranslateCTM CGContextRotateCTM CGContextScaleCTM 而且, 以上几 ...

  2. 【转】 CoreGraphics QuartzCore CGContextTranslateCTM 用法

    原文:http://blog.csdn.net/sqc3375177/article/details/25708447 CoreGraphics.h 一些常用旋转常量 #define M_E 2.71 ...

  3. OpenGL ES2.0光照

    一.简单光照原理 平行光(正常光) 光照效果=   环境颜色 + 漫反射颜色 + 镜面反射颜色 点光源 光照效果=   环境颜色 + (漫反射颜色 + 镜面反射颜色)× 衰减因子 聚光灯 光照效果= ...

  4. [翻译] BFKit

    BFKit BFKit is a collection of useful classes to develop Apps faster. BFKit是一个有用的工具集合,帮助你快速开发. Insta ...

  5. 作为iOS程序员,最核心的60%能力有哪些?

    作为iOS程序员,最核心的60%能力有哪些?   一个合格的iOS程序员需要掌握多少核心技能?你和专业的开发工程师的差距有多大?你现在的水平能开发一个功能完整性能高效的iOS APP吗?一起来看看下面 ...

  6. CocoaPods进阶:本地包管理

    http://www.iwangke.me/2013/04/18/advanced-cocoapods/ 粉笔网的iOS工程师唐巧曾经写过一篇blog<使用CocoaPods来做iOS程序的包依 ...

  7. Quartz2D 编程指南(四)位图与图像遮罩、CoreGraphics 绘制 Layer

    概览 图形上下文 路径 颜色与颜色空间 变换 图案 阴影 渐变 透明层 Quartz 2D 中的数据管理 位图与图像遮罩 CoreGraphics 绘制 Layer 位图与图像遮罩 简介 位图与图像遮 ...

  8. CoreGraphics --- 翻转坐标系

    1. 由于CoreGraphics 的坐标系与手机屏幕坐标系的Y轴是相反的, 所以在我们开发的时候, 需要翻转坐标系; - (void)drawRect:(CGRect)rect { CGContex ...

  9. CoreGraphics 之CGAffineTransform仿射变换(3)

    CoreGraphics 之CGAffineTransform仿射变换(3)   CoreGraphics 的 仿射变换 可以用于 平移.旋转.缩放变换路径 或者图形上下文. (1)平移变换将路径或图 ...

随机推荐

  1. Android 动态生成布局 (多层嵌套)

    Android 除了能够载入xml文件,显示布局外,也能够代码生成布局,并通过setContentView(View view)方法显示布局.单独的一层布局,如一个主布局加一个控件(如Button\i ...

  2. vijos P1352 最大获利(最小割)

    请不要随便指点别人该怎么做.每一个人的人生都应该自己掌握.你给不了别人一切.你也不懂别人的忧伤. 微笑不代表快乐.哭泣不一定悲伤 不努力怎么让关心你的人幸福.不努力怎么让看不起你的人绝望. 我用生命在 ...

  3. VSTO学习笔记(三) 开发Office 2010 64位COM加载项

    原文:VSTO学习笔记(三) 开发Office 2010 64位COM加载项 一.加载项简介 Office提供了多种用于扩展Office应用程序功能的模式,常见的有: 1.Office 自动化程序(A ...

  4. Android OpenGL ES 应用(二) 纹理

    上一篇讲了基础入门 OpenGL (一) ,这一次主要学习OpenGL 纹理基本学习总结 要是做复杂的OpenGL应用程序,一定会用到纹理技术.纹理说白了就是把图片或者视频图像绘制到OpenGL空间中 ...

  5. 基于CefGlue的桌面应用开发

    原文地址:http://johnnyfee.github.io/csharp/2013/12/21/cef-glue/ 前言 如果你想使用WEB技术来开发桌面客户端,并且是想使用的语言也是C#时,那请 ...

  6. 深入理解Tomcat系列之二:源码调试环境搭建(转)

    前言 最近对Tomcat的源码比较感兴趣,于是折腾了一番.要调试源码首先需要搭建环境,由于参考了几篇帖子发现都不怎么靠谱,最后还是折腾出来了,然而却花了足足一天的时间去搭建这个环境.发现都不是帖子的问 ...

  7. Android开展:ADT+Eclipse使用错误:Text editor does not have a document provider

    Eclipse参加Android sdk源代码 正在使用Eclipse进行Android开发时间,我们经常需要导入sdk源代码来Eclipse中,方便api阅读和查询,详细操作为:ctrl+鼠标左键. ...

  8. TSL230选型

    tsl230是一种可以直接将光强转化成频率值的器件.详细原理就不介绍了,数据手冊里写的都非常清楚,230系列包括非常多种,主要为下面四类:TSL230,TSL230A,TSL230B系列:TSL230 ...

  9. 158个JAVA免豆精品资料汇总

    附件完整版下载地址: http://down.51cto.com/data/431561 附件部分预览~ java中国移动收费系统[源代码] http://down.51cto.com/data/70 ...

  10. Redshift扩容及踩到的坑

    下午发现redshift集群已经没有什么空间了.删掉一些不须要的暂时表也仅仅降到86%左右,为了能放下这两天的数据必须扩容了 watermark/2/text/aHR0cDovL2Jsb2cuY3Nk ...