繁体   English   中英

C中的空间数据结构

[英]Spatial Data Structures in C

我在高性能集群中从事理论化学工作,通常涉及分子动力学模拟。 我的工作涉及的问题之一涉及N维(通常N = 2-5)超​​球的静态场,测试粒子可能碰撞。 我正在寻找优化(读取:大修)我用来表示球体领域的数据结构,这样我就可以进行快速碰撞检测。 目前,我使用一个死的简单指针数组指向N元结构(中心的每个坐标加倍)和最近邻居列表。 我听说过oct和quad-trees,但是没有找到关于它们如何工作,如何有效地实现它,或者如何用一个快速碰撞检测的明确解释。 鉴于我的模拟大小,内存(几乎)没有对象,但周期是。

如何最好地解决您的问题取决于您未描述的几个因素: - 相同的超球面排列是否会用于许多粒子碰撞计算? - 超球体的大小是否均匀? - 粒子的运动是什么(例如直线/曲线),是受球体影响的运动? - 你认为粒子的体积是零吗?

我假设粒子不具有简单的直线运动,因为这将是找到线和点之间的最近点的相对快速的计算,这可能与找到线的哪个框的速度大致相同。与...相交(以确定要检查的n树中的位置)。

如果您的超球面位置对于大量粒子碰撞是固定的,那么计算voronoi分解/ Dirichlet曲面细分将为您提供一种快速的方法,以便稍后找到空间中任何给定点的哪个球体最接近您的粒子。

然而,要回答关于八叉树/四叉树/ 2 ^ n树的原始问题,在n维中,您将从包含您感兴趣的空间区域的(超)立方体开始。这将被细分为2 ^ n个超立方体如果你认为内容太复杂了。 这将继续递归,直到叶节点中只有简单元素(例如一个超球面质心)。 现在构建了n树,您可以通过获取粒子的路径并将其与外部超立方体相交来将其用于碰撞检测。 交叉点位置将告诉您接下来要访问的树的下一级中的哪个超立方体,并确定该级别上所有2 ^ n超立方体的交叉位置,然后向下,直到到达叶节点。 到达叶子后,您可以检查粒子路径与存储在该叶子上的超球面之间的相互作用。 如果碰撞已经完成,则必须从当前超立方体叶片中找到粒子路径的出口点,并确定它移动到下一个的超立方体。 继续,直到发现碰撞或完全离开整个边界超立方体。

退出超立方体时有效地找到相邻超立方体是该方法中最具挑战性的部分之一。 对于2 ^ n树,可以调整Samet的方法{1,2}。 对于kd-trees(二叉树),在{3}第4.3.3节中提出了一种方法。

有效的实现可以简单到将每个超立方体的8个指针的列表存储到其子超立方体,并且如果它是叶子则以特殊方式标记超立方体(例如,使所有指针为空)。

可以在Klinger&Dyer {4}中找到划分空间以创建四叉树(可以推广到n树)的描述

正如其他人所提到的,kd-tree可能比2 ^ n-tree更适合,因为对任意数量维度的扩展更为直接,但是它们将导致更深的树。 也可以更容易地调整分割位置以使用kd树匹配超球面的几何形状。 以上对2 ^ n树中的冲突检测的描述同样适用于kd树。

{1} 连接组件标签,Hanan Samet,使用Quadtrees期刊ACM第28卷,第3期(1981年7月)

{2} 由八叉树代表的图像中的邻居发现,Hanan Samet,计算机视觉,图形和图像处理第46卷,第3期(1989年6月)

{3} 凸壳体生成,连通分量标记和理论定义模型的最小距离计算,Dan Pidcock,2000

{4}使用常规分解的图片表示实验,Klinger,A。和Dyer,CR E,Comptr。 图形和图像处理5(1976),68-105。

听起来你想要实现一个kd树,它可以让你更快地搜索N维空间。 有一些更多的信息和链接到Stony Brook算法库的实现。

由于你的场是静态的(我假设你的意思是超球不移动),那么我所知道的最快的解决方案是Kdtree。
您可以自己制作,也可以使用其他人,如下所示: http//libkdtree.alioth.debian.org/

四叉树是二维树,其中在每个级别节点具有4个子节点,每个子节点覆盖父节点的1/4区域。

Oct树是一个三维树,其中每个级别一个节点有8个子节点,每个子节点包含父节点体积的1/8。 这是帮助您想象它的图片: http//en.wikipedia.org/wiki/Octree

如果您正在进行N维交叉测试,则可以将其推广到N树。

交叉算法的工作原理是从树的顶部开始,并递归遍历到与被测对象相交的任何子节点,在某些时候,您将获得包含实际对象的叶节点。

只要你可以通过它们的中心指定球体,八叉树就可以工作 - 它将点分为两个孩子的立方区域。 在八叉树数据结构中计算邻居将要求您进行球体相交立方体计算(在某种程度上比它们看起来更容易),以确定八叉树中的哪些立方区域在球体内。

查找最近的邻居意味着返回树,直到您获得一个包含多个填充子节点并包含所有周围节点的节点(这可确保查询获取所有边)。

从记忆中,这是球形立方体交叉的(有点天真)基本算法:

一世。 是多维数据集中的中心(这得到了同名的情况)

II。 立方体的任何角都在中心的半径r内(球体内的角落)

III。 对于立方体的每个表面(你可以通过计算中心所在表面的哪一侧来消除一些表面)计算出来(这是所有第一年的矢量运算):

一个。 表面的法线到达球体的中心

从球体中心到法线与表面平面的交点的距离(弦线平面与立方体表面平面)

C。 平面的交点位于立方体的侧面(与立方体相交的一个条件)

IV。 计算弦的大小(正常长度与球体半径之比的Cos ^ -1)

v。如果线上的最近点小于弦的距离并且该点位于线的两端之间,则弦与立方体的一个边相交(弦沿着其中一个边与某个立方体表面相交)。

略微模糊地记住,但这是我在使用octee数据结构(多年前)涉及球形区域的情况下所做的事情。 您可能还希望查看KD树,因为其他一些海报建议,但您的初始问题听起来与我所做的非常相似。

暂无
暂无

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

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