ios 绕点旋转的一步仿射变换?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8275882/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 15:36:13  来源:igfitidea点击:

One step affine transform for rotation around a point?

iosmathcore-graphicscgaffinetransform

提问by hotpaw2

How can I make a Core Graphics affine transform for rotation around a point x,y of angle a, using only a single call to CGAffineTransformMake() plus math.h trig functions such as sin(), cos(), etc., and no other CG calls.

如何仅使用一次调用 CGAffineTransformMake() 加上 math.h 触发函数(例如 sin()、cos() 等)来进行 Core Graphics 仿射变换以围绕角度 a 的点 x,y 旋转,以及没有其他 CG 调用。

Other answers here seem to be about using multiple stacked transforms or multi-step transforms to move, rotate and move, using multiple Core Graphics calls. Those answers do not meet my specific requirements.

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

回答by landweber

A rotation of angle a around the point (x,y) corresponds to the affine transformation:

围绕点 (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));

You may need to plug in -a instead of a depending on whether you want the rotation to be clockwise or counterclockwise. Also, you may need to plug in -y instead of y depending on whether or not your coordinate system is upside down.

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

Also, you can accomplish precisely the same thing in three lines of code using:

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

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

If you were applying this to a view, you could also simply use a rotation transform via CGAffineTransformMakeRotation(a), provided you set the view's layer's anchorPoint property to reflect the point you want to rotate around. However, is sounds like you aren't interested in applying this to a view.

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

Finally, if you are applying this to a non-Euclidean 2D space, you may not want an affine transformation at all. Affine transformations are isometries of Euclidean space, meaning that they preserve the standard Euclidean distance, as well as angles. If your space is not Euclidean, then the transformation you want may not actually be affine, or if it is affine, the matrix for the rotation might not be as simple as what I wrote above with sin and cos. For instance, if you were in a hyperbolic space, you might need to use the hyperbolic trig functions sinh and cosh, along with different + and - signs in the formula.

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

P.S. I also wanted to remind anyone reading this far that "affine" is pronounced with a short "a" as in "ask", not a long "a" as in "able". I have even heard Apple employees mispronouncing it in their WWDC talks.

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

回答by Ming Chu

for Swift 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)

回答by valvoline

For those like me, that are struggling in search of a complete solution to rotate an image and scale it properly, in order to fill the containing frame, after a couple of hours this is the most complete and flawless solution that I have obtained.

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

The trick here is to translate the reference point, before any trasformation involved (both scale and rotation). After that, you have to concatenate the two transform in order to obtain a complete affine transform.

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

I have packed the whole solution in a CIFilter subclass that you can gist here.

我已将整个解决方案打包在一个 CIFilter 子类中,您可以在此处获取该子类。

Following the relevant part of code:

按照代码的相关部分:

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

回答by dijipiji

Use the view's layer and anchor point. e.g.

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

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