如何从CGContext中获取base-space坐标系对应的变换矩阵
CGContext.setShadow的offset参数必须以base-space为单位指定:
offset - 指定base-space下的平移量
什么是“base-space”?
相关文档给出的解释如下:
- 绘图(用户)坐标系:执行绘图命令时使用的坐标系
- 视图坐标系(base space):相对于视图固定的坐标系
- (物理)设备坐标系:对应物理屏幕像素的坐标系
上述定义已经明确,但*如何获取base-space对应的变换矩阵?*已知CGContext.userSpaceToDeviceSpaceTransform是用户坐标系到物理设备坐标系的变换,请问如何获取用户坐标系到base-space、或是base-space到物理设备坐标系的变换?
回答
两种变换的获取方式如下:
用户坐标系 → base-space 变换矩阵
在UIView的draw(_ rect: CGRect)方法中获取到的CGContext,默认的当前变换矩阵(CTM)就是用户坐标系到base-space的映射,你可以直接通过CGContext.ctm属性读取该值。
如果你中途修改过CTM(比如执行了平移、旋转、缩放等绘图变换操作),可以在修改CTM前先调用CGContext.saveGState()保存初始状态,需要读取初始变换时恢复状态再读取CTM即可。base-space → 物理设备坐标系 变换矩阵
这个变换由屏幕参数和系统坐标规则决定,你可以直接手动构造:
- base-space的单位是点,设备坐标系的单位是像素,x、y方向的缩放系数都是当前屏幕的
scale值 - iOS中base-space原点在左上角,Core Graphics原生设备坐标系原点在左下角,需要额外做y轴翻转处理
示例代码(Swift):
let screenScale = UIScreen.main.scale let viewRenderHeight = view.bounds.height // 构造base-space到设备坐标系的变换矩阵 let baseToDeviceTransform = CGAffineTransform(scaleX: screenScale, y: -screenScale) .translatedBy(x: 0, y: -viewRenderHeight * screenScale)
你也可以通过已知的CGContext.userSpaceToDeviceSpaceTransform倒推验证:由于用户坐标系到设备坐标系的变换 = 用户坐标系到base-space变换 × base-space到设备坐标系变换,因此base-space到设备坐标系的变换 = 初始CTM的逆矩阵 × userSpaceToDeviceSpaceTransform,计算结果和上述手动构造的矩阵完全一致。
内容的提问来源于stack exchange,提问作者Paulius Liekis

