iOS Core Graphic,如何计算CGAffineTransform(scaleX offset?

iOS Core Graphic, how to calculate CGAffineTransform(scaleX offset?

虽然我正在通过 ray wenderlich,

学习 Core Graphic

一步是改造UIBezierPath,var transform = CGAffineTransform(scaleX: 0.8, y: 0.8)

不知道为什么后面的步骤是对的,就是transform = transform.translatedBy(x: 15, y: 30)

我不知道x和y位置是怎么算出来的。

通过打印UIBezierPath currentPointprint(medallionPath.currentPoint),我以为宽度应该是(x1 - x2) * 0.5,高度应该是y1 - y2,真不知道为什么是

(x: 15, y: 30)

完整代码如下,已在 Playground 测试

let size = CGSize(width: 120, height: 200)
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
let context = UIGraphicsGetCurrentContext()!

//Gold colors
let darkGoldColor = UIColor(red: 0.6, green: 0.5, blue: 0.15, alpha: 1.0)
let midGoldColor = UIColor(red: 0.86, green: 0.73, blue: 0.3, alpha: 1.0)

let medallionPath = UIBezierPath(ovalIn: CGRect(x: 8, y: 72, width: 100, height: 100))

print(medallionPath.currentPoint)
//  (108.0, 122.0)
print(medallionPath.bounds)
//  (8.0, 72.0, 100.0, 100.0)
context.saveGState()
medallionPath.addClip()

darkGoldColor.setFill()
medallionPath.fill()

context.restoreGState()
// question
var transform = CGAffineTransform(scaleX: 0.8, y: 0.8)

// transform = transform.translatedBy(x: 15, y: 30)
medallionPath.lineWidth = 2.0

//apply the transform to the path
medallionPath.apply(transform)
print(medallionPath.currentPoint)
//  (86.4, 97.6)
print(medallionPath.bounds)
//  (6.4, 57.6, 80.0, 80.0)
medallionPath.stroke()


//This code must always be at the end of the playground
let image = UIGraphicsGetImageFromCurrentImageContext()!

UIGraphicsEndImageContext()
transform = transform.translatedBy(x: 15, y: 30)

翻译。它将整个路径向右移动 15 并向下移动 30。您的问题是 幻数 1530 从何而来。


奖章绘图有一个尺寸为 100 x 100 的圆,起始位置为 (8, 72),由这行代码建立:

let medallionPath = UIBezierPath(ovalIn: CGRect(x: 8, y: 72, width: 100, height: 100))

代码然后通过按 0.8 缩放原始路径添加一个内环,因此它将是一个 80 x 80 圆。为了让这个小圆环的中心与大圆的中心对齐,它需要在水平和垂直方向上额外偏移 10。 (较小的圆在水平和垂直方向上 20 较小,因此将其移动 1/220 可使其正确对齐)。然后的目标是将它定位在 (18, 82)width: 80, height: 80.

因此,我们需要在 X 和 Y 方向上应用 translation(移位),以便在缩放路径时我们最终得到锚定在 (18, 82)。棘手的一点是缩放应用于移位值,因此也必须考虑到这一点。

所以,我们从 8 的 X 位置开始,我们想要应用一些平移值 dx,这样当结果按 0.8 缩放时,我们最终值为 18:

(8 + dx) * 0.8 = 18

求解 dx:

dx = (18 / 0.8) - 8
dx = 14.5

与 Y 类似,我们从 72 的 Y 位置开始,并希望应用平移 dy,这样当它按 0.8 缩放时,我们最终得到 82:

(72 + dy) * 0.8 = 82

求解 dy:

dy = (82 / 0.8) - 72
dy = 30.5

所以,数学上正确的翻译是 (14.5, 30.5):

transform = transform.translatedBy(x: 14.5, y: 30.5)

Ray Wenderlich 出于某些只有他们自己知道的原因将这些四舍五入为 (15, 30)(也许是因为四舍五入的数字在代码中看起来更好?)。有可能他们懒得做数学运算,只是尝试数值直到看起来正确

此处比例为 0.8 表示当前的 80%,因此它的 x、y、宽度和高度都减少到 80% 所以新的比例差异是

scaleDifference = ((1/ 0.8) - 1.0) * 100 = 25%

现在总尺寸差为0.25,这里内圆在中心所以中心点不变所以它的x和y位置改变来计算x和y

这里的路径 rect 是 (8, 72, 100, 100) 所以计算公式

圆从两边缩小 10%,要保持在中心,需要增加 10% x 和 y 并减少 10% 的宽度和高度,这样圆就会在中心

这里的比例设置为 80%,所以我们给出的所有 x 和 y 平移都将计算为 80%,例如,如果我们给出平移 x = 10 和 y = 10,系统将转换为它的 80%,所以x = 8 和 y = 8。

我们必须为 x 和 y 添加宽度差异以使其保持在中心

宽度和高度是 100 所以

100 * (scaleDifference / 2.0)
100 * (0.25 / 2.0) = 12.5

并且由于缩放 x 和 y 也减少到 0.8%,所以要使它成为 100% 是

xDifference = 8 * scaleDifference = 2.0
yDifference = 72 * scaleDifference = 18.0

为了使圆圈保持在中心,我们必须添加与 dx 的宽度差异和与 dy 的高度差异以获得最终的 x 和 y 平移值

dx = xDifference + widthDifference = 2.0 + 12.5 = 14.5 
dy = yDifference + heightDifference = 18.0 + 12.5 = 30.5