excel 对象沿着自定义轴的二维旋转

gz5pxeao  于 2023-01-31  发布在  其他
关注(0)|答案(2)|浏览(166)

我正试着把我的头缠在如何绕着任何轴旋转一个2d对象上,这个轴可以是任何地方,包括形状本身之外。
我碰巧使用的语言是VBA,但任何伪代码都可以。
我正在寻找一个类似这样的函数:

function rotate(obj, axisX, axisY, angle)
    obj.rotate(angle)
    obj.x = ?
    obj.y = ?

我不确定这是否相关,但为了简单起见,我们可以假设形状是矩形。
并且一旦形状被旋转,x,y坐标将是包含旋转形状的正方形的坐标。

    • 编辑:**

我试过实现这两个函数。它们的行为完全相同,但不使用轴有旋转点。
下面是我现在拥有的代码,通过一个屏幕截图可以了解代码的行为。您将看到,最初,轴心点位于矩形内部,然而,旋转后,矩形以这样的方式移动,轴心点不再包含在其中。
注意注解的- .Height / 2,这是建议的。如果我把减法和旋转0度,矩形是关闭的。如果我删除这一位,矩形是正确的位置时,尝试旋转0度。

'((( TRUNCATED CODE)))
    'Rotate
    Dim Axis As Coordinates
    With Axis
        .X = objHinge.Left + (objHinge.Width / 2)
        .Y = objHinge.Top + (objHinge.Height / 2)
    End With
    
    Call RotateAroundAxis(objBookcaseB, Axis, Range("rotation").Value)
End Sub


Private Sub RotateAroundAxis(ByRef Obj As Shape, Axis As Coordinates, angle As Integer)
    
    Dim deltaX As Integer
    Dim deltaY As Integer
    
    
    deltaX = Obj.Left - Axis.X
    deltaY = Obj.Top - Axis.Y
    
    '// apply 2D rotation matrix
    Dim RadianAngle As Double
    RadianAngle = angle * 3.14159 / 180
    Dim Coords As Coordinates
    With Coords
        .X = deltaX * Cos(RadianAngle) - deltaY * Sin(RadianAngle)
        .Y = deltaX * Sin(RadianAngle) + deltaY * Cos(RadianAngle)
    End With
    
    With Obj
        .Left = Coords.X + Axis.X '- .Width / 2
        .Top = Coords.Y + Axis.Y '- .Height / 2
        .Rotation = angle
    End With
    
End Sub

Private Sub RotateAroundAxis2(ByRef Obj As Shape, Axis As Coordinates, angle As Integer)

    Dim newCoords As Coordinates
    newCoords = RotateCoordinates(Obj.Left, Obj.Top, Axis.X, Axis.Y, angle)
    
    With Obj
        .Left = newCoords.X '- .Width / 2
        .Top = newCoords.Y '- .Height / 2
        .Rotation = angle
    End With
    
End Sub

'X = X coordinate of the object to rotate
'Y = Y coordinate of the object to rotate
'Xa = axis to rotate with
'Ya = axis to rotate with
'R = Degrees of rotation (in radians)
Private Function RotateCoordinates(X, Y, Xa, Ya, angle) As Coordinates
    Dim Pi As Double
    Dim R As Double
    Pi = 3.14159
    R = angle * Pi / 180
 
    'Location Formulas
    RotateCoordinates.X = ((X - Xa) * Cos(R)) - ((Y - Ya) * Sin(R)) + Xa
    RotateCoordinates.Y = ((X - Xa) * Sin(R)) + ((Y - Ya) * Cos(R)) + Ya
End Function

dw1jzc5e

dw1jzc5e1#

对此的常用方法是将操作分为三个基本步骤:
1.将对象移动到局部空间(也称为对象空间)
1.绕原点旋转
1.向后移动对象(也称为世界空间)

function rotate(obj, axisX, axisY, angle) {
     // 1.
     obj.x -= axisX
     obj.y -= axisY

     // 2.
     obj.rotate(angle)

     // 3.
     obj.x += axisX
     obj.y += axisY
 }

编辑有关obj.rotate的一些注解:该方法假设rotate函数全局旋转也就是说,如果对象不在原点,它将以类似于方式的轨道旋转。但如果rotate局部旋转对象(对象空间)对象将始终围绕其中心旋转,而不管其在世界空间中的位置。在这种情况下,您需要自己另外计算新位置(但使用相同的原理):

ox = obj.x - axisX
oy = obj.y - axisY

// apply 2D rotation matrix
obj.x = ox * cos(angle) - oy * sin(angle)
obj.y = ox * sin(angle) + oy * cos(angle)

obj.x += axisX
obj.y += axisY
h7wcgrx3

h7wcgrx32#

原件:

好吧,我可以看到我们已经有了一般的答案,但我有一点乐趣,使这一点,所以我会张贴它无论如何。
它展示了所有的概念是如何结合在一起的,所以可能会对某人有所帮助。

Option Explicit
Type ObjLocData
    X As Long
    Y As Long
End Type
Sub Rotate_Object_About_Axis()

    Dim RotObj As Shape
    Dim RotLoc1 As ObjLocData
    Dim RotLoc2 As ObjLocData
    Dim AxisObj As Shape
    Dim AxisLoc As ObjLocData
    Dim R_Rad As Double
    Dim Pi As Double
    
    R_Rad = 0.1
    Pi = 3.14159
    
    Set AxisObj = ActiveSheet.Shapes("AxisObj")
    AxisLoc = ObjectLocation(AxisObj)
    Set RotObj = ActiveSheet.Shapes("RotObj")
    RotLoc1 = ObjectLocation(RotObj)
    Debug.Print AxisLoc.X
    
    RotLoc2 = RotateCoordinates(AxisLoc.X, AxisLoc.Y, RotLoc1.X, RotLoc1.Y, R_Rad)
    With RotObj
        .Left = RotLoc2.X - (.Width / 2)
        .Top = RotLoc2.Y - (.Height / 2)
        .Rotation = .Rotation + (R_Rad * 360 / (2 * Pi))
    End With
    
End Sub
Function ObjectLocation(Shp As Object) As ObjLocData
    ObjectLocation.X = Shp.Left + (Shp.Width / 2)
    ObjectLocation.Y = Shp.Top + (Shp.Height / 2)
End Function
Function RotateCoordinates(Xa, Ya, X, Y, R) As ObjLocData
    RotateCoordinates.X = ((X - Xa) * Cos(R)) - ((Y - Ya) * Sin(R)) + Xa
    RotateCoordinates.Y = ((X - Xa) * Sin(R)) + ((Y - Ya) * Cos(R)) + Ya
End Function
'Location Formulas
'X'=(x-p)cos(?)-(y-q)sin(?)+p,
'y'=(x-p)sin(?)+(y-q)cos(?)+q.

更新:

我重做的脚本与度的工作,只是一个独立的子。你只需要调用它与你的两个形状和所需的旋转度。请记住旋转轴将是中心的枢轴对象如果你想它是其他任何东西,你将需要改变代码。

Option Explicit
Type ObjLocData
    X As Long
    Y As Long
End Type
Sub Example_Of_Usage()

    Dim Door As Shape
    Dim Pivot As Shape
    Dim R As Double
    
    Set Door = ActiveSheet.Shapes("Door")
    Set Pivot = ActiveSheet.Shapes("PivotPoint")
    R = 45
    
    Call Rotate_Object_About_Axis(Door, Pivot, R)
    
End Sub
Sub Rotate_Object_About_Axis(RotObj As Shape, AxisObj As Shape, R_Deg As Double)

    Dim RotLoc1 As ObjLocData
    Dim RotLoc2 As ObjLocData
    Dim AxisLoc As ObjLocData
    Dim R_Rad As Double
    Dim Pi As Double
    
    Pi = 3.14159
    R_Rad = (R_Deg / 360 * (2 * Pi))
    Debug.Print R_Rad
    Debug.Print R_Deg
    
    
    AxisLoc = ObjectLocation(AxisObj)
    RotLoc1 = ObjectLocation(RotObj)
    
    RotLoc2 = RotateCoordinates(AxisLoc.X, AxisLoc.Y, RotLoc1.X, RotLoc1.Y, R_Rad)
    With RotObj
        .Left = RotLoc2.X - (.Width / 2)
        .Top = RotLoc2.Y - (.Height / 2)
        .Rotation = .Rotation + (R_Rad * 360 / (2 * Pi))
    End With
    
End Sub
Function ObjectLocation(Shp As Object) As ObjLocData
    ObjectLocation.X = Shp.Left + (Shp.Width / 2)
    ObjectLocation.Y = Shp.Top + (Shp.Height / 2)
End Function
Function RotateCoordinates(Xa, Ya, X, Y, R) As ObjLocData
    RotateCoordinates.X = ((X - Xa) * Cos(R)) - ((Y - Ya) * Sin(R)) + Xa
    RotateCoordinates.Y = ((X - Xa) * Sin(R)) + ((Y - Ya) * Cos(R)) + Ya
End Function
'Location Formulas
'X'=(x-p)cos(?)-(y-q)sin(?)+p,
'y'=(x-p)sin(?)+(y-q)cos(?)+q.

新示例:

R = -45

R = +10

R = +35,带新枢轴点

相关问题