Swift:如何在二维平面上旋转点?

4

我想让一个点逆时针旋转90度。

初始

https://ibb.co/HHCCSyp

最终

https://ibb.co/3vyV7PG

我们来看一下初始图像中左上角和右上角的点。它们的坐标是:

let topLeft = CGPoint(x: 2, y: 1)  
let topRight = CGPoint(x: 3, y: 1) 

旋转之后它们的坐标应该变为:

topLeft 1:0
topRight 2:0

我该怎么做呢?

我尝试了几种答案,但没有一个能给我最终的结果。

以下代码都没有成功: 旋转CGPoint围绕另一个CGPoint

在网格上旋转CGPoint的最佳方法是什么?

这里是我的示例代码:

 let topLeft = CGPoint(x: 2, y: 1)   
 let topRight = CGPoint(x: 3, y: 1)  

 func rotatePoint1(_ point: CGPoint, _ degrees: CGFloat) -> CGPoint {
     let s = CGFloat(sinf(Float(degrees)))
     let c = CGFloat(cosf(Float(degrees)));
     return CGPoint(x: c * point.x - s * point.y, y: s * point.x + c * point.y)
 }

 func rotatePoint2(_ point: CGPoint, _ degrees: CGFloat, _ origin: CGPoint) -> CGPoint {
     let dx = point.x - origin.x
     let dy = point.y - origin.y
     let radius = sqrt(dx * dx + dy * dy)
     let azimuth = atan2(dy, dx) // in radians
     let newAzimuth = azimuth + degrees * CGFloat(M_PI / 180.0) // convert it to radians
     let x = origin.x + radius * cos(newAzimuth)
     let y = origin.y + radius * sin(newAzimuth)
     return CGPoint(x: x, y: y)
 }

 func rotatePoint3(_ point: CGPoint, _ degrees: CGFloat) -> CGPoint {
     let translateTransform = CGAffineTransform(translationX: point.x, y: point.y)
     let rotationTransform = CGAffineTransform(rotationAngle: degrees)
     let customRotation = (rotationTransform.concatenating(translateTransform.inverted())).concatenating(translateTransform)
     return point.applying(customRotation)
 }

 print(rotatePoint1(topLeft, -90))
 print(rotatePoint1(topRight, -90))

在绕中心点逆时针旋转90度后,您的“topLeft”变成了左下角(1:1)(而“topRight”变成了左上角),因此值得更清楚地指定问题。 - MBo
2个回答

7
您的示例实际上描述了两个旋转:

  1. 将点围绕3x3网格的中心逆时针旋转90度。这样做后,topLeft点变为bottomLefttopRight变为topLeft
  2. 然后,您将这些点绕正方形中心顺时针旋转90度(即相反的方向),使它们再次成为topLefttopRight

使用this answer中的此函数:

func rotatePoint(target: CGPoint, aroundOrigin origin: CGPoint, byDegrees: CGFloat) -> CGPoint {
    let dx = target.x - origin.x
    let dy = target.y - origin.y
    let radius = sqrt(dx * dx + dy * dy)
    let azimuth = atan2(dy, dx) // in radians
    let newAzimuth = azimuth + byDegrees * .pi / 180 // convert it to radians
    let x = origin.x + radius * cos(newAzimuth)
    let y = origin.y + radius * sin(newAzimuth)
    return CGPoint(x: x, y: y)
}

let topLeft = CGPoint(x: 2, y: 1)
let topRight = CGPoint(x: 3, y: 1)
let squareCenter = CGPoint(x: 2.5, y: 1.5)

// First rotate around the center of the 3 x 3 square
let centerOfRotation = CGPoint(x: 1.5, y: 1.5)

let tl1 = rotatePoint(target: topLeft, aroundOrigin: centerOfRotation, byDegrees: -90)  // (x 1 y 1)
let tr1 = rotatePoint(target: topRight, aroundOrigin: centerOfRotation, byDegrees: -90) // (x 1 y 0)
let sc1 = rotatePoint(target: squareCenter, aroundOrigin: centerOfRotation, byDegrees: -90)  // (x 1.5 y 0.5)

// Now rotate the 1x1 square the other way around new position of square center
let tl2 = rotatePoint(target: tl1, aroundOrigin: sc1, byDegrees: 90)  // (x 1 y 0)
let tr2 = rotatePoint(target: tr1, aroundOrigin: sc1, byDegrees: 90)  // (x 2 y 0)

注意:正如@MBo在评论中指出的那样,如果您的单元格始终为1x1,则只需旋转单元格的中心,然后添加和减去0.5偏移量即可找到四个角落。


@vacawame 谢谢,这正是我需要的,现在我明白为什么所有尝试都失败了。非常感谢你。还有一个问题,如何将它设置为底部左侧和底部右侧? - Kolkos
1
@vacawama 似乎您正确理解了作者的需求。只需注意 - 只需要使用单个旋转 - 旋转小格子的中心,然后添加角落的偏移量即可。 - MBo
@MBo,没错。如果单元格始终为1x1,则可以旋转中心并添加偏移量。我试图保持通用性,以防以后旋转其他大小和尺寸的单元格。 - vacawama
squareCenter 基于您正在旋转的正方形。 您可以使用 topRight.x - topLeft.x 计算尺寸,将其一半加到 topLeft.xtopLeft.y 中以找到 squareCenter。 如果您询问更大的网格,则旋转中心只是 (gridWidth/2.0, gridHeight/2.0) - vacawama
@vacawama 我已经苦苦挣扎了一段时间,面临着非常类似的问题。我想在方向改变后将一个CGPoint从横屏转换为其对应的竖屏位置,反之亦然。换句话说,这个点应该保持在完全相同的位置。你能看一下我的尝试吗? - Leo Dabus

1
你可以像这样转换视图: yourView.transform = CGAffineTransform(rotationAngle: -CGFloat.pi/2) 编辑: 我的错误。
使用角度时,请使用CGFloat.pi print(rotatePoint1(topLeft, -CGFloat.pi/2)) 直接使用sin和cos函数。
let s = sin(degrees)
let c = cos(degrees)

iOS的坐标系与标准坐标系有些不同,因此您需要调整角度(您可以查看simulation)。

print(rotatePoint1(topLeft, -CGFloat.pi/2)) // (1.0000000000000002, -2.0)
print(rotatePoint1(topRight, -CGFloat.pi/2)) // (1.0000000000000002, -3.0)

嘿,输出不正确,请检查我帖子中的图像:左上角应该是1:0,右上角是2:0。 - Kolkos

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