最初按中心旋转时围绕点旋转对象
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()
现在它适用于预旋转和预缩放。
【讨论】:
以上是关于最初按中心旋转时围绕点旋转对象的主要内容,如果未能解决你的问题,请参考以下文章