Pergunta

I se as coordenadas do ponto superior esquerdo de um rectângulo, bem como a sua largura, altura e rotação de 0 a 180 e -0 a -180.

Eu estou tentando obter as coordenadas delimitadora da caixa de reais à volta do rectângulo.

O que é uma maneira simples de calcular as coordenadas da caixa delimitadora

  • min y, y máximo, min x, max x?

O ponto A não é sempre no min y ligado, ele pode estar em qualquer lugar.

Eu posso usar matriz do toolkit transformar em AS3, se necessário.

Foi útil?

Solução

  • Transformar as coordenadas de todos os quatro cantos
  • Encontre o menor de todos os quatro de x como min_x
  • Encontre o maior de todos os quatro x do e chamá-lo max_x
  • Ditto com a do y
  • A caixa delimitadora é (min_x,min_y), (min_x,max_y), (max_x,max_y), (max_x,min_y)

AFAIK, não há nenhuma estrada real que você vai chegar lá muito mais rápido.

Se você está querendo saber como transformar as coordenadas, tente:

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

onde (x0, y0) é o centro em torno do qual você está girando. Você pode precisar mexer com isso dependendo de suas funções trigonométricas (que eles esperam graus ou radianos) sentido / sinal de sua coordenar vs. sistema como você está especificando ângulos, etc.

Outras dicas

Eu percebo que você está pedindo ActionScript, mas, apenas no caso de alguém se aqui procurando a resposta iOS ou OS-X, é o seguinte:

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

    return result;
}

Se suas ofertas OS para fazer todo o trabalho duro para você, deixe-o! :)

Swift:

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

O método descrito por MarkusQ funciona perfeitamente, mas tenha em mente que você não precisa para transformar os outros três cantos, se você tem o ponto A já.

Um método alternativo, que é mais eficiente, é a prova que quadrante o seu ângulo de rotação é em e em seguida, basta calcular a resposta diretamente. Isso é mais eficiente como você só tem um pior caso de dois if (verificando o ângulo), enquanto que a outra abordagem tem um pior caso de doze (6 para cada componente quando verificando os outros três cantos para ver se eles são maiores do que o atual max ou menos do que o min atual) eu acho.

O algoritmo básico, que usa nada mais do que uma série de aplicações do teorema de Pitágoras, é mostrado abaixo. Tenho indicado o ângulo de rotação por theta e expressou o cheque lá em graus como é pseudo-código.

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;
    }
}

Esta abordagem assume que você tem o que você diz que tem ou seja, o ponto A e um valor para teta que mentiras no intervalo [-180, 180]. Eu também assumiu que teta aumentos no sentido horário como é o que o retângulo que foi girada em 30 graus no seu diagrama parece indicar que você está usando, eu não tinha certeza do que a parte do lado direito estava tentando denote. Se este for o caminho errado ao redor seguida, basta trocar as cláusulas simétrica e também o sinal dos termos st.

    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];
        }

Se você estiver usando GDI +, você pode criar um novo GrpaphicsPath -> Adicionar quaisquer pontos ou formas para isso -> Aplicar transformação rotate -> uso GraphicsPath.GetBounds () e ele irá retornar um retângulo que circunda a sua forma rotacionada <. / p>

(edit) VB.Net Amostra

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

End Sub

Embora Código Guru declarou os GetBounds () método, eu tenho notado a questão é marcado as3, cabo flexível, então aqui está um trecho de AS3 que ilustra a idéia.

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);

Eu notei que há dois métodos que parecem fazer a mesma coisa: getBounds () e getRect ()

/**
     * 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);
    }

Aplicar a matriz de rotação para seus pontos de canto. Em seguida, use o mínimo / máximo, respectivamente, dos x obtidos, y coordenadas para definir sua caixa delimitadora nova.

Aqui estão três funções de minhas bibliotecas de código aberto. As funções são totalmente testados em Java, mas as fórmulas podem ser facilmente traduzido para qualquer idioma.

As assinaturas são:

public static flutuador getAngleFromPoint (Ponto Final CenterPoint, Ponto Final TouchPoint)

public static flutuador getTwoFingerDistance (flutuar firstTouchX, flutuar firstTouchY, flutuar secondTouchX, flutuador secondTouchY)

Ponto getPointFromAngle (ângulo dupla final, final de raio duplo)

Esta solução assume que a densidade de pixels é uniformemente espaçados. Antes de rodar o objeto faça o seguinte:

  1. Use getAngleFromPoint para calcular o ângulo do centro para o canto superior direito (digamos que este retorno de 20 graus) o que significa que o canto esquerdo upp é -20 graus ou 340 graus.

  2. Use o getTwoFingerDistance para voltar a distância diagonal entre o ponto central e no canto superior direito (esta distância deve obvoiusly ser o mesmo para todos os cantos, essa distância será usado no cálculo seguinte).

  3. Agora vamos dizer que girar o objeto no sentido horário em 30 graus. Sabemos agora que o canto superior direito deve ser de 50 graus e no canto superior esquerdo está a 10 graus.

  4. Agora você deve ser capaz de usar a função getPointFromAngle no canto superior esquerdo e superior direito. usando o raio devolvido a partir do passo 2. A posição X multiplicado por 2 a partir do canto superior direito deve dar-lhe a nova largura e os tempos de posição y 2 a partir do canto superior esquerdo deve dar ao a nova altura.

Estes acima de 4 etapas deve ser colocado em condições com base em quão longe você ter rodado o objeto outro sábio você pode retornar a altura como a largura ea largura como a altura.

Bare em mente as funções de ângulo são expressas em factores de 0-1, em vez de 0-360 (basta multiplicar ou dividir por 360, onde apropriado):

// Obtém um ângulo a partir de dois pontos expressos como um factor de 0 -1 (sendo 0 0/360, 0,25 sendo de 90 graus etc)

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;

}

// Mede a distância diagonal entre dois pontos

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)

}

//-se coordenadas XY de um ângulo dado um raio (O ângulo é expresso em um factor de 0-1 0 sendo 0/360 graus e 0,75 sendo 270 etc)

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;

}

Esses trechos de código são de minhas bibliotecas de código aberto: https://bitbucket.org/warwick/hgdialrepo e https://bitbucket.org/warwick/hacergestov2 . Um deles é uma biblioteca gesto para Android e o outro é um controle de discagem para Android. Há também uma implementação OpenGLES 2.0 do controlo de ligação em: https://bitbucket.org/warwick/hggldial

Eu não tenho certeza eu entendo, mas uma matriz de transformação composto vai lhe dar as novas coordenadas para todos os pontos em causa. Se você acha que o retângulo pode derramar sobre a área pós transformação imagable aplicar um caminho de recorte.

No caso de você não estiver familiarizado com a definição exata das matrizes dar uma olhada aqui .

Eu costumava Região para a primeira rotação do retângulo e, em seguida, usar essa região girada para detectar esse retângulo

        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();

Agora, para detectar que retângulo

        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;
        }

    }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top