繁体   English   中英

点轴对齐矩形测试?

[英]Point in axis aligned rectangle test?

我的矩形结构有以下成员:x,y,width,height。

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

这就是我通常这样做的方式。 给定一个在矩形之外的点,这将在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;

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

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

首先,使用了解英特尔SSE指令的编译器,以正确的方式组合&和&&的测试要快得多。 这将两个测试组合成一个,但是在后两个测试中保持快速:

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

目前,使用128位SSE指令进行编译比所有&&更快,但使用256位AVX2设置速度较慢,即使使用全部&#s。

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

因此,请查看非向量化代码的简化示例,该代码查找“count”ptinrects并在找到足够的内容时退出:

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的搜索向量化,但是当找到矩形中的“count”点时仍然存在。 请注意,此代码可以读取访问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

tags:快速ptinrect快速指向矩形中的快点

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

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM