最初按中心旋转时围绕点旋转对象

Posted

技术标签:

【中文标题】最初按中心旋转时围绕点旋转对象【英文标题】:Rotate object around point when it's initially rotated by it's center 【发布时间】:2018-11-05 15:01:33 【问题描述】:

绕点旋转很简单:One step affine transform for rotation around a point?

但是,我遇到了一个问题:之前旋转“轨道物体”时它不起作用。代码如下:

import UIKit

class ViewController: UIViewController 

    var orbitingImageView: UIImageView!
    var centerImageView: UIImageView!

    let rr: CGFloat = .pi / 4

    override func viewDidLoad() 
        super.viewDidLoad()

        centerImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 150, height: 150))
        centerImageView.center = CGPoint(x: 300, y: 400)
        centerImageView.backgroundColor = .red
        view.addSubview(centerImageView)

        orbitingImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
        orbitingImageView.center = CGPoint(x: 500, y: 400)
        orbitingImageView.backgroundColor = .blue
        view.addSubview(orbitingImageView)

        orbitingImageView.transform = orbitingImageView.transform
            .rotated(by: rr) //without it works fine

        n()
    

    func n() 
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.05)  //little trick to make an animation

            let angle: CGFloat = 0.05

            let orb = self.orbitingImageView!
            let cen = self.centerImageView!
            let a = CGPoint(x: cen.center.x - orb.center.x,
                            y: cen.center.y - orb.center.y)

            self.orbitingImageView.transform = self.orbitingImageView.transform
                .translatedBy(x: a.x, y: a.y)
                .rotated(by: angle)
                .translatedBy(x: -a.x, y: -a.y)

            self.n()
        
    




extension CGAffineTransform  //helper methods

    func getScale() -> CGFloat 
        return (self.a * self.a + self.c * self.c).squareRoot()
    

    func getRotation() -> CGFloat 
        return atan2(self.b, self.a)
    


现在,我可以像这样修改 n() 函数:

func n() 
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.05)  //little trick to make an animation

        let angle: CGFloat = 0.05

        let orb = self.orbitingImageView!
        let cen = self.centerImageView!
        let a = CGPoint(x: cen.center.x - orb.center.x,
                        y: cen.center.y - orb.center.y)

        self.orbitingImageView.transform = self.orbitingImageView.transform
            .rotated(by: -self.rr)
            .translatedBy(x: a.x, y: a.y)
            .rotated(by: angle)
            .translatedBy(x: -a.x, y: -a.y)
            .rotated(by: self.rr)

        self.n()
    

它又可以工作了。但是,这种方法需要存储初始角度(变量 rr)。

如何计算 rr?

这只是我在“真实”项目中使用的代码的简化版本。在那里我可以平移/捏合/旋转屏幕上的多个对象。例如,如果我选择了 2 个对象,则第一个对象(我的手指在其上)应按其中心旋转,而第二个对象应围绕第一个点的中心旋转。然后就是这个问题,因为如果第二个对象之前单独旋转(通过它的中心),我需要这个旋转(这里是 rr)。

【问题讨论】:

【参考方案1】:

最后,我找到了解决方案。我没有计算 rr,而是用 1 步方法代替了 3 步绕点旋转:

let tr = CGAffineTransform(
    a: cos(angle),
    b: sin(angle),
    c: -sin(angle),
    d: cos(angle),
    tx: a.x - a.x * cos(angle) + a.y * sin(angle),
    ty: a.y - a.x * sin(angle) - a.y * cos(angle)
)

self.orbitingImageView.transform = self.orbitingImageView.transform
    .concatenating(tr)

完整代码:

import UIKit

class ViewController: UIViewController 

    var orbitingImageView: UIImageView!
    var centerImageView: UIImageView!

    let rr: CGFloat = .pi / 4

    override func viewDidLoad() 
        super.viewDidLoad()

        centerImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 150, height: 150))
        centerImageView.center = CGPoint(x: 300, y: 400)
        centerImageView.backgroundColor = .red
        view.addSubview(centerImageView)

        orbitingImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
        orbitingImageView.center = CGPoint(x: 500, y: 400)
        orbitingImageView.backgroundColor = .blue
        view.addSubview(orbitingImageView)


        orbitingImageView.transform = orbitingImageView.transform
            .rotated(by: rr)
            .scaledBy(x: 0.5, y: 0.5) //even works with prescaling

        n()
    

    func n() 
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) 

            let angle: CGFloat = 0.05

            let orb = self.orbitingImageView!
            let cen = self.centerImageView!

            let a = CGPoint(x: cen.center.x - orb.center.x,
                            y: cen.center.y - orb.center.y)

            let tr = CGAffineTransform(
                a: cos(angle),
                b: sin(angle),
                c: -sin(angle),
                d: cos(angle),
                tx: a.x - a.x * cos(angle) + a.y * sin(angle),
                ty: a.y - a.x * sin(angle) - a.y * cos(angle)
            )

            self.orbitingImageView.transform = self.orbitingImageView.transform
                .concatenating(tr)

            self.n()
        
    


现在它适用于预旋转和预缩放。

【讨论】:

以上是关于最初按中心旋转时围绕点旋转对象的主要内容,如果未能解决你的问题,请参考以下文章

AS3 围绕空间点旋转 3D 对象

在OpenGL中围绕特定点旋转对象

如何在 OpenGL 中围绕 Z 轴中心旋转对象?

如何使用MATLAB围绕不是图像中心点的点旋转图像?

围绕世界 0,0,0 而不是对象中心旋转

如何在three.js中围绕对象的中心旋转?