从旋转的矩形计算边界框坐标

发布于 2024-07-15 02:58:28 字数 232 浏览 9 评论 0原文

我有一个矩形左上角的坐标以及它的宽度、高度和旋转角度(0 到 180 和 -0 到 -180)。

我试图获取矩形周围实际框的边界坐标。

计算边界框

  • Min y、max y、min x、max x 坐标的简单方法是什么?

A 点并不总是在最小 y 边界上,它可以在任何地方。

如果需要的话,我可以使用 as3 中的矩阵转换工具包。

I have the coordinates of the top left point of a rectangle as well as its width, height and rotation from 0 to 180 and -0 to -180.

I am trying to get the bounding coordinates of the actual box around the rectangle.

What is a simple way of calculating the coordinates of the bounding box

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

The A point is not always on the min y bound, it can be anywhere.

I can use matrix the transform toolkit in as3 if needed.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

落墨 2024-07-22 02:58:29

我使用“区域”首先旋转矩形,然后使用该旋转区域来检测该矩形,

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

    }

I used Region for First rotating the rectangle and then use that rotated region to detect that rectangle

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

now to detecting that rectangle

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

    }
撑一把青伞 2024-07-22 02:58:28
  • 变换所有四个角的坐标
  • 找到所有四个 x 中最小的 min_x
  • 找到所有四个 x 中最大的并称之为 max_x
  • 与 y 相同
  • 您的边界框是 < code>(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) 是您旋转的中心。 您可能需要根据您的三角函数(它们是否期望度数或弧度)、坐标系的意义/符号与您指定角度的方式等进行修改。

  • Transform the coordinates of all four corners
  • Find the smallest of all four x's as min_x
  • Find the largest of all four x's and call it max_x
  • Ditto with the y's
  • Your bounding box is (min_x,min_y), (min_x,max_y), (max_x,max_y), (max_x,min_y)

AFAIK, there isn't any royal road that will get you there much faster.

If you are wondering how to transform the coordinates, try:

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

where (x0,y0) is the center around which you are rotating. You may need to tinker with this depending on your trig functions (do they expect degrees or radians) the sense / sign of your coordinate system vs. how you are specifying angles, etc.

葬花如无物 2024-07-22 02:58:28

我知道您要求的是 ActionScript,但是,以防万一有人来这里寻找 iOS 或 OS-X 答案,那就是:

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

    return result;
}

如果您的操作系统愿意为您完成所有艰苦的工作,那就让它吧! :)

斯威夫特:

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

I realize that you're asking for ActionScript but, just in case anyone gets here looking for the iOS or OS-X answer, it is this:

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

    return result;
}

If your OS offers to do all the hard work for you, let it! :)

Swift:

func boundingRectAfterRotatingRect(rect: CGRect, toAngle radians: CGFloat) -> CGRect {
    let xfrm = CGAffineTransformMakeRotation(radians)
    return CGRectApplyAffineTransform (rect, xfrm)
}
爱本泡沫多脆弱 2024-07-22 02:58:28

MarkusQ 概述的方法非常有效,但请记住,如果您已经有了 A 点,则无需变换其他三个角。

另一种更有效的方法是测试您的旋转角度位于哪个象限,然后直接计算答案。 这是更有效的,因为最坏的情况只有两个 if 语句(检查角度),而另一种方法最坏的情况有 12 个(检查其他三个角以查看它们是否大于当前角时,每个组件有 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 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;
    }
}

此方法假设您拥有您所说的内容,即 A 点和位于 [-180, 180] 范围内的 theta 值。 我还假设 theta 沿顺时针方向增加,因为这就是图中旋转 30 度的矩形似乎表明您正在使用的,我不确定右侧的部分试图表示什么。 如果这是错误的方法,那么只需交换对称子句以及 st 项的符号即可。

The method outlined by MarkusQ works perfectly but bear in mind that you don't need to transform the other three corners if you have point A already.

An alternative method, which is more efficient, is to test which quadrant your rotation angle is in and then simply compute the answer directly. This is more efficient as you only have a worst case of two if statements (checking the angle) whereas the other approach has a worst case of twelve (6 for each component when checking the other three corners to see if they are greater than the current max or less than the current min) I think.

The basic algorithm, which uses nothing more than a series of applications of Pythagoras' theorem, is shown below. I have denoted the rotation angle by theta and expressed the check there in degrees as it's 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 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;
    }
}

This approach assumes that you have what you say you have i.e. point A and a value for theta that lies in the range [-180, 180]. I've also assumed that theta increases in the clockwise direction as that's what the rectangle that has been rotated by 30 degrees in your diagram seems to indicate you are using, I wasn't sure what the part on the right was trying to denote. If this is the wrong way around then just swap the symmetric clauses and also the sign of the st terms.

这样的小城市 2024-07-22 02:58:28
    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];
        }
    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];
        }
高跟鞋的旋律 2024-07-22 02:58:28

如果您使用的是 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

结束子

if you are using GDI+ , you can create a new GrpaphicsPath -> Add any points or shapes to it -> Apply rotate transformation -> use GraphicsPath.GetBounds() and it will return a rectangle that bounds your rotated shape.

(edit) VB.Net Sample

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

无妨# 2024-07-22 02:58:28

当矩形绕其中心旋转时,计算很简单:

function getBoundingBox(rX, rY, rW, rH, rA) {
  const absCosRA = Math.abs(Math.cos(rA));
  const absSinRA = Math.abs(Math.sin(rA));

  const bbW = rW * absCosRA + rH * absSinRA;
  const bbH = rW * absSinRA + rH * absCosRA;
  
  const bbX = rX - (bbW - rW) / 2;
  const bbY = rY - (bbH - rH) / 2;

  return { x: bbX, y: bbY, w: bbW, h: bbH };
}

When the rectangle is rotated around its center, the calculation is trivial:

function getBoundingBox(rX, rY, rW, rH, rA) {
  const absCosRA = Math.abs(Math.cos(rA));
  const absSinRA = Math.abs(Math.sin(rA));

  const bbW = rW * absCosRA + rH * absSinRA;
  const bbH = rW * absSinRA + rH * absCosRA;
  
  const bbX = rX - (bbW - rW) / 2;
  const bbY = rY - (bbH - rH) / 2;

  return { x: bbX, y: bbY, w: bbW, h: bbH };
}
天赋异禀 2024-07-22 02:58:28

尽管 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()

Although Code Guru stated the GetBounds() method, I've noticed the question is tagged as3, flex, so here is an as3 snippet that illustrates the idea.

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

I noticed that there two methods that seem to do the same thing: getBounds() and getRect()

两仪 2024-07-22 02:58:28
/**
     * 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);
    }
/**
     * 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);
    }
扮仙女 2024-07-22 02:58:28

将旋转矩阵应用于角点。 然后分别使用获得的 x,y 坐标的最小值/最大值来定义新的边界框。

Apply the rotation matrix to your corner points. Then use the minimum/maximum respectively of the obtained x,y coordinates to define your new bounding box.

零度° 2024-07-22 02:58:28

以下是我的开源库中的三个函数。 这些函数在 Java 中经过全面测试,但公式可以轻松翻译为任何语言。

签名为:

public static float getAngleFromPoint(final Point centerPoint, Final Point touchPoint)

public static float getTwoFingerDistance(float firstTouchX, float firstTouchY, float secondaryTouchX, float secondaryTouchY)

Point getPointFromAngle(final double angle, final double radius)

该解决方案假设像素密度均匀分布。
在旋转对象之前,请执行以下操作:

  1. 使用 getAngleFromPoint 计算从中心到右上角的角度(假设返回 20 度),这意味着左上角为 -20 度或 340 度。

  2. 使用 getTwoFingerDistance 返回中心点到右上角的对角距离(这个距离显然应该是所有角都相同,这个距离将在接下来的计算中使用)。

  3. 现在假设我们将对象顺时针旋转 30 度。 我们现在知道右上角必须为 50 度,左上角必须为 10 度。

  4. 您现在应该能够在左上角和右上角使用 getPointFromAngle 函数。 使用步骤 2 返回的半径。
    X 位置从右上角乘以 2 应该给出新的宽度,Y 位置从左上角乘以 2 应该给出新高度。

上述 4 个步骤应根据您旋转对象的距离设置条件,否则您可能会返回高度作为宽度,将宽度作为高度返回。

请记住,角度函数以 0-1 的因子表示,而不是 0-360(只需在适当的情况下乘以或除以 360):

//从两点获取角度,表示为 0 -1 的因子(0 为 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-1 的系数表示,0 为 0/360 度,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
一个是 Android 的手势库,另一个是 Android 的拨号控件。 还有拨号控件的 OpenGLES 2.0 实现:https://bitbucket.org/warwick/hggldial

Here are three functions from my open source libraries. The functions are fully tested in Java but the formulae can be easily translated to any language.

The signatures are:

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)

This solution assumes that the pixel density is evenly spaced.
Before rotating the object do the following:

  1. Use getAngleFromPoint to calculate the angle from the center to the upper right corner (lets say this returns 20 degrees) meaning that the upp left corner is -20 degrees or 340 degrees.

  2. Use the getTwoFingerDistance to return the diagonal distance between the center point and the upper right corner (this distance should obvoiusly be the same to all corners, This distance will be used in the next calculation).

  3. Now lets say we rotate the object clockwise by 30 degrees. We now know that the upper right corner must be at 50 degrees and the upper left corner is at 10 degrees.

  4. You should now be able to use the getPointFromAngle function on the upper left and upper right corner. using the radius returned from step 2.
    The X position multiplied by 2 from the upper right corner should give you the new width and the Y position times 2 from the upper left corner should give the the new height.

These above 4 steps should be put into conditions based upon how far you have rotated your object other wise you may return the height as the width and the width as the height.

Bare in mind the angle functions are expressed in factors of 0-1 instead of 0-360 (just multiply or divide by 360 where appropriate):

//Gets an angle from two points expressed as a factor of 0 -1 (0 being 0/360, 0.25 being 90 degrees 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;

}

//Measures the diagonal distance between two points

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)

}

//Get XY coordinates from an angle given a radius (The angle is expressed in a factor of 0-1 0 being 0/360 degrees and 0.75 being 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;

}

These code snippets are from my open source libraries: https://bitbucket.org/warwick/hgdialrepo and https://bitbucket.org/warwick/hacergestov2.
One is a gesture library for Android and the other is a dial control for Android. There is also an OpenGLES 2.0 implementation of the dial control at: https://bitbucket.org/warwick/hggldial

童话 2024-07-22 02:58:28

我不确定我是否理解,但是复合变换矩阵将为您提供所有相关点的新坐标。 如果您认为矩形可能会在变换后溢出可成像区域,请应用剪切路径。

如果您不熟悉矩阵的确切定义,请查看此处

I am not sure I understand, but a compound transformation matrix will give you the new co-ordinates for all points concerned. If you think the rectangle may spill over the imagable area post transformation apply a clipping path.

In case you are unfamiliar with the exact definition of the matrices take a look here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文