【发布时间】:2022-01-24 19:34:22
【问题描述】:
我有大量静态“墙”集合。这些被保存为 Vector3 点的两项数组,可以被视为线段(这是一个 2D 问题,所以我们只对 X 和 Z 感兴趣)。其中大约有 1000 个。
有一个大的点列表 - (以百万计)保存在一个名为 pointCollection 的列表中,还有一个更小的(数百个)Vector3 点保存在另一个名为 testCollection 的列表中。
结合 pointCollection 和 testCollection 的每一项,并针对墙集合测试这些段中的每一个,如果没有交叉点,则可以完成一些工作。
我目前的方法效果很好,但太慢了,因此如果没有一些改进就无法使用。
下面的工作(但速度很慢)代码显示了我在测试和交集函数中的初始方法。
//iterate over the point collection
foreach (Vector3 myPoint in pointCollection){
//iterate over the test collection
foreach (Vector3 myTest in testCollection){
//assume no intersection until proven wrong
bool pointClean = true;
//test against all walls
foreach (Vector3[] myWall in myWalls){
if (intersects(myPoint.x, myPoint.z, myTest.x, myTest.z, myWall[0].x, myWall[0].z, myWall[1].x, myWall[1].z) == true){
//Break to avoid unneeded tests - this point has already intersected
pointClean = false;
break;
}
}
if (pointClean == true){
//do some work if the point is clean
}
}
//tests the intersection of line segment (ab -> cd) vs (pq -> rs)
public bool intersects(float a, float b, float c, float d, float p, float q, float r, float s) {
float det = (c - a) * (s - q) - (r - p) * (d - b);
float gamma;
float lambda;
if (det == 0) {
return false;
} else {
lambda = ((s - q) * (r - a) + (p - r) * (s - b)) / det;
gamma = ((b - d) * (r - a) + (c - a) * (s - b)) / det;
return (0 < lambda && lambda < 1) && (0 < gamma && gamma < 1);
}
}
我觉得可能有一些可用的快捷方式“快速”通过使用矩形或排序列表排除了一些可能的重叠,但我正在绘制空白。
【问题讨论】:
-
你的空间有界限吗?
-
是的,两个轴都有明确的限制 - 因此可以按至少一个维度对列表进行排序。
-
我认为您正在寻找线扫描算法,我已经使用了几次,效果非常好。 en.wikipedia.org/wiki/Sweep_line_algorithm
-
另一种方法可以是分段树。 en.wikipedia.org/wiki/Segment_tree 在这里,您可以将 pointCollection 存储在分段树中,并将您的 testcollection 作为您想要获取 pointCollection 节点的“窗口”。
-
我过去使用过四叉树,你可能会在那里找到一些东西。我会对此有所了解。
标签: c# algorithm optimization