检查点是否位于旋转矩形(C#)中

检查点是否位于旋转矩形(C#)中,c#,winforms,math,graphics,geometry,C#,Winforms,Math,Graphics,Geometry,我有一个C#(Windows窗体)程序,它在一个画框上画一些矩形。它们也可以以一定角度绘制(旋转) 我知道每个矩形的起点(左上角)、大小(宽度+高度)和角度。由于旋转,起点不必位于左上角,但这在这里并不重要。 然后,当我单击picturebox时,我需要检查我单击了哪个矩形(如果有) 所以我需要一些方法来检查一个点是否在一个矩形中,但是我还需要考虑每个矩形的旋转。 有人知道在C#中实现这一点的方法吗?你可以保留第二张未展开的图像,在那里你可以绘制矩形的副本,每个矩形都有独特的颜色。当用户单击pi

我有一个C#(Windows窗体)程序,它在一个画框上画一些矩形。它们也可以以一定角度绘制(旋转)

我知道每个矩形的起点(左上角)、大小(宽度+高度)和角度。由于旋转,起点不必位于左上角,但这在这里并不重要。 然后,当我单击picturebox时,我需要检查我单击了哪个矩形(如果有)

所以我需要一些方法来检查一个点是否在一个矩形中,但是我还需要考虑每个矩形的旋转。
有人知道在C#中实现这一点的方法吗?

你可以保留第二张未展开的图像,在那里你可以绘制矩形的副本,每个矩形都有独特的颜色。当用户单击picturebox时,在第二幅图像中找到相应像素的颜色,这将确定单击了哪个矩形。

是否可以将应用于矩形的相同旋转反向应用于点


例如,将矩形A从原点(左上角)顺时针旋转45度,然后将点B绕同一原点逆时针旋转45度,然后检查它是否在矩形A内旋转前

是否允许矩形重叠?
如果是这样的话,您是希望所有的矩形都在一个点上,还是只希望顶层的矩形?

我知道这个问题已经得到了回答,但不久前我不得不做一些类似的事情。我为System.Windows.Point类创建了一个扩展方法,该方法完全符合Neil的建议:

    public static double GetAngle(this Point pt)
    {
        return Math.Atan2(pt.X, -pt.Y) * 180 / Math.PI;
    }

    public static Point SetAngle(this Point pt, double angle)
    {
        var rads = angle * (Math.PI / 180);
        var dist = Math.Sqrt(pt.X * pt.X + pt.Y * pt.Y);
        pt.X = Math.Sin(rads) * dist;
        pt.Y = -(Math.Cos(rads) * dist);
        return pt;
    }
这将允许我处理0,0附近的点的角度。因此,如果您知道要测试的矩形的中心,您将通过该值的负值偏移该点(例如:pt.X-=32;pt.Y-=32),然后应用矩形的负旋转(如Neil:pt.SetAngle(-45);)所建议的)


现在如果点在64,64之内,你就知道你碰到了矩形。更具体地说,我是在检查旋转图像的一个像素,以确保我击中了一个特定颜色的像素。

如果你知道矩形角点的坐标,这是一个快速、优雅的解决方案,只涉及两个点积和标量积:

编辑:回头看,我使用的是MonoGame,OP使用的是Windows窗体。下面是关于MonoGame的

我搞砸这件事已经有一段时间了,我找到了一些答案,但没有一个真正起作用。这是一个C#函数,它完全按照OP描述的那样工作,如果不是OP,那么其他人也会像我一样在谷歌上搜索

弄明白这一点真让人头疼。很多典型的猜测

    bool PointIsInRotatedRectangle(Vector2 P, Rectangle rect, float rotation)
    {
        Matrix rotMat = Matrix.CreateRotationZ(-rotation);
        Vector2 Localpoint = P - (rect.Location).ToVector2();
        Localpoint = Vector2.Transform(Localpoint, rotMat);
        Localpoint += (rect.Location).ToVector2();

        if (rect.Contains(Localpoint)) { return true; }
        return false;
    }
这是一行代码。使用起来可能更快

    bool PointIsInRotatedRectangle(Vector2 P, Rectangle rect, float rotation)
    {
        return rect.Contains(Vector2.Transform(P - (rect.Location).ToVector2(), Matrix.CreateRotationZ(-rotation)) + (rect.Location).ToVector2());
    }

将矩形边视为将一个角点链接到下一个角点的向量列表,按顺时针方向对角点进行排序。如果点位于正方形中,则它必须相对于所有边向量位于右侧

这可以通过向量积来解决,但归结起来如下:

在矩形角点上迭代:

  • 要检查的点是
    P=[px,py]
  • 当前角点是
    C=[cx,cy]
    ,下一个角点是
    N=[nx,ny]

  • 如果
    px*ny+cx*py+nx*cy,这将是一种内存浪费,而且速度会很慢。我现在正在CF项目中使用它来做一些特别复杂的命中测试。但也请注意:Rectangle类有一个Contains方法,可用于测试点包含。这不是一个完美的解决方案,因为它不会缩放得太好,但对于平均大小的图像,这不会太糟糕。如果你能将这个“缓冲区”的位深度保持在较低的水平,它就不会占用太多内存。它会占用一大块内存,但不需要那么多。可能只有不到256个矩形;一张800x600的灰度图像将占用468k,这在现代计算机的容量和程序内存使用范围内。那会有多慢呢?根据存储矩形列表的方式,查找像素可能是O(1),将像素映射到矩形可能是O(1)或O(log(n))。比检查每个矩形更快。这是一个标准的时空权衡。你的建议对一个点下的所有矩形都是可行的,你只需要相应地使用你的缓冲区。说他有8个直肠。为每个像素保留一个字节,并为每个矩形分配一个位。这当然是正确的方法,但我现在似乎无法正确计算。谢谢。我认为理想的解决方案取决于您在应用程序中设置的框架。在某些情况下,我认为Outis关于z缓冲区的想法更为理想。请记住,他的解决方案与GPU在3D中渲染对象的方法相同。公平地说,您将“z-”引入了缓冲概念。嘿,非常感谢!我真的花了好几个小时搞三角学,但令我惊讶的是,这真的奏效了!真遗憾,我能给你的只是一张赞成票!:)尼尔,一开始我很难理解这一点。这看起来很简单,但我必须把它写在纸上,以直观地了解发生了什么。无论出于何种原因,如果有人在使用它,请参阅以获取视觉帮助。矩形是否围绕原点、左上角或其他任意点旋转?这非常好!可以简化为:公共静态布尔点是旋转矩形(vector2p,Rectangle rect,float rotation){return rect.Contains(Vector2.Transform(P-(rect.Location).ToVector2(),Matrix.CreateRotationZ(-rotation))+(rect.Location).ToVector2();}