测试点是否在2D空间的线范围内

时间:2017-08-20 09:25:30

标签: java algorithm math geometry

这个问题有点难以制定,所以我首先要展示这张图片:

enter image description here

我想测试点(例如图像上的p1和p2)是否在垂直于其极限线的虚线内。我知道要测试的点的坐标和线的限制。

因此,对于p1,它将是错误的,对于p2,它将是真的。

计算这个计算效率最高的方法是什么?

我正在使用Java中的浮点数。

7 个答案:

答案 0 :(得分:3)

使用点积

可以非常高效地完成此操作

enter image description here

如果A组件并行B,则为正,如果反并行,则为负

因此,如果您有一个由点AB定义的线段以及一个测试点P,那么您只需要两个点积运算来测试:

dot(A - B, P - B) >= 0 && dot(B - A, P - A) >= 0

编辑:图解说明:

enter image description here

点积可以显示为:

enter image description here

因此,如果θ > 90然后dot(A, B) < 0,反之亦然。现在为您解决问题:

enter image description here

在案例1中,当dot(A - B, P - B) > 0时我们说P位于B虚线的正确一侧,反之亦然。通过对称我们可以做A处的相同操作,通过交换AB

答案 1 :(得分:0)

如果测试点(tp)与范围的起点(sp)和终点(ep)一起形成一个钝角三角形,你可以断定它超出了范围。

https://en.wikipedia.org/wiki/Acute_and_obtuse_triangles

特殊情况是tp与sp和ep相同,然后计算2个距离:

  • distSpAndTp - sp和tp之间的距离
  • distEpAndTp - ep和tp之间的距离

如果这两个距离的总和= sp和ep之间的距离,那么tp在范围内,否则它超出范围。

答案 2 :(得分:0)

最好的方法是首先创建一个矩形 Rect android.graphics 包),x和width是行的开头和结尾,y和高度是屏幕高度的开始和结束。 然后使用 Rect 方法 Rect.contains(int x,int y) 来检查点坐标是否存在内。

对于浮点数,请改用 RectF 类。

答案 3 :(得分:0)

这种方法涉及使用2D矢量(无论如何应该使用它,使得在任何坐标系统中工作都更容易)和点(标量)产品。它不需要任何相对昂贵的操作,如平方根或三角函数,因此非常高效。

AB成为线段的起点和终点(按点我的意思是表示2D空间中的位置的矢量),以任何顺序排列。如果P是要测试的点,那么:

  • 如果dot(PA, AB)dot(PB, AB)具有相同的符号,则该点位于区域(如示例中的p1)。
  • 如果上面的点积具有相反的符号,则该点位于区域(如p2)。

PA = A - PPB = B - PAB = B - A

这种情况可以推测如下:

if dot(PA, AB) * dot(PB, AB) <= 0 {
   // Opposite signs, inside region
   // If the product is equal to zero, the point is on one of the dotted lines
}
else {
   // Same signs, outside region
}

答案 4 :(得分:0)

让我们说, x1 是该行的开头, x2 是结束。然后 ax 是水平平面中的点;垂直计划中的 y1 y2 ay

  

if((ax&gt; = x1&amp;&amp; ax&lt; = x2)&amp;&amp;(ay&gt; = y1&amp;&amp; ay&lt; = y2)){//做你的工作   }

答案 5 :(得分:0)

已经有一些答案,但还有另一种解决方案可以为您提供点垂直于线段的单位距离。

其中,行为x1y1x2y2,点为pxpy

从行开始到结束找到向量

vx = x2 - x1;
vy = y2 - y1;

从行开始(或结束)到点

的向量
vpx = px - x1;
vpy = py - y1;

然后将两个向量的点积除以线的长度平方。

unitDist = (vx * vpx + vy * vpy) / (vx * vx + vy * vy);

如果垂直截距位于线段上,则unitDist将为0 <= unitDist <= 1

缩写形式

x2 -= x1;
y2 -= y1;
unitDist = (x2 * (px - x1) + y2 * (py - y1)) / (x2^2 + y2^2);
if (unitDist >= 0 && unitDist <= 1) {
    // point px,py perpendicular to line segment x1,y1,x2,y2
}

您还可以获得截距所在线上的点。

p2x = vx * unitDist + x1;
p2y = vy * unitDist + y1;

因此该点距离线的距离(注意不是线段而是线)

dist = hypot(p2x - px, p2y - py);

如果您使用点通过使用最小距离来确定所选行,则可以使用一个点进行选择。

答案 6 :(得分:0)

使用复数可以很好地解决这个问题。

ab段的端点。我们使用将原点0映射到a并将点1映射到b的转换。这种转变是相似的,它的表达只是

p = (b - a) q + a

您可以通过替换q=0q=1进行验证。它将垂直于给定段的整个条纹映射到垂直于段0-1的条带。

现在逆变换显然是

q = (p - a) / (b - a), 

,所需的条件是

0 <= Re((p - a) / (b - a)) <= 1.

为避免分裂,您可以重写

0 <= Re((p - a) (b - a)*) <= |b-a|²

0 <= (px - ax)(bx - ax) + (py - ay)(by - ay) <= (bx - ax)² + (by - ay)².