Ich habe die Koordinaten des oberen linken Punktes eines Rechtecks sowie dessen Breite, Höhe und Drehung von 0 bis 180 und -0 bis -180.
Ich versuche, die Begrenzungskoordinaten der tatsächlichen Box um das Rechteck zu erhalten.
Was ist eine einfache Methode zur Berechnung der Koordinaten des Begrenzungsrahmens?
- Min y, max y, min x, max x?
Der A-Punkt ist nicht immer auf der Min-Grenze, er kann überall sein.
Bei Bedarf kann ich das Transformations-Toolkit in as3 als Matrix verwenden.
Antworten:
min_x
max_x
(min_x,min_y), (min_x,max_y), (max_x,max_y), (max_x,min_y)
AFAIK, es gibt keine königliche Straße, die Sie viel schneller dorthin bringt.
Wenn Sie sich fragen, wie Sie die Koordinaten transformieren sollen, versuchen Sie Folgendes:
x2 = x0+(x-x0)*cos(theta)+(y-y0)*sin(theta) y2 = y0-(x-x0)*sin(theta)+(y-y0)*cos(theta)
Dabei ist (x0, y0) das Zentrum, um das Sie sich drehen. Abhängig von Ihren Triggerfunktionen (erwarten sie Grad oder Bogenmaß) müssen Sie möglicherweise den Sinn / das Vorzeichen Ihres Koordinatensystems im Vergleich zur Angabe von Winkeln usw. basteln.
quelle
Mir ist klar, dass Sie nach ActionScript fragen, aber für den Fall, dass jemand hier nach der Antwort für iOS oder OS-X sucht, ist dies:
+ (CGRect) boundingRectAfterRotatingRect: (CGRect) rect toAngle: (float) radians { CGAffineTransform xfrm = CGAffineTransformMakeRotation(radians); CGRect result = CGRectApplyAffineTransform (rect, xfrm); return result; }
Wenn Ihr Betriebssystem anbietet, die ganze harte Arbeit für Sie zu erledigen, lassen Sie es! :) :)
Schnell:
func boundingRectAfterRotatingRect(rect: CGRect, toAngle radians: CGFloat) -> CGRect { let xfrm = CGAffineTransformMakeRotation(radians) return CGRectApplyAffineTransform (rect, xfrm) }
quelle
Die von MarkusQ beschriebene Methode funktioniert einwandfrei. Beachten Sie jedoch, dass Sie die anderen drei Ecken nicht transformieren müssen, wenn Sie bereits Punkt A haben.
Eine alternative Methode, die effizienter ist, besteht darin, zu testen, in welchem Quadranten sich Ihr Drehwinkel befindet, und dann einfach die Antwort direkt zu berechnen. Dies ist effizienter, da Sie nur den schlechtesten Fall von zwei if-Anweisungen haben (Überprüfen des Winkels), während der andere Ansatz den schlechtesten Fall von zwölf hat (6 für jede Komponente, wenn Sie die anderen drei Ecken überprüfen, um festzustellen, ob sie größer als der Strom sind max oder weniger als die aktuelle min) denke ich.
Der grundlegende Algorithmus, der nur eine Reihe von Anwendungen des Satzes von Pythagoras verwendet, ist unten dargestellt. Ich habe den Drehwinkel mit Theta bezeichnet und die Prüfung dort in Grad als Pseudocode ausgedrückt.
ct = cos( theta ); st = sin( theta ); hct = h * ct; wct = w * ct; hst = h * st; wst = w * st; if ( theta > 0 ) { if ( theta < 90 degrees ) { // 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; } }
Bei diesem Ansatz wird davon ausgegangen, dass Sie das haben, was Sie sagen, dh Punkt A und einen Wert für Theta, der im Bereich [-180, 180] liegt. Ich habe auch angenommen, dass Theta im Uhrzeigersinn zunimmt, da das Rechteck, das in Ihrem Diagramm um 30 Grad gedreht wurde, darauf hinweist, dass Sie es verwenden. Ich war mir nicht sicher, was der Teil rechts zu bezeichnen versuchte. Wenn dies falsch herum ist, tauschen Sie einfach die symmetrischen Klauseln und auch das Vorzeichen der st-Begriffe aus.
quelle
theta
es sich eindeutig nicht um Abschlüsse handelt. Es dient als Erinnerung bei der Implementierung des richtigen Arbeitscodes, um die Winkeleinheiten korrekt zu machen.if (theta > 0 degrees)
undif (theta > -90 degrees)
so , dass sie im Einklang steht. Die Inkonsistenz fordert die Benutzer auf, sie zu bearbeiten.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]; }
quelle
Wenn Sie GDI + verwenden, können Sie einen neuen GrpaphicsPath erstellen -> Punkte oder Formen hinzufügen -> Rotationstransformation anwenden -> GraphicsPath.GetBounds () verwenden und ein Rechteck zurückgeben, das Ihre gedrehte Form begrenzt.
(bearbeiten) VB.Net-Beispiel
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
quelle
Obwohl Code Guru die GetBounds () -Methode angegeben hat, ist mir aufgefallen, dass die Frage als 3, flex markiert ist. Hier ist ein as3-Snippet, das die Idee veranschaulicht.
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);
Mir ist aufgefallen, dass es zwei Methoden gibt, die dasselbe zu tun scheinen: getBounds () und getRect ()
quelle
/** * 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); }
quelle
Wenden Sie die Rotationsmatrix auf Ihre Eckpunkte an. Verwenden Sie dann das Minimum / Maximum der erhaltenen x, y-Koordinaten, um Ihren neuen Begrenzungsrahmen zu definieren.
quelle
Hier sind drei Funktionen aus meinen Open Source-Bibliotheken. Die Funktionen sind vollständig in Java getestet, aber die Formeln können leicht in jede Sprache übersetzt werden.
Die Unterschriften sind:
public static float getAngleFromPoint (Endpunkt centerPoint, Endpunkt touchPoint)
public static float getTwoFingerDistance (float firstTouchX, float firstTouchY, float secondTouchX, float secondTouchY)
Punkt getPointFromAngle (endgültiger Doppelwinkel, endgültiger Doppelradius)
Diese Lösung setzt voraus, dass die Pixeldichte gleichmäßig verteilt ist. Gehen Sie vor dem Drehen des Objekts wie folgt vor:
Verwenden Sie getAngleFromPoint, um den Winkel von der Mitte zur oberen rechten Ecke zu berechnen (sagen wir, dies ergibt 20 Grad), was bedeutet, dass die obere linke Ecke -20 Grad oder 340 Grad beträgt.
Verwenden Sie getTwoFingerDistance, um den diagonalen Abstand zwischen dem Mittelpunkt und der oberen rechten Ecke zurückzugeben (dieser Abstand sollte offensichtlich für alle Ecken gleich sein. Dieser Abstand wird in der nächsten Berechnung verwendet).
Nehmen wir nun an, wir drehen das Objekt um 30 Grad im Uhrzeigersinn. Wir wissen jetzt, dass die obere rechte Ecke bei 50 Grad und die obere linke Ecke bei 10 Grad sein muss.
Sie sollten jetzt in der Lage sein, die Funktion getPointFromAngle in der oberen linken und oberen rechten Ecke zu verwenden. Verwenden Sie den aus Schritt 2 zurückgegebenen Radius. Die X-Position multipliziert mit 2 aus der oberen rechten Ecke sollte die neue Breite ergeben, und die Y-Position mal 2 aus der oberen linken Ecke sollte die neue Höhe ergeben.
Diese obigen 4 Schritte sollten in Bedingungen versetzt werden, die davon abhängen, wie weit Sie Ihr Objekt gedreht haben. Andernfalls können Sie die Höhe als Breite und die Breite als Höhe zurückgeben.
Beachten Sie jedoch, dass die Winkelfunktionen in Faktoren von 0-1 anstelle von 0-360 ausgedrückt werden (multiplizieren oder dividieren Sie sie gegebenenfalls durch 360):
// Ruft einen Winkel von zwei Punkten ab, ausgedrückt als Faktor 0 -1 (0 ist 0/360, 0,25 ist 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 den diagonalen 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) }
// XY-Koordinaten aus einem Winkel mit einem bestimmten Radius abrufen (Der Winkel wird in einem Faktor von 0-1 0 ausgedrückt, der 0/360 Grad und 0,75 ist, 270 usw.)
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 Codefragmente stammen aus meinen Open Source-Bibliotheken: https://bitbucket.org/warwick/hgdialrepo und https://bitbucket.org/warwick/hacergestov2 . Eine ist eine Gestenbibliothek für Android und die andere ist eine Wählsteuerung für Android. Es gibt auch eine OpenGLES 2.0-Implementierung der Wählsteuerung unter: https://bitbucket.org/warwick/hggldial
quelle
Ich bin nicht sicher, ob ich das verstehe, aber eine zusammengesetzte Transformationsmatrix gibt Ihnen die neuen Koordinaten für alle betroffenen Punkte. Wenn Sie der Meinung sind, dass das Rechteck nach der Transformation über den vorstellbaren Bereich hinausläuft, wenden Sie einen Beschneidungspfad an.
Falls Sie mit der genauen Definition der Matrizen nicht vertraut sind, schauen Sie hier .
quelle
Ich habe Region verwendet, um zuerst das Rechteck zu drehen, und dann diesen gedrehten Bereich, um dieses Rechteck zu erkennen
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();
Nun zum Erkennen dieses Rechtecks
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; } }
quelle