我需要在空间中将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));
}
}
答案 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空间......)。