Oblicz współrzędne obwiedni na podstawie obróconego prostokąta

Mam współrzędne lewego górnego punktu prostokąta oraz jego szerokość, wysokość i obrót od 0 do 180 i od -0 do -180.

Próbuję uzyskać współrzędne obwiedni rzeczywistego pola wokół prostokąta.

Jaki jest prosty sposób obliczania współrzędnych obwiedni

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

Punkt A nie zawsze znajduje się na granicy min y, może być wszędzie.

I can use matrix the transform toolkit w razie potrzeby w as3.

Author: Peter O., 2009-03-07

11 answers

  • Przekształć współrzędne wszystkich czterech narożników
  • Znajdź najmniejszy ze wszystkich czterech x jako min_x
  • Znajdź największy ze wszystkich czterech x i nazwij go max_x
  • Ditto z y
  • Twoja Obwiednia to (min_x,min_y), (min_x,max_y), (max_x,max_y), (max_x,min_y)
AFAIK, nie ma żadnej królewskiej drogi, która doprowadzi cię tam szybciej.

Jeśli zastanawiasz się, jak przekształcić współrzędne, spróbuj:

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

Gdzie (x0,y0) jest środkiem, wokół którego się obracasz. Możesz potrzebować majstrować z tym w zależności od funkcji Tryg (czy oczekują stopni lub radianów) sens / znak twojego układu współrzędnych vs. jak określasz kąty, itp.

 70
Author: MarkusQ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-07 17:25:42

Zdaję sobie sprawę, że prosisz o ActionScript, ale na wszelki wypadek, gdyby ktoś tu przyszedł, szukając odpowiedzi na iOS lub OS-X, jest to:

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

    return result;
}

Jeśli twój OS oferuje wykonać całą ciężką pracę dla Ciebie, niech to! :)

Swift:

func boundingRectAfterRotatingRect(rect: CGRect, toAngle radians: CGFloat) -> CGRect {
    let xfrm = CGAffineTransformMakeRotation(radians)
    return CGRectApplyAffineTransform (rect, xfrm)
}
 23
Author: Olie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-05 17:19:56

Metoda opisana przez MarkusQ działa doskonale, ale pamiętaj, że nie musisz przekształcać pozostałych trzech narożników, jeśli masz już punkt A.

Alternatywną metodą, która jest bardziej efektywna, jest sprawdzenie, w którym kwadrancie znajduje się twój kąt obrotu, a następnie po prostu Oblicz odpowiedź bezpośrednio. Jest to bardziej efektywne, ponieważ masz tylko najgorszy przypadek dwóch twierdzeń if (sprawdzanie kąta), podczas gdy inne podejście ma najgorszy przypadek dwunastu (6 dla każdego składnika podczas sprawdzania pozostałe trzy rogi, aby zobaczyć, czy są one większe niż prąd max lub mniej niż prąd min) myślę.

Poniżej przedstawiono podstawowy algorytm, który wykorzystuje jedynie szereg zastosowań twierdzenia Pitagorasa. Oznaczyłem kąt obrotu przez theta i wyraziłem tam czek w stopniach, jak to pseudo-kod.
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;
    }
}

To podejście zakłada, że masz to, co mówisz, że masz, tj. punkt A i wartość dla theta, która leży w przedziale [-180, 180]. Ja też zakładając, że zwiększa się theta w kierunku zgodnym z ruchem wskazówek zegara, ponieważ prostokąt, który został obrócony o 30 stopni na diagramie, wydaje się wskazywać, że używasz, nie byłem pewien, co część po prawej stronie próbuje oznaczać. Jeśli jest to niewłaściwy sposób, to po prostu zamień klauzule symetryczne, a także znak terminów st.

 8
Author: Troubadour,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-17 20:29:42
    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];
        }
 6
Author: bajie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-06 02:38:49

Jeśli używasz GDI+, możesz utworzyć nową ścieżkę GrpaphicsPath - > Dodaj do niej dowolne punkty lub kształty - > Zastosuj transformację rotate - > użyj GraphicsPath.GetBounds() i zwróci prostokąt ograniczający obrócony kształt.

[edytuj] VB.Net próbka

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

 3
Author: Bishoy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-02 20:12:42

Chociaż Code Guru stwierdził metodę GetBounds (), zauważyłem, że pytanie jest oznaczone jako as3, flex, więc tutaj jest fragment as3, który ilustruje pomysł.

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

Zauważyłem, że istnieją dwie metody, które wydają się robić to samo: getBounds () i getRect ()

 2
Author: George Profenza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-18 00:30:43
/**
     * 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);
    }
 2
Author: Nick Bilyk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-20 21:02:01

Zastosuj matrycę obrotu do punktów narożnych. Następnie użyj odpowiednio minimum / maksimum uzyskanych współrzędnych x,y, aby zdefiniować nową obwiednię.

 1
Author: ypnos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-07 17:19:45

Oto trzy funkcje z moich bibliotek open source. Funkcje są w pełni testowane w Javie, ale wzory można łatwo przetłumaczyć na dowolny język.

Podpisy to:

Public static float getAngleFromPoint (final Point centerPoint, final Point touchPoint)

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

Point getPointFromAngle(final double angle, final double radius)

To rozwiązanie zakłada, że gęstość pikseli jest równomiernie rozłożona. Przed obróceniem obiektu wykonaj następujące czynności:

  1. Użyj getAngleFromPoint, aby Obliczyć Kąt od środka do prawego górnego rogu (powiedzmy, że zwraca 20 stopni), co oznacza, że lewy róg upp wynosi -20 stopni lub 340 stopni.

  2. Użyj getTwoFingerDistance, aby zwrócić odległość po przekątnej między punktem środkowym a prawym górnym rogu (odległość ta powinna oczywiście będzie taka sama dla wszystkich zakrętów, odległość ta zostanie wykorzystana w następnym obliczeniu).

  3. Teraz powiedzmy, że obrócimy obiekt zgodnie z ruchem wskazówek zegara o 30 stopni. Teraz wiemy, że w prawym górnym rogu musi być 50 stopni, a w lewym górnym rogu 10 stopni.

  4. Powinieneś teraz móc korzystać z funkcji getPointFromAngle w lewym górnym rogu i prawym górnym rogu. używając promienia zwróconego z kroku 2. Pozycja X pomnożona przez 2 od prawego górnego rogu narożnik powinien dać nową szerokość, a czasy pozycji Y 2 od lewego górnego rogu powinny dać nową wysokość.

Powyższe 4 kroki powinny być wprowadzone do warunków w zależności od tego, jak daleko obróciłeś swój obiekt, innym razem możesz zwrócić wysokość jako szerokość, a szerokość jako wysokość.

Mając na uwadze, że funkcje kątowe są wyrażane współczynnikami 0-1 zamiast 0-360 (wystarczy pomnożyć lub podzielić przez 360 w stosownych przypadkach):

/ / dostaje kąt z dwóch punktów wyrażonych jako współczynnik 0 -1 (0 to 0/360, 0,25 to 90 stopni itd.)

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;

}

//mierzy odległość diagonalną między dwoma punktami

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)

}

//uzyskaj współrzędne XY z kąta podanego promienia (kąt jest wyrażony we współczynniku 0-1 0 to 0/360 stopni i 0,75 to 270 itd.)

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;

}

Te fragmenty kodu pochodzą z moich bibliotek open source: https://bitbucket.org/warwick/hgdialrepo i https://bitbucket.org/warwick/hacergestov2 . Jednym z nich jest biblioteka gestów dla Androida, a drugi to sterowanie wybierania dla Androida. Istnieje również implementacja OpenGLES 2.0 kontrolki wybierania pod adresem: https://bitbucket.org/warwick/hggldial

 1
Author: user2288580,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-10 00:28:12

Nie jestem pewien, czy rozumiem, ale macierz transformacji złożonej da ci nowe Współrzędne dla wszystkich punktów. Jeśli uważasz, że prostokąt może rozlać się na obrazowalny obszar po transformacji, zastosuj ścieżkę przycinającą.

Jeśli nie jesteś zaznajomiony z dokładną definicją macierzy, zajrzyj TUTAJ .

 0
Author: dirkgently,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-07 17:12:55

Najpierw obróciłem prostokąt, a następnie użyłem obróconego obszaru, aby wykryć ten prostokąt

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

Teraz do wykrywania tego prostokąta

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

    }
 0
Author: Abdulrehman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-27 10:04:46