Математический вопрос о точечной ротации в .Net - PullRequest
1 голос
/ 23 июня 2010

У меня есть частичный ответ.Начиная с:

newHeight = Высота * cos (радианы) + Ширина * sin (радианы)
newWidth = Высота * sin (радианы) + Ширина * cos (радианы)

Я могупереверните уравнения, чтобы получить:

temp = sqr (cos (радианы)) - sqr (sin (радианы))
высота = newHeight * cos (радианы) - newWidth * sin (радианы) / temp
Width = 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добавлен к ширине.Я уверен, что это связано с грехом, потому что или где-то и то и другое, но замораживание мозга мешает мне построить формулу.

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, которые были повернуты на угол вокруг его центра.Я изменяю ширину и / или высоту границ.Как я могу работать в обратном направлении, чтобы найти оригинальное изображение Bounds, которое могло бы создать BoundsAfterRotation?

Ответы [ 3 ]

1 голос
/ 23 июня 2010

Просто поверните его назад на тот же угол, минус.Обратите внимание, что вы можете использовать класс System.Drawing.Matrix.У него есть метод RotateAt ().Используйте метод TransformPoints (), чтобы применить вращение.И метод Invert () для создания матрицы, которая отображает точки назад.

0 голосов
/ 23 июня 2010

У меня нет времени, чтобы дать полный ответ, но учтите следующее: Если вы начнете с квадрата, повернутого на pi / 2, чтобы он выглядел как <>, и пусть alpha будет углом междулиния, соединяющая центр квадрата с его самым правым краем и осью x, а затем довольно простая тригонометрия говорит вам, что ширина повернутого квадрата равна cos(alpha)*d, где d - диагональ квадрата, если альфа находится между -pi / 4 и pi / 4.

Теперь вам «просто» нужно рассчитать альфа под вашим углом, проверить, какие из ребер важны для определения ширины, и рассчитать «не повернутую» ширинуот диагонали.

0 голосов
/ 23 июня 2010

Вы можете переходить от изображения к повороту, но не от поворота к изображению. Это связано с тем, что при повороте необходимо округлять позиции пикселей, и новое изображение выглядит немного иначе.

Поэтому вы всегда должны держаться за исходное изображение и делать копии изображения для каждого поворота.

Простое вращение назад удвоит округление.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...