Frage

Ich habe die Koordinaten der linken oberen Punkt eines Rechtecks sowie dessen Breite, Höhe und Drehwinkel von 0 bis 180 ° und -0 -180.

Ich bin versuchen, um die bounding-Koordinaten von der aktuellen box um das Rechteck.

Was ist eine einfache Möglichkeit, die Berechnung der Koordinaten der bounding-box

  • Min y max y min x, max x?

Der A-Punkt ist nicht immer auf der min y gebunden, Sie kann überall sein.

Kann ich nutzen-matrix der Transformation toolkit in as3, wenn nötig.

War es hilfreich?

Lösung

  • Transformieren Sie die Koordinaten der vier Ecken
  • Finden Sie die kleinste von allen vier x als min_x
  • Finden Sie die größte von allen vier x und nennen es max_x
  • Dito mit der y
  • Ihre bounding-box (min_x,min_y), (min_x,max_y), (max_x,max_y), (max_x,min_y)

AFAIK, es gibt keinen Königsweg, dass Sie dort viel schneller.

Wenn Sie sich Fragen, wie eine Transformation der Koordinaten ist, versuchen Sie:

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

wobei (x0,y0) ist das Zentrum, um das Sie rotieren.Sie müssen möglicherweise Experimentieren mit dieser je nach trig-Funktionen (erwarten Sie Grad oder Bogenmaß) Sinne / Zeichen Ihrer Koordinatensystem vs.wie Sie angeben, Winkel, etc.

Andere Tipps

Ich merke, dass Sie Fragen für ActionScript, jedoch, nur in Fall, wer bekommt hier auf der Suche nach dem iOS-oder OS-X zu beantworten, ist dies:

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

    return result;
}

Wenn Ihr OS bietet, zu tun alle die harte Arbeit für Sie, lassen Sie es!:)

Swift:

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

Die beschriebene Methode von MarkusQ funktioniert perfekt, aber Bedenken Sie, dass Sie nicht brauchen, um zu verwandeln Sie die anderen drei Ecken, wenn Sie haben, zeigen Eine bereits.

Eine alternative Methode, die effizienter ist, ist zu testen, welche Quadranten, Ihr Drehwinkel ist und dann einfach berechnen Sie die Antwort direkt.Dies ist effizienter, da Sie nur ein worst-case-zwei if-Anweisungen (die überprüfung der Winkel), während der andere Ansatz ist ein worst-case-zwölf (6) für jede Komponente bei der überprüfung der anderen drei Ecken zu sehen, wenn Sie größer als die aktuelle max oder kleiner als die Strom min), denke ich.

Der grundlegende Algorithmus, der verwendet nichts anderes als eine Reihe von Anwendungen des Pythagoras' theorem, ist unten dargestellt.Ich habe bezeichnet den Winkel der Drehung von theta und drückte der Prüfung in Grad, es ist pseudo-code.

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

Dieser Ansatz setzt Voraus, dass Sie haben, was Sie sagen, Sie haben alsoPunkt A und einen Wert für theta-das liegt im Bereich [-180, 180].Ich habe auch angenommen, dass theta erhöht sich im Uhrzeigersinn, wie das ist, was das Rechteck, der gedreht wurde um 30 Grad im Diagramm erscheint, um anzuzeigen, die Sie verwenden, war ich nicht sicher, was der Teil auf der rechten Seite war versucht zu bezeichnen.Wenn dies der falsche Weg, um dann tauschen Sie Sie einfach mit der symmetrischen Klauseln und auch die Zeichen der st Begriffe.

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

wenn Sie mit GDI+ können Sie erstellen eine neue GrpaphicsPath -> Fügen Sie alle Punkte oder Formen, um Sie -> Bewerben Sie sich drehen transformation -> verwenden Sie GraphicsPath.GetBounds() und wird es wieder ein Rechteck, die Grenzen des gedrehten Form.

(edit) VB.Net Probe

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

Obwohl Code-Guru erklärte der GetBounds () - Methode, die ich bemerkt habe, ist die Frage tagged as3, flex, also hier ist ein as3-snippet, das veranschaulicht die Idee.

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

Ich bemerkte, dass es zwei Methoden, die scheinen, um die gleiche Sache:getBounds() und 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);
    }

Gelten die rotationsmatrix zu Ihrer Eckpunkte.Dann verwenden Sie die minimum - /maximum-bzw. der erhaltenen x -, y-Koordinaten definieren Sie Ihre neue bounding box.

Hier sind drei Funktionen von meine open-source-Bibliotheken.Die Funktionen sind vollständig getestet in Java, aber die Formel kann leicht übersetzt werden zu jeder Sprache.

Die Signaturen sind:

public static float getAngleFromPoint(letzten Punkt, dem Mittelpunkt, Endpunkt touchPoint)

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

Punkt getPointFromAngle(final double angle, final double radius)

Diese Lösung setzt Voraus, dass die pixel-Dichte ist gleichmäßig verteilt.Vor rotierenden die Objekt zu tun die folgenden:

  1. Verwenden getAngleFromPoint zur Berechnung der Winkel von der Mitte in der oberen rechten Ecke (können sagen, dies gibt 20 Grad), was bedeutet, dass die upp linken Ecke ist auf -20 Grad und 340 Grad.

  2. Verwenden Sie die getTwoFingerDistance Rücksendung der Diagonale Abstand zwischen dem Mittelpunkt und der oberen rechten Ecke (sollte dieser Abstand obvoiusly werden das gleiche für alle Ecken Dieser Abstand wird bei der nächsten Berechnung).

  3. Jetzt können sagen, dass wir das Objekt drehen im Uhrzeigersinn um 30 Grad.Wir wissen jetzt, dass der oberen rechten Ecke werden müssen, bei 50 Grad, und der oberen linken Ecke ist um 10 Grad.

  4. Sie sollten nun in der Lage zu verwenden die getPointFromAngle-Funktion auf der oberen linken und oberen rechten Ecke.mit dem radius kehrte aus Schritt 2.Die X-position multipliziert mit 2 von der rechten oberen Ecke sollte geben Sie die neue Breite und die Y-position mal 2 von der oberen linken Ecke geben sollte, die die neue Höhe.

Die oben genannten 4 Schritte sollten in Bedingungen, basierend auf, wie weit Sie gedreht Ihr Objekt andere Weise können Sie wieder die Höhe mit der Breite und die Breite als die Höhe.

Bare im Hinterkopf, die Winkel-Funktionen sind ausgedrückt in Faktoren von 0-1 anstelle von 0-360 (nur Multiplikation oder Division von 360 gegebenenfalls):

//Wird ein Winkel aus zwei Punkten ausgedrückt als ein Faktor 0 -1 (0 0/360, 0.25 als 90 Grad usw.)

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;

}

//Misst die Diagonale Abstand zwischen zwei Punkten

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)

}

//Holen Sie sich die XY-Koordinaten von einem Winkel aus einem gegebenen radius (Der Winkel, ausgedrückt in einem Faktor 0-1 0 0/360 Grad und 0,75 als 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;

}

Diese code-Schnipsel aus meiner open-source-Bibliotheken: https://bitbucket.org/warwick/hgdialrepo und https://bitbucket.org/warwick/hacergestov2.Ist eine Geste-Bibliothek für Android, und der andere ist ein dial-Steuerung für Android.Es ist auch eine OpenGLES 2.0-Implementierung von der Drehregler an: https://bitbucket.org/warwick/hggldial

Ich bin nicht sicher, ob ich verstehe, aber eine zusammengesetzte transformation matrix geben Sie die neuen Koordinaten für alle Punkte betrifft.Wenn Sie denken, dass das Rechteck kann überschwappen der imagable Bereich post-transformation einen Beschneidungspfad anwenden.

Im Falle Sie nicht vertraut sind mit der exakten definition der Matrizen, nehmen Sie einen Blick hier.

Ich verwendet die Region für Zunächst drehen Sie das Rechteck und dann verwenden, dass gedreht region, um zu erkennen, dass Rechteck

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

jetzt zu erkennen, dass Rechteck

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

    }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top