【问题标题】:One step affine transform for rotation around a point?围绕一个点旋转的一步仿射变换?
【发布时间】:2012-01-06 17:36:46
【问题描述】:

如何仅使用对 CGAffineTransformMake() 以及 math.h 三角函数(例如 sin()、cos() 等)的一次调用,进行核心图形仿射变换以围绕角度 a 的点 x,y 旋转.,并且没有其他 CG 调用。

这里的其他答案似乎是关于使用多个堆叠变换或多步变换来移动、旋转和移动,使用多个核心图形调用。这些答案不符合我的具体要求。

【问题讨论】:

  • 为什么你需要一个电话到CGAffineTransformMake()?堆叠调用产生完全相同的结果,只是它们以一种可读且有意义的方式进行。如果你真的想在一个调用中完成,你最终只会复制堆栈调用中使用的相同数学,绝对没有好处。
  • 可能有什么要求?您可以使用 CGAffineTransformConcat 将这些“堆叠”转换组合成一个 CGAffineTransform。结果将与各个组件的公式相同,所涉及的计算在内部将相同,或者在 CGAffineTransformConcat 的情况下可能更优化。
  • 我希望矩阵方程用于不同(不一定是欧几里得)几何二维空间中的匹配但非图形模型对象。
  • 也许添加有关您的“要求”的详细信息会鼓励社区提供更多帮助。 “堆叠”转换更具可读性,这通常是首选。
  • 查看接受的答案以了解所需的详细信息:一步变换所需的正弦和余弦方程,可有效地用于直接计算二维物理模型中多个点的位置任何图形上下文,以及在图形上下文中旋转图像以完全匹配。可读性不在我声明的要求之列。

标签: ios math core-graphics cgaffinetransform


【解决方案1】:

围绕点 (x,y) 的角度 a 的旋转对应于仿射变换:

CGAffineTransform transform = CGAffineTransformMake(cos(a),sin(a),-sin(a),cos(a),x-x*cos(a)+y*sin(a),y-x*sin(a)-y*cos(a));

您可能需要插入 -a 而不是 a,具体取决于您希望旋转是顺时针还是逆时针。此外,您可能需要插入 -y 而不是 y,具体取决于您的坐标系是否颠倒。

此外,您可以使用以下三行代码完成完全相同的事情:

CGAffineTransform transform = CGAffineTransformMakeTranslation(x, y);
transform = CGAffineTransformRotate(transform, a);
transform = CGAffineTransformTranslate(transform,-x,-y);

如果您将其应用于视图,您也可以通过 CGAffineTransformMakeRotation(a) 简单地使用旋转变换,前提是您设置视图层的 anchorPoint 属性以反映您想要围绕旋转的点。但是,听起来您对将其应用于视图不感兴趣。

最后,如果您将其应用于非欧几里得二维空间,您可能根本不需要仿射变换。仿射变换是欧几里得空间的等距,这意味着它们保留标准的欧几里得距离以及角度。如果你的空间不是欧几里得,那么你想要的变换实际上可能不是仿射的,或者如果它是仿射的,那么旋转矩阵可能不像我上面用 sin 和 cos 写的那么简单。例如,如果您在双曲空间中,您可能需要使用双曲三角函数 sinh 和 cosh,以及公式中的不同 + 和 - 符号。

附:我还想提醒读到这里的任何人,“仿射”的发音是“问”中的短“a”,而不是“able”中的长“a”。我什至听说 Apple 员工在他们的 WWDC 演讲中误读了它。

【讨论】:

  • 'a' 似乎是以弧度表示的角度
  • 如果您要给出发音提示,那么您还应该指定它是像“fine”中的-fine还是像“feen”中的-fine。但也许我是唯一一个弄错那部分的人。 :-/
  • 旋转超过 180 度时此功能不起作用,该功能转换为最终结果,始终以最短的方式旋转
  • @Zeezer 这是仿射变换的限制,而不是这种方法。
【解决方案2】:

对于像我这样正在努力寻找完整的解决方案来旋转图像并正确缩放以填充包含框架的人,几个小时后这是我拥有的最完整和完美的解决方案获得。

这里的技巧是在涉及任何变换(缩放和旋转)之前平移参考点。之后,您必须连接两个变换以获得完整的仿射变换。

我已将整个解决方案打包在一个 CIFilter 子类中,您可以gist here

以下代码的相关部分:

CGFloat a = _inputDegree.floatValue;
CGFloat x = _inputImage.extent.size.width/2.0;
CGFloat y = _inputImage.extent.size.height/2.0;

CGFloat scale = [self calculateScaleForAngle:GLKMathRadiansToDegrees(a)];

CGAffineTransform transform = CGAffineTransformMakeTranslation(x, y);
transform = CGAffineTransformRotate(transform, a);
transform = CGAffineTransformTranslate(transform,-x,-y);


CGAffineTransform transform2 = CGAffineTransformMakeTranslation(x, y);
transform2 = CGAffineTransformScale(transform2, scale, scale);
transform2 = CGAffineTransformTranslate(transform2,-x,-y);

CGAffineTransform concate   = CGAffineTransformConcat(transform2, transform);

【讨论】:

    【解决方案3】:

    使用视图的图层和锚点。例如

    view.layer.anchorPoint = CGPoint(x:0,y:1.0)
    

    【讨论】:

    • 这个解决方案就像一个魅力!谢谢!
    【解决方案4】:

    对于 Swift 4

    print(x, y) // where x,y is the point to rotate around
    let degrees = 45.0
    let transform = CGAffineTransform(translationX: x, y: y)
        .rotated(by: degrees * .pi / 180)
        .translatedBy(x: -x, y: -y)
    

    【讨论】:

    • 如果可以提取变换矩阵并在其他地方(在 C linpack 和 Metal 等中)使用,则可能有用
    猜你喜欢
    • 1970-01-01
    • 2012-11-21
    • 2023-04-03
    • 2017-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多