我有3个点(A、B和X)和距离(d)。我需要测试一个函数,如果X点是更接近于距离d任何一点上的线段AB。

问题是首先是我正确的解决方案然后来了一个更好的(快速)的解决方案。

我第一次通过如下

AX = X-A
BX = X-B
AB = A-B

    // closer than d to A (done squared to avoid needing to compute the sqrt in mag)
If d^2 > AX.mag^2  return true

    // closer than d to B
If d^2 > BX.mag^2 return true

    // "beyond"  B
If (dot(BX,AB) < 0) return false

    // "beyond"  A
If (dot(AX,AB) > 0) return false

    // find component of BX perpendicular to AB
Return (BX.mag)^2 - (dot(AB,BX)/AB.mag)^2 < d^2

这个代码最终会正在运行的大型设的P和一个大集/B/d三胞胎的意图,找到所有P的通过至少一A/B/d所以我怀疑有一种方法来减少总体费用的基础上,但是我还没看到呢。

(顺便说一句:我知道,一些重新排序,一些临时性的价值观和一些代数的身份可能会降低的成本上。我只是省略了他们,为了清楚起见.)


编辑:这是一个2D问题(但解决方案,概括来3D会很酷

编辑:在进一步的反思,我期待的命中率是50%左右。X点,可以形成一种嵌套的层次,所以我希望能够修剪子树大,因为所有通和所有失败。A/B/d限制的三胞胎将更多的一个伎俩。

编辑:d是在同一个数量级。


编辑:Artelius发布一个不错的解决方案。我不确定我明白到底是什么,他正在为我下一切之前我完全理解它。无论如何另一种思想来想作为一个结果是:

  • 第一Artelius'位,预cacluate一个矩阵,将AB为中心吃的来源和与X轴。(2补充说,4muls和2增加了)
  • 把它折叠所有入第1象限(2abs)
  • 规模在X和Y使中心部分的区域进入一个单元方(2mul)
  • 测试如果点是在这场(2试验)就是这样退出
  • 测试结束盖(回到无标值
    • 翻译在x到的地方结束在原籍国(1添加)
    • 广场,并添加(2穆尔1加)
    • 比较d^2(1cmp)

我相当肯定,这个节拍我的解决方案。

(如果没有什么更好的到来曾根Artelius获取"奖金":)

有帮助吗?

解决方案

如果你设置的(A、B、d)在固定的,可以计算出一个对的矩阵,为各翻译的协调系统,以便线基地成为X轴和中点的AB是起源。

想想 这是一个简单的方式构造的矩阵:

trans = - ((A + B) / 2)        // translate midpoint of AB to origin

rot.col1 = AB / AB.mag         // unit vector in AB direction

                        0 -1    
rot.col2 = rot.col1 * (      ) // unit vector perp to AB
                        1  0 

rot = rot.inverse()            // but it needs to be done in reverse

然后你只要把每个X和做 rot * (X + trans).

该区域的问题实际上是对称的在x轴和y轴现在,所以可以采取的绝对值x的协调,并y坐标.

然后你只需要检查:

y < d && x < AB.mag/2            //"along" the line segment
|| (x - AB.mag/2)^2 + y^2 < d^2  // the "end cap".

你可以做另外一个特技;该矩阵可比例下降的一个因素 AB.mag/2 (记得的的矩阵是只计算一次,每(A、B)含义,它是更好的,找到他们慢,比实际检查本身)。这意味着你检查变为:

y < 2*d/AB.mag && x < 1
|| (x - 1)^2 + y^2 < (2*d/AB.mag)^2

具有替换的两个实例。mag/2恒1,这可能是一个触更快。当然,你可以precalculate 2*d/AB.mag(2*d/AB.mag)^2 为好。

这是否会工作的速度比其他方法取决于投入你给它。但是,如果长AB是长相比,d,我认为这将大大快于方法发布。

其他提示

Hmmmmmmm....什么的点击率?如何经常做点"X"满足近要求?

我认为,现有的算法是良好的,以及任何额外的优化将从调整到真实的数据。例如,如果"X"指符合近测试99%的时间,那么我认为你的最优化的战略应当是相当大的不同,比如果这只有通过测试1%的时间。


顺便说一下,当你到哪里你这个算法与成千上万的点,你应该组织的所有各点进入一个K-维树(或 KDTree).它使计算的"最接近的邻居"简单得多。

你的问题就更复杂一点比一个基本最近的邻居(因为你检查近来的-一个线段,而不只是近来-一点),但我仍然认为KDTree将是方便的。

如果我读了这个正确,然后这几乎是同样作为经典的光球交叉点测试的作用,在射线3D-跟踪。

在这种情况下你有一个领域在位置X的半径d,你在试图找出是否AB线交叉的领域。这一差异的光线跟踪的是,在这种情况下你已经有了一个具体的行AB,而在光线跟踪的线通常是广义的作为 origin + distance * direction, 和你不在乎有多远沿着无穷线 AB+ 它是。

在伪码,从我自己的射示踪剂(根据的算法中给出的"介绍对光线追踪"(ed.Glassner):

Vector v = X - A
Vector d = normalise(B - A)  // unit direction vector of AB
double b = dot(v, B - A)
double discrim = b^2 - dot(v, v) + d^2
if (discrim < 0)
     return false            // definitely no intersection

如果你已经走了这么远,那么有的 一些 机会,你的条件得到满足。你只需找出是否有交叉点(s)在线AB:

discrim = sqrt(discrim)
double t2 = b + discrim
if (t2 <= 0)
    return false             // intersection is before A

double t1 = b  - discrim

result = (t1 < length(AB) || (t2 < length(AB))

这个代码最终会正在运行的大型设的P和一个大集/B/d三胞胎的意图,找到所有P的通过至少一A/B/d所以我怀疑有一种方法来减少总体费用的基础上,但是我还没看到呢。

在这种情况下,当d-a-b,对于给定点X,你可以第一个测试是否属于一个许多领域的半径d和中心Ai或Bi。看看图片:

     ......        .....
  ...........   ...........
 ...........................
.......A-------------B.......
 ...........................
  ...........   ...........
     .....         .....

前两个测试

If d^2 > AX.mag^2 return true
If d^2 > BX.mag^2 return true

是最快的,如果d-AB他们也是那些有最高的概率要取得成功(鉴于测试成功,在所有)。鉴于X,你可以做所有的"领域的测试",然后所有的最后一人:

Return (BX.mag)^2 - (dot(AB,BX)/AB.mag)^2 

如果#组/B/d都很大,而你绝对是在2D,考虑使用 R-树木 (或他们的八当量)其中每一条在R-树是最小的边界框/B/d三倍。这会让你消除具有测试一个很大的A/B/d三倍&集中你的CPU功率仅仅在几个在那里的每个点X是在边界的框/B/d三倍。然后做了更详细的测试就像一个你提的。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top