在空间中相交的矩形

时间:2016-04-05 01:46:16

标签: c++ data-structures spatial

我需要在空间中将1百万个空间多边形(使用它们的最小边界矩形指定)与4个完全不相交的MBR(MBR1,MBR2,MBR3,MBR4)相交。 MBR1,MBR2,MBR3和MBR4将整个空间分成4个不相交的部分。为此,我编写了以下代码。然而,事实证明,对于100万个点,代码运行速度非常慢。有没有什么方法可以改进代码,以便它可以运行得更快。如果是,那么有人可以帮助相同的

//---------------------------------------------------------------------------
struct MBR
{
    double xRight, xLeft, yBottom, yTop;
};
bool intersects(MBR spatialId,MBR mbr) 
{
    if (mbr.yBottom > spatialId.yTop || mbr.yTop < spatialId.yBottom) return false;
    if (mbr.xLeft > spatialId.xRight || mbr.xRight < spatialId.xLeft) return false;        
    return true;    
}
//---------------------------------------------------------------------------
bool contains(MBR spatialId,MBR mbr) 
{
    if (mbr.yBottom > spatialId.yBottom || mbr.yTop < spatialId.yTop) return false;
    if (mbr.xLeft > spatialId.xLeft || mbr.xRight < spatialId.xRight) return false;
    return true;    
}
//---------------------------------------------------------------------------
bool touches(MBR spatialId,MBR mbr) 
{
    if (    (mbr.yBottom >= spatialId.yBottom + std::numeric_limits<double>::epsilon() && 
            mbr.yBottom <= spatialId.yBottom - std::numeric_limits<double>::epsilon()) ||
            (mbr.yTop >= spatialId.yTop + std::numeric_limits<double>::epsilon() &&
            mbr.yTop <= spatialId.yTop - std::numeric_limits<double>::epsilon()))
            return true;
    if (    (mbr.xLeft >= spatialId.xLeft + std::numeric_limits<double>::epsilon() &&
            mbr.xLeft <= spatialId.xLeft - std::numeric_limits<double>::epsilon()) ||
            (mbr.xRight >= spatialId.xRight + std::numeric_limits<double>::epsilon() &&
            mbr.xRight <= spatialId.xRight - std::numeric_limits<double>::epsilon()))
            return true;    
    return false;    
}
//---------------------------------------------------------------------------
MBR MBR1,MBR2,MBR3,MBR4;
vector<unsigned> spatialIds; //contain 1 million spatial identifiers which are intersected with MBR1, MBR2, MBR3, MBR4
//MBR1, MBR2, MBR3, MBR4 are again specified using their Minimum Bounding Rectangles
vector<unsigned> result; //contains the resulting intersecting spatial ids
for(vector<MBR>::iterator itSpatialId=spatialIds.begin(),lSpatialId=spatialIds.end();itSpatialId!=lSpatialId;++itSpatialId)
{
    if(intersects((*itSpatialId),MBR1)||contains((*itSpatialId),MBR1)||touches((*itSpatialId),MBR1))
    {
        result.push_back((*itSpatialId));
    }

    if(intersects((*itSpatialId),MBR2)||contains((*itSpatialId),MBR2)||touches((*itSpatialId),MBR2))
    {
        result.push_back((*itSpatialId));
    }                    

    if(intersects((*itSpatialId),MBR3)||contains((*itSpatialId),MBR3)||touches((*itSpatialId),MBR3))
    {
        result.push_back((*itSpatialId));
    }   

    if(intersects((*itSpatialId),MBR4)||contains((*itSpatialId),MBR4)||touches((*itSpatialId),MBR4))
    {
        result.push_back((*itSpatialId));
    }   
}

1 个答案:

答案 0 :(得分:1)

我认为你可以简化交叉测试。

首先,我不认为在比较两个值时epsilon是必要的,比较运算符不会引入任何数值误差。

其次,您只需要检查以下内容:

bool intersectsContainsOrTouches(MBR spatialId,MBR mbr) 
{
    return (mbr.yBottom <= spatialId.yTop && mbr.yTop >= patialId.yBottom) &&     
        (mbr.xLeft <= spatialId.xRight && mbr.xRight >= spatialId.xLeft);
}

通常,您可以使用BSP或多维索引来执行空间“JOIN”操作。但由于您只有4个矩形可以连接,因此简单地遍历所有1M矩形并将每个矩形与4个MBR进行比较应该更快。 我不确定多维索引或二进制空间分区在这里会有所帮助。

不过,需要多长时间?它应该显然不到一分钟,这是一个问题吗?

修改

如果必须重复执行此操作,我会将数据放入空间索引中,然后您可以对每个MBR的索引执行四个窗口查询。 还有专用算法,例如TOUCH。 如果您使用的是Java,请查看我的PH-Tree(在添加/删除或移动单个矩形时也很好。对于其他语言,请检查R-Tree(R + tree,X-Tree,.. ),kd-trees或quadtrees。

对于C ++,您可以查看ODE。它是一个3D游戏物理引擎,内部有几种用于检测MBR重叠的算法(四叉树,SAP空间......)。