检查是一个点(x,y)是在直线上绘制的两个点之间

时间:2013-07-17 06:44:41

标签: java line

我画了两点A(x,y)--- B(x,y)之间的一条线 现在我有第三个点C(x,y)。我想知道如果C位于A和B之间的线上。 我想用java语言做。我找到了几个类似的答案。但是,都有一些问题,没有人是完美的。

10 个答案:

答案 0 :(得分:69)

if (distance(A, C) + distance(B, C) == distance(A, B))
    return true; // C is on the line.
return false;    // C is not on the line.

或只是:

return distance(A, C) + distance(B, C) == distance(A, B);

这种方式非常简单。如果C位于AB行,则会出现以下情况:

A-C------B

并且,无论它在哪一行,dist(AC) + dist(CB) == dist(AB)。对于任何其他情况,你有一个描述的三角形和'dist(AC)+ dist(CB)> DIST(AB)':

A-----B
 \   /
  \ /
   C

事实上,如果C位于外推线上,这甚至可以起作用:

C---A-------B

如果距离保持不合格。距离dist(AB)可以计算为:

  ___________________________
 /           2              2
V (A.x - B.x)  + (A.y - B.y)

请记住浮点运算的固有限制(有限精度)。您可能需要选择“足够接近”的测试(例如,小于百万分之一的错误)以确保平等的正确运行。

答案 1 :(得分:9)

<强>注意!数学只!

Try this!

你可以尝试这个公式。将A(x1, y1)B(x2, y2)坐标放到公式中,然后就会得到类似

的内容
y = k*x + b; // k and b - numbers

然后,任何满足这个等式的点都会在你的线上。 要检查C(x, y)是否在A(x1, y1)B(x2, y2)之间,请检查:(x1<x<x2 && y1<y<y2) || (x1>x>x2 && y1>y>y2)

示例

A(2,3) B(6,5)

线的等式:

(y - 3)/(5 - 3) = (x - 2)/(6 - 2)
(y - 3)/2 = (x - 2)/4
4*(y - 3) = 2*(x - 2)
4y - 12 = 2x - 4
4y = 2x + 8
y = 1/2 * x + 2; // equation of line. k = 1/2, b = 2;

让我们检查C(4,4)是否在这一行。

2<4<6 & 3<4<5 // C between A and B

现在将C坐标放入等式:

4 = 1/2 * 4 + 2
4 = 2 + 2 // equal, C is on line AB

PS:如@paxdiablo所写,你需要在计算之前检查线是水平还是垂直。请检查

y1 == y2 || x1 == x2

答案 2 :(得分:7)

我认为最简单的是

// is BC inline with AC or visa-versa
public static boolean inLine(Point A, Point B, Point C) {
   // if AC is vertical
   if (A.x == C.x) return B.x == C.x;
   // if AC is horizontal
   if (A.y == C.y) return B.y == C.y;
   // match the gradients
   return (A.x - C.x)*(A.y - C.y) == (C.x - B.x)*(C.y - B.y);
}

您可以通过将x值的差除以y值的差值来计算梯度。

注意:如果您在屏幕上绘制C,则会有不同的测试来查看A是否出现在A和B之间的线上。数学假设A,B,C是无限小点。实际上非常小到表示错误。

答案 3 :(得分:2)

以上答案不必要地复杂化。最简单的如下。

  1. 如果(x-x1)/(x2-x1)=(y-y1)/(y2-y1)= alpha(常数),则点C(x,y)将位于第1和第1点之间的界限2。

  2. 如果alpha&lt; 0.0,然后C在点1的外部。

  3. 如果alpha&gt; 1.0,然后C在点2的外部。
  4. 最后,如果alpha = [0,1.0],那么C是1&amp;的内部。 2。
  5. 希望这个答案有所帮助。

答案 4 :(得分:1)

我认为一个简单的方法是检查3个点形成的角度。 如果ACB角为180度(或接近于此,取决于您想要的精度),则点C在A和B之间。

答案 5 :(得分:1)

我认为这可能有帮助

How to check if a point lies on a line between 2 other points

该解决方案仅使用整数,因为您只需提供整数即可消除一些陷阱

答案 6 :(得分:0)

我认为这里的所有方法都存在缺陷,因为它们并没有尽可能严格地处理舍入错误。基本上,所描述的方法将使用一些简单的算法告诉您您的点是否足够接近线,并且它将或多或少精确。

为什么精确度很重要?因为这是op提出的问题。对于一个计算机程序来说,没有一个点在一条线上,一条线的epsilon中只有一点,需要记录这个epsilon。

让我们来说明问题所在。使用距离比较算法:

让我们说段从(0,0)到(0,2000),我们在我们的应用程序中使用浮点数(它有大约7位小数的​​精度),我们测试是否有点( 1E-6,1000)是否在线。

从段的任一端到该点的距离是1000.0000000005或1000 + 5E-10,因此,与该点之间的距离的增加之间的差异是大约1E-9。但是这些值都不能存储在具有足够精确度的浮点数上,并且该方法将返回true

如果我们使用更精确的方法,比如计算到线中最近点的距离,它会返回一个值,浮动具有足够的精度来存储,我们可以根据可接受的epsilon返回false。

我在示例中使用了浮点数,但同样适用于任何浮点类型,例如double。

一种解决方案是使用BigDecimal以及您想要的任何方法,如果性能和内存命中不是问题。

比比较浮点距离更精确的方法,更重要的是,始终精确,尽管计算成本较高,但计算距离线中最近点的距离。

Shortest distance between a point and a line segment

看起来我分裂了头发,但我之前不得不处理这个问题。链接几何运算时会出现问题。如果你不能控制你正在处理什么样的预防损失,最终你会遇到困难的错误,这会导致你严格地对代码进行推理以解决问题。

答案 7 :(得分:0)

def DistBetwPoints(p1, p2):
    return math.sqrt( (p2[0] - p1[0])**2 + (p2[1] - p1[1])**2 )

# "Check if point C is between line endpoints A and B"
def PointBetwPoints(A, B, C):
    dist_line_endp = DistBetwPoints(A,B)
    if DistBetwPoints(A,C)>dist_line_endp:       return 1
    elif DistBetwPoints(B,C)>dist_line_endp:     return 1
    else:                                        return 0

答案 8 :(得分:0)

这是我的 C# 解决方案。我相信 Java 等价物将几乎相同。

注意事项:

  1. 只有当点在直线的边界内时,方法才会返回 true(它不假设一条无限长的直线)。

  2. 它将处理垂直或水平线。

  3. 它计算要检查的点与线的距离,以便将容差传递给该方法。

     /// <summary>
     /// Check if Point C is on the line AB
     /// </summary>
     public static bool IsOnLine(Point A, Point B, Point C, double tolerance)
     {
         double minX = Math.Min(A.X, B.X) - tolerance;
         double maxX = Math.Max(A.X, B.X) + tolerance;
         double minY = Math.Min(A.Y, B.Y) - tolerance;
         double maxY = Math.Max(A.Y, B.Y) + tolerance;
    
         //Check C is within the bounds of the line
         if (C.X >= maxX || C.X <= minX || C.Y <= minY || C.Y >= maxY)
         {
             return false;
         }
    
         // Check for when AB is vertical
         if (A.X == B.X)
         {
             if (Math.Abs(A.X - C.X) >= tolerance)
             {
                 return false;
             }
             return true;
         }
    
         // Check for when AB is horizontal
         if (A.Y == B.Y)
         {
             if (Math.Abs(A.Y - C.Y) >= tolerance)
             {
                 return false;
             }
             return true;
         }
    
    
         // Check istance of the point form the line
         double distFromLine = Math.Abs(((B.X - A.X)*(A.Y - C.Y))-((A.X - C.X)*(B.Y - A.Y))) / Math.Sqrt((B.X - A.X) * (B.X - A.X) + (B.Y - A.Y) * (B.Y - A.Y));
    
         if (distFromLine >= tolerance)
         {
             return false;
         }
         else
         {
             return true;
         }
     }
    

答案 9 :(得分:0)

这是我制作的一个 JavaScript 函数。您向它传递三个点(具有 x 和 y 属性的三个对象)。点 1 和点 2 定义您的线,点 3 是您要测试的点。

您将收到一个带有一些有用信息的对象:

  • on_projected_line - 如果 pt3 位于线上的任意位置,包括点之外。
  • on_line - 如果 pt3 位于线上以及 pt1pt2 之间或之上。
  • x_between - 如果 pt3 在 x 边界之间或之上。
  • y_between - 如果 pt3 在 y 边界之间或之上。
  • between - 如果 x_betweeny_between 都为真。

/**
 * @description Check if pt3 is on line defined by pt1 and pt2.
 * @param {Object} pt1 The first point defining the line.
 * @param {float} pt1.x
 * @param {float} pt1.y
 * @param {Object} pt2 The second point defining the line.
 * @param {float} pt2.x
 * @param {float} pt2.y
 * @param {Object} pt3 The point to test.
 * @param {float} pt3.x
 * @param {float} pt3.y
 */
function pointOnLine(pt1, pt2, pt3) {
    const result = {
        on_projected_line: true,
        on_line: false,
        between_both: false,
        between_x: false,
        between_y: false,
    };

    // Determine if on line interior or exterior
    const x = (pt3.x - pt1.x) / (pt2.x - pt1.x);
    const y = (pt3.y - pt1.y) / (pt2.y - pt1.y);

    // Check if on line equation
    result.on_projected_line = x === y;

    // Check within x bounds
    if (
        (pt1.x <= pt3.x && pt3.x <= pt2.x) ||
        (pt2.x <= pt3.x && pt3.x <= pt1.x)
    ) {
        result.between_x = true;
    }

    // Check within y bounds
    if (
        (pt1.y <= pt3.y && pt3.y <= pt2.y) ||
        (pt2.y <= pt3.y && pt3.y <= pt1.y)
    ) {
        result.between_y = true;
    }

    result.between_both = result.between_x && result.between_y;
    result.on_line = result.on_projected_line && result.between_both;
    return result;
}

console.log("pointOnLine({x: 0, y: 0}, {x: 1, y: 1}, {x: 2, y: 2})")
console.log(pointOnLine({x: 0, y: 0}, {x: 1, y: 1}, {x: 2, y: 2}))

console.log("pointOnLine({x: 0, y: 0}, {x: 1, y: 1}, {x: 0.5, y: 0.5})")
console.log(pointOnLine({x: 0, y: 0}, {x: 1, y: 1}, {x: 0.5, y: 0.5}))