关于.Net中点旋转的数学问题
我有一个部分答案。起始于:
newHeight = 高度 * cos(弧度) + 宽度 * sin(弧度)
newWidth = Height * sin(radians) + Width * cos(radians)
我可以反转方程得到:
temp = sqr(cos(radians)) - sqr(sin(radians))
高度 = newHeight * cos(弧度) - newWidth * sin(弧度) / temp
宽度 = newWidth * cos(弧度) - newHeight * sin(弧度) / temp
上述方程仅适用于角度范围 0-28、62-90、180-208 和 242-270。在这些范围之外,计算出的界限太大,导致在 45、135、225 和 315 处溢出。
我想我需要检测我处于哪个象限并稍微修改方程。有什么想法吗?
我一直在努力弄清楚我在这个问题中到底要问什么,所以希望下面的例子能够澄清问题。
该示例的作用是取一个 100x100 的正方形,将其旋转 12 度并将宽度添加 100。我想要做的是找出一个矩形的尺寸,当旋转 12 度时将得到相同的矩形,而无需随后将 100 添加到宽度:
绘制的矩形是旋转形状的边界,而不是形状本身:
Dim radAngle = Math.PI * 12 / 180.0R
Dim widthChange = 100
Dim b2 = New RectangleF(200, 200, 100, 100)
b2 = GetBoundsAfterRotation(b2, radAngle)
b2.Width += widthChange
g.DrawRectangle(Pens.Red, ToRectangle(b2))
Dim offsetY = 21
Dim offsetX = -7
b2 = New RectangleF(200, 200, 100 + widthChange - offsetX, 100 - offsetY)
b2 = GetBoundsAfterRotation(b2, radAngle)
b2.X += CInt(offsetX / 2)
b2.Y += CInt(offsetY / 2)
g.DrawRectangle(Pens.Green, ToRectangle(b2))
通过反复试验,我发现 offsetX 和 offsetY 的值将在这种特殊情况下产生相同的矩形:一个 100x100 的正方形旋转 12 度,宽度增加 100。我确信它在某个地方涉及到 sin、cos 或两者,但大脑冻结阻止我构建公式。
ETA:在这种情况下,我增加了宽度,但我需要一个通用的解决方案来改变宽度、高度或两者。
ETA2:对于本例,生成的矩形边界大小为 218.6 x 118.6。为了在旋转 12 度后获得这些边界,起始矩形边界约为 207 x 79。
原始:
我使用以下标准例程来获取图像绕其中心旋转指定角度后的边界。边界是偏移的,以便图像的中心始终位于同一位置:
Public Function GetBoundsAfterRotation(ByVal imageBounds As RectangleF, ByVal radAngle As Double) As RectangleF
Dim w = imageBounds.Width
Dim h = imageBounds.Height
Dim rotationPoints As PointF() = {New PointF(0, 0), New PointF(w, 0), New PointF(0, h), New PointF(w, h)}
RotatePoints(rotationPoints, New PointF(w / 2.0F, h / 2.0F), radAngle)
Dim newBounds = GetBoundsF(rotationPoints)
Dim x = imageBounds.X + newBounds.X //Offset the location to ensure the centre point remains the same
Dim y = imageBounds.Y + newBounds.Y
Return New RectangleF(New PointF(x, y), newBounds.Size)
End Function
//
Public Shared Sub RotatePoints(ByVal pnts As PointF(), ByVal origin As PointF, ByVal radAngle As Double)
For i As Integer = 0 To pnts.Length - 1
pnts(i) = RotatePoint(pnts(i), origin, radAngle)
Next
End Sub
//
Public Shared Function RotatePoint(ByVal pnt As PointF, ByVal origin As PointF, ByVal radAngle As Double) As PointF
Dim newPoint As New PointF()
Dim deltaX As Double = pnt.X - origin.X
Dim deltaY As Double = pnt.Y - origin.Y
newPoint.X = CSng((origin.X + (Math.Cos(radAngle) * deltaX - Math.Sin(radAngle) * deltaY)))
newPoint.Y = CSng((origin.Y + (Math.Sin(radAngle) * deltaX + Math.Cos(radAngle) * deltaY)))
Return newPoint
End Function
//
Public Shared Function GetBoundsF(ByVal pnts As PointF()) As RectangleF
Dim left As Single = pnts(0).X
Dim right As Single = pnts(0).X
Dim top As Single = pnts(0).Y
Dim bottom As Single = pnts(0).Y
For i As Integer = 1 To pnts.Length - 1
If pnts(i).X < left Then
left = pnts(i).X
ElseIf pnts(i).X > right Then
right = pnts(i).X
End If
If pnts(i).Y < top Then
top = pnts(i).Y
ElseIf pnts(i).Y > bottom Then
bottom = pnts(i).Y
End If
Next
Return New RectangleF(left, top, CSng(Math.Abs(right - left)), CSng(Math.Abs(bottom - top)))
End Function
我的问题是:
我有一些 BoundsAfterRotation 围绕其中心旋转了一个角度。我更改边界的宽度和/或高度。我如何向后工作才能找到创建 BoundsAfterRotation 的原始 imageBounds?
I have a partial answer. Starting with:
newHeight = Height * cos(radians) + Width * sin(radians)
newWidth = Height * sin(radians) + Width * cos(radians)
I can reverse the equations to get:
temp = sqr(cos(radians)) - sqr(sin(radians))
Height = newHeight * cos(radians) - newWidth * sin(radians) / temp
Width = newWidth * cos(radians) - newHeight * sin(radians) / temp
The above equations only behave for the angle ranges 0-28, 62-90, 180-208 and 242-270. Out of these ranges, the calculated bounds are too large and result in an overflow at 45, 135, 225 and 315.
I presume I need to detect which quadrant I'm in and modify the equations slightly. Any ideas?
I've struggled to be clear on what exactly I'm asking for in this question so hopefully the following example will clear things up.
What the example does is take a 100x100 square, rotate it by 12 degrees and add 100 to the width. What I want to do is find out the the dimensions of a rectangle that when rotated by 12 degrees will result in the same rectangle, without adding the 100 to the width afterwards:
The rectangles drawn are the bounds of the rotated shape, not the shape itself:
Dim radAngle = Math.PI * 12 / 180.0R
Dim widthChange = 100
Dim b2 = New RectangleF(200, 200, 100, 100)
b2 = GetBoundsAfterRotation(b2, radAngle)
b2.Width += widthChange
g.DrawRectangle(Pens.Red, ToRectangle(b2))
Dim offsetY = 21
Dim offsetX = -7
b2 = New RectangleF(200, 200, 100 + widthChange - offsetX, 100 - offsetY)
b2 = GetBoundsAfterRotation(b2, radAngle)
b2.X += CInt(offsetX / 2)
b2.Y += CInt(offsetY / 2)
g.DrawRectangle(Pens.Green, ToRectangle(b2))
Through trail and error I found the values of offsetX and offsetY that will result in the same rectangle for this particular case : a 100x100 square rotated by 12 degrees with 100 added to the width. I'm sure it involves sin, cos or both somewhere but brain freeze prevents me from building the formula.
ETA: In this case I increase the width, but I need a general solution for the width, height or both changing.
ETA2: For this case, the resultant rectangle bound's size was 218.6 x 118.6. To get these bounds after rotating through 12 degrees, the start rectangle bounds were around 207 x 79.
Original:
I use the following, standard, routines to get the bounds of an image after it has been rotated by a specified angle, about its centre. The bounds are offset so that the centre of the image is always in the same place:
Public Function GetBoundsAfterRotation(ByVal imageBounds As RectangleF, ByVal radAngle As Double) As RectangleF
Dim w = imageBounds.Width
Dim h = imageBounds.Height
Dim rotationPoints As PointF() = {New PointF(0, 0), New PointF(w, 0), New PointF(0, h), New PointF(w, h)}
RotatePoints(rotationPoints, New PointF(w / 2.0F, h / 2.0F), radAngle)
Dim newBounds = GetBoundsF(rotationPoints)
Dim x = imageBounds.X + newBounds.X //Offset the location to ensure the centre point remains the same
Dim y = imageBounds.Y + newBounds.Y
Return New RectangleF(New PointF(x, y), newBounds.Size)
End Function
//
Public Shared Sub RotatePoints(ByVal pnts As PointF(), ByVal origin As PointF, ByVal radAngle As Double)
For i As Integer = 0 To pnts.Length - 1
pnts(i) = RotatePoint(pnts(i), origin, radAngle)
Next
End Sub
//
Public Shared Function RotatePoint(ByVal pnt As PointF, ByVal origin As PointF, ByVal radAngle As Double) As PointF
Dim newPoint As New PointF()
Dim deltaX As Double = pnt.X - origin.X
Dim deltaY As Double = pnt.Y - origin.Y
newPoint.X = CSng((origin.X + (Math.Cos(radAngle) * deltaX - Math.Sin(radAngle) * deltaY)))
newPoint.Y = CSng((origin.Y + (Math.Sin(radAngle) * deltaX + Math.Cos(radAngle) * deltaY)))
Return newPoint
End Function
//
Public Shared Function GetBoundsF(ByVal pnts As PointF()) As RectangleF
Dim left As Single = pnts(0).X
Dim right As Single = pnts(0).X
Dim top As Single = pnts(0).Y
Dim bottom As Single = pnts(0).Y
For i As Integer = 1 To pnts.Length - 1
If pnts(i).X < left Then
left = pnts(i).X
ElseIf pnts(i).X > right Then
right = pnts(i).X
End If
If pnts(i).Y < top Then
top = pnts(i).Y
ElseIf pnts(i).Y > bottom Then
bottom = pnts(i).Y
End If
Next
Return New RectangleF(left, top, CSng(Math.Abs(right - left)), CSng(Math.Abs(bottom - top)))
End Function
My question is:
I have some BoundsAfterRotation that were rotated by an angle about its centre. I change the width and/or height of the bounds. How can I work backwards to find the original imageBounds that would have created the BoundsAfterRotation?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
只需将其旋转回来相同的角度(负角)即可。请注意,您可以考虑使用 System.Drawing.Matrix 类。它有一个 RotateAt() 方法。使用 TransformPoints() 方法应用旋转。 Invert() 方法创建一个将点映射回来的矩阵。
Just rotate it back by the same angle, negative. Note that you could consider using the System.Drawing.Matrix class. It has a RotateAt() method. Use the TransformPoints() method to apply the rotation. And the Invert() method to create a matrix that maps points back.
您可以从图像转到旋转,但不能从旋转转到图像。这是因为当您旋转时,您必须舍入像素位置,并且新图像看起来有点不同。
因此,您必须始终保留原始图像并为每次旋转制作图像的副本。
只需向后旋转即可进行双舍入。
You can go from image to rotation, but not from rotation to image. That is because when you rotate, you have to round the pixel positions and the new image looks a little bit different.
Therefore you must always hold on to the original image and make copies of the image for every roation.
Simply rotating back will double rounding.
我没有时间给出完整的答案,但请考虑以下事项:如果您从旋转 pi/2 的正方形开始,使其看起来像
<>
,并让 alpha是连接正方形中心与其最右边缘的线与 x 轴之间的角度,然后非常基本的三角学告诉您,旋转正方形的宽度是 cos(alpha)*d ,如果 alpha 介于 -pi/4 和 pi/4 之间,则 d 为正方形的对角线。现在,您“只需”从角度计算 alpha,检查哪些边缘对于了解宽度很重要,并从对角线计算“未旋转”宽度。
I don't have the time to give a complete answer, but consider the following: If you start with the square rotated by pi/2, so that it looks like
<>
, and let alpha be the angle between the line connecting the center of the square with its rightmost edge and the x-axis, then pretty basic trigonometry tells you, that the width of the rotated square iscos(alpha)*d
, with d being the diagonal of the square, if alpha is between -pi/4 and pi/4.Now, you "just" have to calculate alpha from your angle, check wich ones of the edges are the ones important to know the width, and calculate the "unrotated" width from the diagonal.