点轴对齐矩形测试?

时间:2010-10-08 20:12:10

标签: c++ c algorithm

我的矩形结构包含以下成员: x,y,宽度,高度。

给出点x,y 知道x,y是否在矩形内部的最快方法是什么?我会做很多这些,所以速度很重要。

5 个答案:

答案 0 :(得分:6)

这就是我通常这样做的方式。给定一个在矩形之外的点,这将在4个案例中的3个中进行较少的测试。有时只进行一次测试。

if(point.x < rect.x) return false;
if(point.y < rect.y) return false;
if(point.x >= rect.x + rect.width) return false;
if(point.y >= rect.y + rect.height) return false;
return true;

您使用哪一个应该取决于您是否预期会发生更多碰撞或更多未命中。

答案 1 :(得分:1)

if (p.x > x && p.y > y && p.x < x+width && p.y < y+height)

这应该只是少数装配说明。

假设矩形的x,y始终是矩形的最小值坐标。它还可以折扣矩形边框上的点。

答案 2 :(得分:1)

在C ++中(可以简单地翻译成C):

bool pointInRectangle( Point const & p, Rectangle const & r ) {
    return 
        ((r.x <= p.x) && (p.x <= (r.x + r.width ))) &&
        ((r.y <= p.y) && (p.y <= (r.y + r.height)));
}

答案 3 :(得分:1)

我在编写比赛时找到了两个更好的答案。首先,它使用两个点的坐标,而不是缓慢的高度/宽度,这也假设一个点是两个浮点数,一个矩形是四个浮点数;对于不同的数据类型,可能需要更改此逻辑!

首先,使用了解英特尔SSE指令的编译器,结合&amp; amp;和&amp;&amp;以正确的方式更快。这将两个测试组合成一个,但保持快速进行后两个测试:

if((p.x>=r.lx)&(p.x<=r.hx)&&(p.y>=r.ly)&(p.y<=r.hy))
    ptisinrect=true;

目前,使用128位SSE指令进行编译比使用所有&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&nbsp;更快,但使用256位AVX2设置的速度较慢,即使使用全部&amp;&#39; p>

但是,如果将程序设置为测试阵列中的大量点,则可以使其完全向量化并显着提高性能(仍然使用SSE,而不是AVX或AVX2)。矢量化是一种简单的并行化,具有一些严格的要求。例如,循环中不会出现短路,并且您不能多次保存到同一变量。

请看一下这个非矢量化代码的简化示例,该代码可以查找&#39; count&#39;如果找到足够的信息并退出:

for(unsigned a=0;a<n;++a)
{
    if((pp[a].x>=r.lx)&&(pp[a].x<=r.hx)&&(pp[a].y>=r.ly)&&(pp[a].y<=r.hy))
    {
        ++found;
       if(found>count)
            return true;
    }

}

下面的代码是同一个例子的例子,只是将0到n个ptinrects的搜索向量化,但是当&#39; count&#39;找到矩形中的点。请注意,此代码可以读取超过n的32个点,因此需要为该数组分配32个额外的空间点:

typedef struct ab
{
    int64_t a[4];
};
typedef struct{
union{
    ab ab;
    int8_t o[32];
    };
}xmmb;
xmmb o;
for(unsigned i=0;i<n;i+=32)
{
    for(unsigned a=0;a<32;++a)
    {
        o.o[a]=((pp[i+a].x>=r.lx)&(p[i+a].x<=r.hx)&(p[i+a].y>=r.ly)&(p[i+a].y<=r.hy));
    }

    for(unsigned kk=0;kk<4;++kk)
    {
        if(o.ab.a[kk])
       for(unsigned a=kk<<3;a<(kk+1)<<3;++a)
       {
            if(o.o[a]) 
            {
                if(i+a<n)
                {
                    ++found;
                    if(found>count)
                        return true;
                }
            }
        }
    }
}

即使看起来很奇怪,这段代码比上一个例子快得多! 它正在做的是在向量并行中运行ptrect测试并将true / false存储在32个8位字节的数组中。然后它一次检查8个(因此使用4个64位的联合)来保存测试。然后查看具有真值的任何值并将它们添加到计数中。

再次注意,这仅适用于128位SSE,并且当编译为256位AVX2时,目前(2015年2月)较慢,因此请使用开关或编译指示来保持SSE 最后,这段代码可能有语法错误之类的东西,因为将它输入这种格式并不容易切割:D

标签:快速ptinrect快速点在矩形中的快点

答案 4 :(得分:0)

如果您要定位特定的CPU,例如x86,您可以使用SIMD(即SSE)进行非常快速的无分支测试。诀窍是使用4 x 32位整数来表示矩形,该矩形映射到SIMD向量(它需要16字节大小和16字节对齐)。

相关问题