문제

사각형의 상단 왼쪽 지점의 좌표와 폭, 높이 및 회전은 0에서 180 및 -0 ~ -180입니다.

사각형 주위에 실제 상자의 경계 좌표를 얻으려고 노력하고 있습니다.

경계 박스의 좌표를 계산하는 간단한 방법은 무엇입니까?

  • Min Y, Max Y, Min X, Max X?

요점은 항상 최소에있는 것은 아니며 어디에나있을 수 있습니다.

필요한 경우 AS3의 Matrix The Transform 툴킷을 사용할 수 있습니다.

도움이 되었습니까?

해결책

  • 네 모서리 모두의 좌표를 변형시킵니다
  • 4 개의 X 중 가장 작은 것을 찾으십시오 min_x
  • 4 개의 X 중 가장 큰 것을 찾고 전화하십시오. max_x
  • Y와 함께
  • 당신의 경계 상자입니다 (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)은 회전하는 중심입니다. 트리그 함수 (도 또는 라디안을 기대합니까)에 따라 좌표계의 감각 / 부호 대 각도를 지정하는 방법 등에 따라 이에 따라 땜질해야 할 수도 있습니다.

다른 팁

나는 당신이 ActionScript를 요구한다는 것을 알고 있지만, 누군가가 iOS 또는 OS-X 답변을 찾는 사람이라면 다음과 같습니다.

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

    return result;
}

당신의 OS가 당신을 위해 모든 노력을 기울이겠다고 제안한다면, 그것을 보내십시오! :)

빠른:

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

Markusq가 설명한 방법은 완벽하게 작동하지만 포인트 A가 있으면 다른 세 모서리를 변환 할 필요가 없다는 것을 명심하십시오.

더 효율적인 대체 방법은 회전 각도가 어떤 사분면에 있는지 테스트 한 다음 간단히 답을 계산하는 것입니다. 이것은 최악의 경우 최악의 경우 IF 문 (각도 점검) 만있는 반면 다른 접근법은 12 개의 최악의 경우 (다른 세 모서리가 현재보다 더 큰지 확인할 때 각 구성 요소에 대해 6 개에 대해 6 개)를 가지고 있기 때문에 더 효율적입니다. 현재 최소보다 최대 또는 작습니다) 나는 생각합니다.

피타고라스 정리의 일련의 응용 프로그램 만 사용하는 기본 알고리즘은 다음과 같습니다. 나는 Theta의 회전 각도를 표시하고 의사 코드 인 정도로 검사를 각도로 표현했습니다.

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

이 접근법은 당신이 당신이 당신이 당신이 당신이 당신의 IE 지점 A를 가지고 있다고 가정하고 [-180, 180] 범위에있는 theta의 값이 있다고 가정합니다. 나는 또한 시계 방향으로 증가한다고 가정했다. 그것이 당신의 다이어그램에서 30도 씩 회전 한 사각형이 당신이 사용하고 있음을 나타내는 것처럼 보이기 때문에, 나는 오른쪽의 부품이 무엇을 나타내려고했는지 확신하지 못했다. 이것이 잘못된 길이라면 대칭 조항과 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];
        }

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

종료 서브

Code Guru는 GetBounds () 메소드를 언급했지만 질문이 AS3, 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 ()

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

회전 매트릭스를 코너 포인트에 적용하십시오. 그런 다음 얻은 x, y 좌표의 최소/최대 값을 사용하여 새 경계 박스를 정의하십시오.

다음은 오픈 소스 라이브러리의 세 가지 기능입니다. 기능은 Java에서 완전히 테스트되지만 공식은 모든 언어로 쉽게 번역 될 수 있습니다.

서명은 다음과 같습니다.

public static float getanglefrompoint (최종 포인트 센터 포인트, 최종 포인트 터치 포인트)

public static float gettwofingerdistance (float firsttouchx, float firsttouchy, float secondtouchx, float secondTouchy)

Point GetPointFromangle (최종 이중 각도, 최종 이중 반경)

이 용액은 픽셀 밀도가 균등 한 간격이라고 가정합니다. 물체를 회전시키기 전에 다음을 수행합니다.

  1. getanglefrompoint를 사용하여 중앙에서 오른쪽 상단 모서리까지 각도를 계산하십시오 (이로 인해 20도 반환이라고 함)는 UPP 왼쪽 모서리가 -20도 또는 340도임을 의미합니다.

  2. gettwofingerdistance를 사용하여 중심 지점과 오른쪽 상단의 대각선 거리를 반환합니다 (이 거리는 모든 모서리와 동일해야합니다.이 거리는 다음 계산에 사용됩니다).

  3. 이제 물체를 시계 방향으로 30도 회전한다고 가정 해 봅시다. 우리는 이제 오른쪽 상단 모서리가 50도이어야하고 왼쪽 상단 모서리는 10도에 있습니다.

  4. 이제 왼쪽 상단과 오른쪽 상단의 getpointfromangle 함수를 사용할 수 있어야합니다. 2 단계에서 돌아온 반경을 사용하여 X 위치는 오른쪽 상단에서 2를 곱한 X 위치에 새 너비를 제공하고 왼쪽 상단의 y 위치 시간 2는 새 높이를 제공해야합니다.

이 4 단계 이상은 물체를 얼마나 멀리 회전했는지에 따라 조건에 넣어야합니다.

각도 함수는 0-360 대신 0-1의 계수로 표현됩니다 (적절한 경우 360을 곱하거나 나누는 것) :

// 0 -1의 계수로 표현 된 두 지점에서 각도를 가져옵니다 (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/360 도인 0-1 0이고 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. 하나는 안드로이드를위한 제스처 라이브러리이고 다른 하나는 안드로이드의 다이얼 컨트롤입니다. 다이얼 컨트롤의 Opengles 2.0 구현도 다음과 같습니다. https://bitbucket.org/warwick/hggldial

나는 내가 이해하지 못하지만, 복합 변환 매트릭스는 당신에게 관련된 모든 지점에 대한 새로운 좌표를 줄 것입니다. 직사각형이 Imagable 영역에 쏟아 질 수 있다고 생각되면 변환 후 클리핑 경로를 적용하십시오.

행렬의 정확한 정의에 익숙하지 않은 경우 여기.

먼저 사각형을 회전시키는 데 영역을 사용한 다음 회전 된 영역을 사용하여 해당 사각형을 감지했습니다.

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

    }
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top