【问题标题】:iOS Core Graphic, how to calculate CGAffineTransform(scaleX offset?iOS Core Graphic,如何计算 CGAffineTransform(scaleX offset?
【发布时间】:2019-09-08 12:29:33
【问题描述】:

当我通过ray wenderlich学习Core Graphic时,

一步是转换UIBezierPath,var transform = CGAffineTransform(scaleX: 0.8, y: 0.8)

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

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

通过打印UIBezierPath currentPoint print(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()

【问题讨论】:

    标签: ios swift uikit core-graphics drawrect


    【解决方案1】:
    transform = transform.translatedBy(x: 15, y: 30)
    

    是一个翻译。它将整个路径向右移动15,向下移动30。你的问题是 magic numbers 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 方向上应用平移(移位),这样当路径缩放时,我们最终会得到一个锚定在 (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),原因只有他们自己知道(因为四舍五入的数字在代码中可能看起来更好?)。他们可能没有费心做数学运算,只是尝试了值直到它看起来正确

    【讨论】:

      【解决方案2】:

      这里的比例是 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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-07-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-02
        • 2018-05-08
        • 1970-01-01
        相关资源
        最近更新 更多