[转]Quartz 2D编程指南(5) – 变换

转自:CocoaChina

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,  10050 );

    旋转变换根据指定的角度来移动坐标空间。我们调用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 / 40 );
    CGContextScaleCTM  (myContext, .25,  .5 );
    CGContextRotateCTM  (myContext, radians  (  22. ) );

    变换操作的顺序会影响到最终的效果。如果调换顺序,将得到不同的结果。调换上面代码的顺序将得到如图5-8所示的效果,代码如下:

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

创建仿射变换

  • 仿射变换操作在矩阵上,而不是在CTM上。我们可以使用这些函数来构造一个之后用于CTM(调用函数CGContextConcatCTM)的矩阵。仿射变换函数使用或者返回一个CGAffineTransform数据对象。我们可以构建简单或复杂的仿射变换。

    仿射变换函数能实现与CTM函数相同的操作–平移、旋转、缩放、联合。表5-1列出了仿射变换函数及其用途。注意每种变换都有两个函数。

    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将一个CGRect数据结构从一个空间变换到另一个空间。

CGAffineTransform矩阵的数学原理1

  • Quartz 2D中,只有CGAffineTransformMake这一个函数需要你了解一点矩阵的数学知识。这个函数使用一个3×3矩阵中的6个值来创建一个仿射变换。虽然你可能从来不会想要自己从头构建一个仿射变换矩阵,但是也许你也想了解一下这些transform函数背后的数学原理。如果不想了解,你可以跳过剩下的内容。

    上面提到的3×3矩阵中的6个关键值分别是:a、b、c、d、tx和ty。

    注意:矩阵最右那一列总是0、0、1。数学上来说,第三列只是因为要允许矩阵连接操作才加上的,这个稍后会解释。这里加上第三列只是为了数学正确性。(在CGAffineTransform结构体中,是没有第三列的定义的,只有前面6个值的定义。)

    给定一个上面那种变换矩阵,Quartz使用下面这个公式来计算点(x, y)变换后的结果(x’, y’):

    点经过矩阵变换后会得到这样的结果:

    下面这个矩阵表示单位矩阵。它表示没有任何的平移、缩放或旋转的效果。坐标点和这个矩阵相乘后,仍然保持不变。

    按照上面那个公式来计算,你就可以看到转换得到的点(x’, y’)和转换前的点(x, y)完全相同:

    下面这个矩阵表示一个平移(translation)操作:

    Quartz用下面这个结果来执行平移:

    下面这个矩阵表示一个对点(x, y)的缩放(scaling)操作:

    Quartz用下面这个结果来缩放坐标系:

    下面这个矩阵表示一个旋转(rotation)操作,将点(x, y)逆时针旋转一个角度:

    Quartz用下面这个结果来执行旋转:

    下面这个等式连接(concatenate)了一个旋转操作和一个平移操作:

    Quartz用下面这个结果来执行变换:

    注意连接矩阵时的顺序很重要–矩阵的乘法是不可以交换的。也就是说矩阵A乘矩阵B的结果不一定等于矩阵B乘矩阵A的结果。

    前面提到,仿射矩阵多带了一列常量(第三列:0,0,1)是为了做连接操作。因为将一个矩阵和另一个矩阵相乘时,矩阵的列数必须和另一个矩阵的行数相同。也就是说,一个2×3的矩阵并不能和另一个2×3的矩阵相乘。因此我们需要多加一列常量。

    在一个转换过的坐标上进行反转(inversion)操作可以得到转换前的原始坐标。将坐标(x, y)用一个矩阵A转换成新坐标(x’, y’)后,再将坐标(x’, y’)用矩阵A的反转矩阵进行转换会得到原始的坐标(x, y)。当一个矩阵和它的反转矩阵相乘时,可以得到一个单位矩阵。

       

CGAffineTransform是一个结构体,用来定义一个3×3阶的矩阵。在Quartz 2D中,这种矩阵用来定义缩放、旋转或平移这种的变换规则(主要是作用在2D坐标系上)。

CTM本质上是一个CGAffineTransform这种结构的矩阵。它是Quartz 2D用来表示用户空间和设备空间之间当前的映射关系的。

如果我们把一个表示缩放、旋转或平移规则的CGAffineTransform矩阵应用在CTM上时,我们就改变了用户空间的坐标系。就使得用户空间中绘制的内容产生了缩放、旋转或平移的效果。

所以我就更喜欢简单的把CGAffineTransform看成一些变换规则。把CTM看成可以被这些变换规则改变的东西,或者我更简单点就把CTM看成当前绘图环境中的坐标系了。 :]

不知道有没有帮到你。你也可以看看后面那没有翻译的那一节“矩阵的数学原理”,看了就比较清楚CGAffineTransform是如何工作的了。

以下是对提供的参考资料的总结,按照要求结构化多个要点分条输出: 4G/5G无线网络优化与网规案例分析: NSA站点下终端掉4G问题:部分用户反馈NSA终端频繁掉4G,主要因终端主动发起SCGfail导致。分析显示,在信号较好的环境下,终端可能因节能、过热保护等原因主动释放连接。解决方案建议终端侧进行分析处理,尝试关闭节电开关等。 RSSI算法识别天馈遮挡:通过计算RSSI平均值及差值识别天馈遮挡,差值大于3dB则认定有遮挡。不同设备分组规则不同,如64T和32T。此方法可有效帮助现场人员识别因环境变化引起的网络问题。 5G 160M组网小区CA不生效:某5G站点开启100M+60M CA功能后,测试发现UE无法正常使用CA功能。问题原因在于CA频点集标识配置错误,修正后测试正常。 5G网络优化与策略: CCE映射方式优化:针对诺基亚站点覆盖农村区域,通过优化CCE资源映射方式(交织、非交织),提升RRC连接建立成功率和无线接通率。非交织方式相比交织方式有显著提升。 5G AAU两扇区组网:与三扇区组网相比,AAU两扇区组网在RSRP、SINR、下载速率和上传速率上表现不同,需根据具体场景选择适合的组网方式。 5G语音解决方案:包括沿用4G语音解决方案、EPS Fallback方案和VoNR方案。不同方案适用于不同的5G组网策略,如NSA和SA,并影响语音连续性和网络覆盖。 4G网络优化与资源利用: 4G室分设备利旧:面对4G网络投资压减与资源需求矛盾,提出利旧多维度调优策略,包括资源整合、统筹调配既有资源,以满足新增需求和提质增效。 宏站RRU设备1托N射灯:针对5G深度覆盖需求,研究使用宏站AAU结合1托N射灯方案,快速便捷地开通5G站点,提升深度覆盖能力。 基站与流程管理: 爱立信LTE基站邻区添加流程:未提供具体内容,但通常涉及邻区规划、参数配置、测试验证等步骤,以确保基站间顺畅切换和覆盖连续性。 网络规划与策略: 新高铁跨海大桥覆盖方案试点:虽未提供详细内容,但可推测涉及高铁跨海大桥区域的4G/5G网络覆盖规划,需考虑信号穿透、移动性管理、网络容量等因素。 总结: 提供的参考资料涵盖了4G/5G无线网络优化、网规案例分析、网络优化策略、资源利用、基站管理等多个方面。 通过具体案例分析,展示了无线网络优化中的常见问题及解决方案,如NSA终端掉4G、RSSI识别天馈遮挡、CA不生效等。 强调了5G网络优化与策略的重要性,包括CCE映射方式优化、5G语音解决方案、AAU扇区组网选择等。 提出了4G网络优化与资源利用的策略,如室分设备利旧、宏站RRU设备1托N射灯等。 基站与流程管理方面,提到了爱立信LTE基站邻区添加流程,但未给出具体细节。 新高铁跨海大桥覆盖方案试点展示了特殊场景下的网络规划需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值