如何可靠地围绕一个点旋转图像?

13
我阅读了来自One step affine transform for rotation around a point?的以下内容:
CGAffineTransform transform = CGAffineTransformMakeTranslation(x, y);
transform = CGAffineTransformRotate(transform, a);
transform = CGAffineTransformTranslate(transform,-x,-y);

然而,当我这样做时,转换后的图像位置错乱,很少在屏幕上正确显示。

我试过让系统放置图片。如果你运行一个循环并放置几个值,会出现一个螺旋形状。然而,虽然我可能最终能够解开图像旋转和它们所要围绕旋转的点之间的关系,但我想问一下最好的解决方案是什么:“我有一张图片;我认为这个点是它的中心;我想让它围绕它的中心旋转这么多度但不偏移其他位置。”

我正在尝试制作http://JonathansCorner.com/ancient-clock/的修改版,现在我正在尝试放置时针。所有尝试将图像按上述方法进行平移和旋转,以使其中心位于所需中心处的尝试均失败了。

对于这个钟表的指针,如何说“我希望指针在以下旋转角度”并使其正确地围绕中心放置?

--编辑--

这段代码的关键部分,为响应评论而编辑的部分,是:

UIImage *hourHandImage = [UIImage imageNamed:@"hour-hand.png"];
UIImageView *hourHandView = [[UIImageView alloc] initWithImage:hourHandImage];
float hourRotation = .5;
hourHandImage = [UIImage imageNamed:@"hour-hand.png"];
hourHandView = [[UIImageView alloc] initWithImage:hourHandImage];
CGAffineTransform transform = CGAffineTransformMakeTranslation(centerX - 21, -centerY - 121);
// transform = CGAffineTransformRotate(transform, hourRotation);
// transform = CGAffineTransformTranslate(transform, 2 * centerX, 2 * centerY);
hourHandView.transform = transform;
hourHandView.layer.anchorPoint = CGPointMake(centerX, centerY);
hourHandView.layer.affineTransform = CGAffineTransformRotate(transform, hourRotation);
[self.view addSubview:hourHandView];

谢谢,

--编辑--

现在我有了简化版的东西;如果我遵循一些指示,我就有了:

CGAffineTransform transform = CGAffineTransformMakeTranslation(100 -21, 100 -121);
transform = CGAffineTransformRotate(transform, hour / 12.0 * M_PI * 2.0);
transform = CGAffineTransformTranslate(transform, -330, 330);
hourHandView.transform = transform;

我希望能够努力将这些数字整理出来,但是现在已经正确显示了9:00的小时数。

非常感谢您的所有帮助!


你有几张示例图片可以发布吗?在这里你使用的是什么作为 xy?它们应该分别是你尝试旋转的物体的边界矩形的一半宽度和高度。 - jscs
还有,a是什么?请注意,它需要用弧度而不是角度表示。 - jscs
@Josh,我使用x和y来确定时钟指针的中心位置 - 通过图像编辑器选择出来的时钟指针中心通常不是其边界框的中心。a已经用弧度表示,并且我尝试了几个不同的值来映射它的行为;但主要是以0.5作为起点,并且我只给出了弧度角度。 - Christos Hayward
就图片而言,我正在处理的方向上首先显示的是http://JonathansCorner.com/project/tracking_hands.png。现在时针已经超出了屏幕范围;它只是一个漂亮的蒸汽朋克钟面,没有指针。 - Christos Hayward
@JonathanHayward anchorPoint 是一个 CGPoint,表示图层位置在边界矩形内的哪个位置。 它的值在 {0.0,0.0} – {1.0,1.0} 范围内。例如:左上角 = {0,0},中心 = {0.5,0.5},右下角 = {1,1}。将其设置为 0.5,0.9,如下面我的答案所示。 - Jano
显示剩余2条评论
4个回答

13

旋转始终围绕 (0,0) 进行。

要围绕某一点进行翻译,首先需要将该点平移到 (0,0),然后旋转它,再将其平移回去。

所以应该是这样的:

// cx, cy is center of screen
// move (cx,cy) to (0,0)  
CGAffineTransform transform = CGAffineTransformMakeTranslation(-cx, -cy);

// roate around (0,0)  
transform = CGAffineTransformRotate(transform, angleRadians);

// mov e (0,0) back to (cx,cy)  
transform = CGAffineTransformTranslate(transform,cx,cy);

10

这一行:

CGAffineTransform transform = CGAffineTransformMakeTranslation(x, y);

将图片沿 x、y 轴移动。

(注意- 你会围绕控制点旋转,无论你将其设置为什么)

这行:

transform = CGAffineTransformRotate(transform, a);

围绕控制点旋转。

如果您的控制点位于左上角(默认情况),它将围绕左上角旋转。

您需要进行如下设置:

[self layer].anchorPoint = CGPointMake(0.5, 0.5);

让它围绕图层中心旋转。


1
似乎你也没有理解转换是如何工作的:MakeTranslation 创建一个转换矩阵,它将所有点移动 +x,+y;旋转会对现有的转换矩阵进行串联,并添加一个围绕 (0,0) 的旋转矩阵。如果你设置锚点,则在旋转的情况下会为你创建两个转换矩阵:首先将锚点转换为 (0,0),然后进行旋转,再将其移回原位。 - AlexWien

8
hourImageView.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
CGFloat angle = hour / 12.0 * M_PI * 2.0;
hourHand.transform = CGAffineTransformMakeRotation(angle);

3

从Alex的答案中得知,Swift 5版本如下:

旋转始终是围绕(0,0)进行的。

要围绕一个点进行平移,首先需要将旋转点平移到(0,0),然后旋转它,最后再将其平移回去。

因此应该这样做:

// centerX, centerY is center of screen
// move (centerX,centerY) to (0,0)  
var myTransform = CGAffineTransform(translationX: -centerX, y: -centerY)

// rotate around (0,0)  
myTransform = myTransform.concatenating(CGAffineTransform(rotationAngle: angleInRadians))

// move (0,0) back to (cx,cy)  
myTransform = myTransform.concatenating(CGAffineTransform(translationX: centerX, y: centerY))

myView.transform = myTransform

1
单行代码... let transform = CGAffineTransform(translationX: center.x, y: center.y).rotated(by: angle).translatedBy(x: -center.x, y: -center.y) - emrahgunduz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接