Подтвердить что ты не робот

Вычислить координаты прямоугольника с поворотным прямоугольником

У меня есть координаты верхней левой части прямоугольника, а также его ширина, высота и вращение от 0 до 180 и от -0 до -180.

Я пытаюсь получить ограниченные координаты фактического прямоугольника вокруг прямоугольника.

Что такое простой способ вычисления координат ограничивающего блока

  • Min y, max y, min x, max x?

Точка A не всегда находится на границе min y, она может быть где угодно.

Я могу использовать матрицу инструментария преобразования в as3, если это необходимо.

4b9b3361

Ответ 1

  • Преобразование координат всех четырех углов
  • Найти наименьшее из всех четырех x как min_x
  • Найдите самый большой из всех четырех x и назовите его max_x
  • То же, что и у
  • Ваша ограничивающая рамка (min_x,min_y), (min_x,max_y), (max_x,max_y), (max_x,min_y)

AFAIK, нет никакой королевской дороги, которая заставит вас там намного быстрее.

Если вам интересно, как преобразовать координаты, попробуйте:

x2 = x0+(x-x0)*cos(theta)+(y-y0)*sin(theta)
y2 = y0-(x-x0)*sin(theta)+(y-y0)*cos(theta)

где (x0, y0) - центр, вокруг которого вы вращаетесь. Возможно, вам понадобится возиться с этим в зависимости от ваших функций триггера (они ждут градусов или радиан) смысла/признака вашей системы координат в сравнении с тем, как вы указываете углы и т.д.

Ответ 2

Я понимаю, что вы просите ActionScript, но на всякий случай кто-то ищет здесь iOS или OS-X ответ, вот что:

+ (CGRect) boundingRectAfterRotatingRect: (CGRect) rect toAngle: (float) radians
{
    CGAffineTransform xfrm = CGAffineTransformMakeRotation(radians);
    CGRect result = CGRectApplyAffineTransform (rect, xfrm);

    return result;
}

Если ваша ОС предлагает вам всю тяжелую работу, пусть это!:)

Swift:

func boundingRectAfterRotatingRect(rect: CGRect, toAngle radians: CGFloat) -> CGRect {
    let xfrm = CGAffineTransformMakeRotation(radians)
    return CGRectApplyAffineTransform (rect, xfrm)
}

Ответ 3

Метод, описанный MarkusQ, работает отлично, но имейте в виду, что вам не нужно преобразовывать остальные три угла, если у вас уже есть точка A.

Альтернативный метод, который является более эффективным, состоит в том, чтобы проверить, в каком квадранте находится ваш angular поворота, а затем просто вычислить ответ напрямую. Это более эффективно, поскольку у вас есть только наихудший случай из двух операторов if (проверка угла), тогда как другой подход имеет наихудший случай из двенадцати (6 для каждого компонента при проверке трех других углов, чтобы увидеть, больше ли они текущего максимум или меньше текущего минимума) я думаю.

Основной алгоритм, который использует не более чем ряд применений теоремы Пифагора, показан ниже. Я обозначил angular поворота тэтой и обозначил проверку в градусах в виде псевдокода.

ct = cos( theta );
st = sin( theta );

hct = h * ct;
wct = w * ct;
hst = h * st;
wst = w * st;

if ( theta > 0 )
{
    if ( theta < 90 )
    {
        // 0 < theta < 90
        y_min = A_y;
        y_max = A_y + hct + wst;
        x_min = A_x - hst;
        x_max = A_x + wct;
    }
    else
    {
        // 90 <= theta <= 180
        y_min = A_y + hct;
        y_max = A_y + wst;
        x_min = A_x - hst + wct;
        x_max = A_x;
    }
}
else
{
    if ( theta > -90 )
    {
        // -90 < theta <= 0
        y_min = A_y + wst;
        y_max = A_y + hct;
        x_min = A_x;
        x_max = A_x + wct - hst;
    }
    else
    {
        // -180 <= theta <= -90
        y_min = A_y + wst + hct;
        y_max = A_y;
        x_min = A_x + wct;
        x_max = A_x - hst;
    }
}

Этот подход предполагает, что у вас есть то, что, как вы говорите, у вас есть, то есть точка A, и значение для тета, которое находится в диапазоне [-180, 180]. Я также предположил, что тета увеличивается в направлении по часовой стрелке, так как то, что прямоangularьник, повернутый на 30 градусов на вашей диаграмме, похоже, указывает на то, что вы используете, я не был уверен, что пыталась обозначить часть справа. Если это не так, просто поменяйте местами симметричные предложения, а также знак слагаемых.

Ответ 4

    fitRect: function( rw,rh,radians ){
            var x1 = -rw/2,
                x2 = rw/2,
                x3 = rw/2,
                x4 = -rw/2,
                y1 = rh/2,
                y2 = rh/2,
                y3 = -rh/2,
                y4 = -rh/2;

            var x11 = x1 * Math.cos(radians) + y1 * Math.sin(radians),
                y11 = -x1 * Math.sin(radians) + y1 * Math.cos(radians),
                x21 = x2 * Math.cos(radians) + y2 * Math.sin(radians),
                y21 = -x2 * Math.sin(radians) + y2 * Math.cos(radians), 
                x31 = x3 * Math.cos(radians) + y3 * Math.sin(radians),
                y31 = -x3 * Math.sin(radians) + y3 * Math.cos(radians),
                x41 = x4 * Math.cos(radians) + y4 * Math.sin(radians),
                y41 = -x4 * Math.sin(radians) + y4 * Math.cos(radians);

            var x_min = Math.min(x11,x21,x31,x41),
                x_max = Math.max(x11,x21,x31,x41);

            var y_min = Math.min(y11,y21,y31,y41);
                y_max = Math.max(y11,y21,y31,y41);

            return [x_max-x_min,y_max-y_min];
        }

Ответ 5

если вы используете GDI +, вы можете создать новый GrpaphicsPath → Добавить любые точки или фигуры к нему → Применить поворотное преобразование → использовать GraphicsPath.GetBounds(), и он вернет прямоугольник, который ограничивает вашу повернутую форму.

(изменить) Пример VB.Net

Public Shared Sub RotateImage(ByRef img As Bitmap, degrees As Integer)
' http://stackoverflow.com/questions/622140/calculate-bounding-box-coordinates-from-a-rotated-rectangle-picture-inside#680877
'
Using gp As New GraphicsPath
  gp.AddRectangle(New Rectangle(0, 0, img.Width, img.Height))

  Dim translateMatrix As New Matrix
  translateMatrix.RotateAt(degrees, New PointF(img.Width \ 2, img.Height \ 2))
  gp.Transform(translateMatrix)

  Dim gpb = gp.GetBounds

  Dim newwidth = CInt(gpb.Width)
  Dim newheight = CInt(gpb.Height)

  ' http://www.codeproject.com/Articles/58815/C-Image-PictureBox-Rotations
  '
  Dim rotatedBmp As New Bitmap(newwidth, newheight)

  rotatedBmp.SetResolution(img.HorizontalResolution, img.VerticalResolution)

  Using g As Graphics = Graphics.FromImage(rotatedBmp)
    g.Clear(Color.White)
    translateMatrix = New Matrix
    translateMatrix.Translate(newwidth \ 2, newheight \ 2)
    translateMatrix.Rotate(degrees)
    translateMatrix.Translate(-img.Width \ 2, -img.Height \ 2)
    g.Transform = translateMatrix
    g.DrawImage(img, New PointF(0, 0))
  End Using
  img.Dispose()
  img = rotatedBmp
End Using

Конец Sub

Ответ 6

Хотя Code Guru указал метод GetBounds(), я заметил, что вопрос отмечен как 3, flex, так что вот фрагмент as3, который иллюстрирует идею.

var box:Shape = new Shape();
box.graphics.beginFill(0,.5);
box.graphics.drawRect(0,0,100,50);
box.graphics.endFill();
box.rotation = 20;
box.x = box.y = 100;
addChild(box);

var bounds:Rectangle = box.getBounds(this);

var boundingBox:Shape = new Shape();
boundingBox.graphics.lineStyle(1);
boundingBox.graphics.drawRect(bounds.x,bounds.y,bounds.width,bounds.height);
addChild(boundingBox);

Я заметил, что есть два метода, которые, похоже, делают одно и то же: getBounds() и getRect()

Ответ 7

/**
     * Applies the given transformation matrix to the rectangle and returns
     * a new bounding box to the transformed rectangle.
     */
    public static function getBoundsAfterTransformation(bounds:Rectangle, m:Matrix):Rectangle {
        if (m == null) return bounds;

        var topLeft:Point = m.transformPoint(bounds.topLeft);
        var topRight:Point = m.transformPoint(new Point(bounds.right, bounds.top));
        var bottomRight:Point = m.transformPoint(bounds.bottomRight);
        var bottomLeft:Point = m.transformPoint(new Point(bounds.left, bounds.bottom));

        var left:Number = Math.min(topLeft.x, topRight.x, bottomRight.x, bottomLeft.x);
        var top:Number = Math.min(topLeft.y, topRight.y, bottomRight.y, bottomLeft.y);
        var right:Number = Math.max(topLeft.x, topRight.x, bottomRight.x, bottomLeft.x);
        var bottom:Number = Math.max(topLeft.y, topRight.y, bottomRight.y, bottomLeft.y);
        return new Rectangle(left, top, right - left, bottom - top);
    }

Ответ 8

Примените матрицу вращения к своим угловым точкам. Затем используйте минимальные/максимальные значения полученных координат x, y, чтобы определить новый ограничивающий прямоугольник.

Ответ 9

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

Подписи:

public static float getAngleFromPoint (конечная точка PointPoint, конечная точка TouchPoint)

public static float getTwoFingerDistance (float firstTouchX, float firstTouchY, float secondTouchX, float secondTouchY)

Точка getPointFromAngle (конечный двойной угол, конечный двойной радиус)

Это решение предполагает, что плотность пикселей равномерно распределена. Перед вращением объекта сделайте следующее:

  • Используйте getAngleFromPoint для вычисления угла от центра до верхнего правого угла (скажем, это возвращает 20 градусов), что означает, что верхний левый угол составляет -20 градусов или 340 градусов.

  • Используйте getTwoFingerDistance для возврата диагонального расстояния между центральной точкой и верхним правом углом (это расстояние должно быть одинаковым во всех углах, это расстояние будет использоваться при следующем вычислении).

  • Теперь скажем, что мы поворачиваем объект по часовой стрелке на 30 градусов. Теперь мы знаем, что верхний правый угол должен быть на уровне 50 градусов, а верхний левый угол - на 10 градусов.

  • Теперь вы можете использовать функцию getPointFromAngle в верхнем левом и верхнем правом углу. используя радиус, возвращенный с шага 2. Положение X, умноженное на 2 из верхнего правого угла, должно дать вам новую ширину, а положение Y позиции 2 из верхнего левого угла должно дать новую высоту.

Эти выше 4 шага должны быть помещены в условия, основанные на том, насколько вы повернули свой объект другим способом, вы можете вернуть высоту как ширину и ширину, как высоту.

Заметим, что угловые функции выражаются в коэффициентах 0-1 вместо 0-360 (просто умножьте или разделите на 360, если это необходимо):

//Получает угол из двух точек, выраженный как коэффициент 0 -1 (0 составляет 0/360, 0,25 - 90 градусов и т.д.)

public float getAngleFromPoint(final Point centerPoint, final Point touchPoint) {

    float returnVal = 0;

    //+0 - 0.5
    if(touchPoint.x > centerPoint.x) {

        returnVal = (float) (Math.atan2((touchPoint.x - centerPoint.x), (centerPoint.y - touchPoint.y)) * 0.5 / Math.PI);

    }
    //+0.5
    else if(touchPoint.x < centerPoint.x) {

        returnVal = (float) (1 - (Math.atan2((centerPoint.x - touchPoint.x), (centerPoint.y - touchPoint.y)) * 0.5 / Math.PI));

    }//End if(touchPoint.x > centerPoint.x)

    return returnVal;

}

//Измеряет диагональное расстояние между двумя точками

public float getTwoFingerDistance(final float firstTouchX, final float firstTouchY, final float secondTouchX, final float secondTouchY) {

    float pinchDistanceX = 0;
    float pinchDistanceY = 0;

    if(firstTouchX > secondTouchX) {

        pinchDistanceX = Math.abs(secondTouchX - firstTouchX);

    }
    else if(firstTouchX < secondTouchX) {

        pinchDistanceX = Math.abs(firstTouchX - secondTouchX);

    }//End if(firstTouchX > secondTouchX)

    if(firstTouchY > secondTouchY) {

        pinchDistanceY = Math.abs(secondTouchY - firstTouchY);

    }
    else if(firstTouchY < secondTouchY) {

        pinchDistanceY = Math.abs(firstTouchY - secondTouchY);

    }//End if(firstTouchY > secondTouchY)

    if(pinchDistanceX == 0 && pinchDistanceY == 0) {

        return 0;

    }
    else {

        pinchDistanceX = (pinchDistanceX * pinchDistanceX);
        pinchDistanceY = (pinchDistanceY * pinchDistanceY);
        return (float) Math.abs(Math.sqrt(pinchDistanceX + pinchDistanceY));

    }//End if(pinchDistanceX == 0 && pinchDistanceY == 0)

}

//Получим координаты XY от угла, заданного радиусом (угол выражается в коэффициенте 0-1 0, равном 0/360 градусов, а 0.75 - 270 и т.д.)

public Point getPointFromAngle(final double angle, final double radius) {

    final Point coords = new Point();
    coords.x = (int) (radius * Math.sin((angle) * 2 * Math.PI));
    coords.y = (int) -(radius * Math.cos((angle) * 2 * Math.PI));

    return coords;

}

Эти фрагменты кода из моих библиотек с открытым исходным кодом: https://bitbucket.org/warwick/hgdialrepo и https://bitbucket.org/warwick/hacergestov2. Один из них представляет собой жесты для Android, а другой - набор для Android. Существует также реализация OpenGLES 2.0 управления набором номера: https://bitbucket.org/warwick/hggldial

Ответ 10

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

Если вы не знакомы с точным определением матриц, посмотрите здесь.

Ответ 11

Я использовал Region for First, поворачивая прямоугольник, а затем использовал эту повернутую область, чтобы обнаружить этот прямоугольник

        r = new Rectangle(new Point(100, 200), new Size(200, 200));         
        Color BorderColor = Color.WhiteSmoke;
        Color FillColor = Color.FromArgb(66, 85, 67);
        int angle = 13;
        Point pt = new Point(r.X, r.Y);
        PointF rectPt = new PointF(r.Left + (r.Width / 2),
                               r.Top + (r.Height / 2));
       //declare myRegion globally 
        myRegion = new Region(r);

        // Create a transform matrix and set it to have a 13 degree

        // rotation.
        Matrix transformMatrix = new Matrix();
        transformMatrix.RotateAt(angle, pt);

        // Apply the transform to the region.
        myRegion.Transform(transformMatrix);
        g.FillRegion(Brushes.Green, myRegion);
        g.ResetTransform();

теперь, чтобы обнаружить этот прямоугольник

        private void panel_MouseMove(object sender, MouseEventArgs e)
    {


        Point point = e.Location;
        if (myRegion.IsVisible(point, _graphics))
        {
            // The point is in the region. Use an opaque brush.
            this.Cursor = Cursors.Hand;
        }
        else {
            this.Cursor = Cursors.Cross;
        }

    }