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?