看看这段代码,它允许在按行排列的一系列点上进行旋转。
首先是三个函数,它们接受一组值并应用关于 X、Y 或 Z 的相应旋转。
Public Function RotPointsX(ByRef pts() As Variant, angle_rad As Double) As Variant()
Dim n As Integer
n = UBound(pts, 1)
If UBound(pts, 2) <> 3 Then
'Need Three Points
Exit Function
End If
Dim tX As Double, tY As Double, tZ As Double
Dim X As Double, Y As Double, Z As Double
For i = 1 To n
tX = pts(i, 1): tY = pts(i, 2): tZ = pts(i, 3)
X = tX
Y = tY * Cos(angle_rad) - tZ * Sin(angle_rad)
Z = tY * Sin(angle_rad) + tZ * Cos(angle_rad)
pts(i, 1) = X: pts(i, 2) = Y: pts(i, 3) = Z
Next i
RotPointsX = pts
End Function
Public Function RotPointsY(ByRef pts() As Variant, angle_rad As Double) As Variant()
Dim n As Integer
n = UBound(pts, 1)
If UBound(pts, 2) <> 3 Then
'Need Three Points
Exit Function
End If
Dim tX As Double, tY As Double, tZ As Double
Dim X As Double, Y As Double, Z As Double
For i = 1 To n
tX = pts(i, 1): tY = pts(i, 2): tZ = pts(i, 3)
X = tZ * Sin(angle_rad) + tX * Cos(angle_rad)
Y = tY
Z = tZ * Cos(angle_rad) - tX * Sin(angle_rad)
pts(i, 1) = X: pts(i, 2) = Y: pts(i, 3) = Z
Next i
RotPointsY = pts
End Function
Public Function RotPointsZ(ByRef pts() As Variant, angle_rad As Double) As Variant()
Dim n As Integer
n = UBound(pts, 1)
If UBound(pts, 2) <> 3 Then
'Need Three Points
Exit Function
End If
Dim tX As Double, tY As Double, tZ As Double
Dim X As Double, Y As Double, Z As Double
For i = 1 To n
tX = pts(i, 1): tY = pts(i, 2): tZ = pts(i, 3)
X = tX * Cos(angle_rad) - tY * Sin(angle_rad)
Y = tX * Sin(angle_rad) + tY * Cos(angle_rad)
Z = tZ
pts(i, 1) = X: pts(i, 2) = Y: pts(i, 3) = Z
Next i
RotPointsZ = pts
End Function
接下来我需要一个函数将范围转换为数组,以及使用此函数执行此操作的最简单方法:
Public Function AsArray(ByVal r_pts As Range) As Variant()
AsArray = r_pts.Value2
End Function
最后在我的工作表中,我将旋转作为嵌套函数并使用 Ctrl-Shift-Enter 作为数组函数输入
所以对于ZYX 的欧拉旋转,需要以下输入
=RotPointsX(
RotPointsY(
RotPointsZ(
AsArray(<range>),
angle_z),
angle_y),
angle_x)
反向旋转是XYZ的负角旋转
=RotPointsZ(
RotPointsY(
RotPointsX(
AsArray(<range>),
-angle_x),
-angle_y),
-angle_z)
我已经通过还原原始点验证了这一点