给定变换矩阵M1,原始旋转中心P1和新的旋转中心P2,计算新变换矩阵M2的正确方法是什么,以保持对象的当前位置和轮换完好无损?
我正在开发一个矢量绘图应用程序,允许用户使用Thumb
控件旋转对象。旋转在对象中心周围很好。我已将RenderTransformOrigin
设置为0.5,0.5
,因此只需将RenderTransform
设置为<RotateTransform Angle="{Binding Rotation}" />
即可为我完成工作。
现在我需要允许用户更改轴心点或旋转中心。我添加了另一个Thumb
,允许用户将枢轴点放在他们喜欢的任何地方。我的想法是简单地将此拇指的位置绑定到RenderTransformOrigin
的{{1}}或CenterX
和CenterY
属性,以开始围绕新中心旋转。
然而问题是,只要用户将枢轴滑块移动到新位置,RotateTransform
就会计算新的变换矩阵并相应地移动对象,这会适得其反,因为枢轴拇指只应该动作旋转操作期间的旋转中心。
在过去2周的大部分时间里,我已经意识到我需要为我的物体计算新的变换矩阵,在移动旋转中心的同时保持当前位置和旋转不变。是否有内置或自定义方式来做到这一点?
为了进一步澄清,以下是它应该如何:
RotateTransform
的CenterX和CenterY被绑定到枢轴的位置。RotateTransform
直接绑定到Pivot的位置,但无论在何时将新中心分配给它,RotateTransform都会计算新位置并相应地移动对象。答案 0 :(得分:1)
在上面的评论中回答@KamilNowak的请求,从那时起已经过去了很长时间,但是我只是设法从我的代码存储库中挖掘了这一点。希望这可以帮助您找到前进的方向。基本上,您需要在更改枢轴点的位置后调用此函数(位于vb.net中,但您应该可以翻译):
'_Designer is the main Canvas control on which all drawing objects are placed
Friend Sub AdjustLocationAfterPivotShift(_Designer As Canvas)
'RectangularObject is the underlying VM object that represents my shape
Dim RO = DirectCast(Me.DataContext, RectangularObject)
'My control template has Thumb elements for translation, rotation, scaling and pivot. Here I'm using rotate and pivot thumbs. Use your controls instead.
Dim DIRotateThumb As RotateThumb = VisualTreeExtensions.GetVisualDescendent(Of RotateThumb)(Me)
Dim _RotateHandle = DirectCast(DIRotateThumb.Template.FindName("PART_RotateEllipse", DIRotateThumb), Shapes.Ellipse)
Dim RotateHandlePos As Point = _RotateHandle.TranslatePoint(New Point(5, 5), _Designer)
Dim RotateCenterPos As Point = Me.TranslatePoint(New Point(RO.PivotX + RO.Size.Width / 2, RO.PivotY + RO.Size.Height / 2), _Designer)
'ROTATION_HANDLE_OFFSET is vertical distance between control and rotation thumb
Dim RotationThumbOffsetFromPivot As New Point(-RO.PivotX, -RO.PivotY - Me.ActualHeight / 2 - ROTATION_HANDLE_OFFSET)
RO.Rotation = Me.ComputeAngle(RotateCenterPos, RotateHandlePos, RotationThumbOffsetFromPivot)
Dim NewLocation As Point = ComputeLocationDelta(New Point(RO.PivotX, RO.PivotY), RO.LastPivot.ToPoint(), RO.Rotation)
RO.Location.X += NewLocation.X
RO.Location.Y += NewLocation.Y
'Set LastPivot to current pivot location after adjusting location
RO.LastPivot.X = RO.PivotX
RO.LastPivot.Y = RO.PivotY
End Sub
''' <summary>
''' Computes X and Y delta that must be added to object's current location to
account for pivot's changed location.
''' </summary>
''' <param name="currentPivot"></param>
''' <param name="originalPivot"></param>
''' <param name="angle"></param>
''' <returns></returns>
Private Function ComputeLocationDelta(currentPivot As Point, originalPivot As
Point, angle As Double) As Point
Dim h = currentPivot.X - originalPivot.X
Dim v = currentPivot.Y - originalPivot.Y
Dim trans As System.Windows.Vector = RotateVector2d(h, v, D2R(angle))
Return New Point(trans.X - h, trans.Y - v)
End Function
Friend Function ComputeAngle(center As Point, pos As Point, offset As Point) As Double
Dim xDiff = pos.X - center.X
Dim yDiff = pos.Y - center.Y
Dim offsetAngle = Math.Atan2(offset.Y, offset.X) * 180 / Math.PI
Return Math.Atan2(yDiff, xDiff) * 180.0 / Math.PI - offsetAngle
End Function
Friend Shared Function RotateVector2d(x0 As Double, y0 As Double, rad As Double) As Vector
Dim result As New Vector With {
.X = x0 * Math.Cos(rad) - y0 * Math.Sin(rad),
.Y = x0 * Math.Sin(rad) + y0 * Math.Cos(rad)
}
Return result
End Function
Friend Shared Function D2R(degree As Double) As Double
Return (degree Mod 360) * Math.PI / 180
End Function
希望这不像泥那么清澈,您可以使用它来谋福利。