Java 检查点(x,y)是否位于直线上绘制的两点之间

Java 检查点(x,y)是否位于直线上绘制的两点之间,java,line,Java,Line,我已经在两点a(x,y)-B(x,y)之间画了一条线 现在我有第三个点C(x,y)。我想知道,如果C位于A和B之间的直线上。 我想用java语言来做。我发现了两个类似的答案。但是,所有人都有一些问题,没有人是完美的 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. 或者只是:

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

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)”的三角形:

事实上,如果C位于外推线上,这一点也有效:

C---A-------B
只要距离保持无符号。距离
dist(AB)
可计算为:

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

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

注意!只有数学

你可以试试这个公式。把你的
A(x1,y1)
B(x2,y2)
坐标放到公式中,你会得到如下结果

y = k*x + b; // k and b - numbers
那么,满足这个方程的任何一点,都位于你的直线上。 要检查
C(x,y)
是否介于
A(x1,y1)
B(x2,y2)
之间,请检查此项:
(x1y2)

示例

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
PS:正如@paxdiablo所写,在计算之前,您需要检查直线是水平的还是垂直的。检查一下

y1 == y2 || x1 == x2

我相信最简单的是

// 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,则有一个不同的测试来查看C是否出现在a和B之间的线上。数学假设A、B、C是无限小点。事实上,误差非常小。

上述答案不必要地复杂。最简单的方法如下

  • 如果(x-x1)/(x2-x1)=(y-y1)/(y2-y1)=α(常数),则点C(x,y)将位于pts 1和2之间的线上

  • 如果α<0.0,则C位于点1的外部

  • 如果alpha>1.0,则C位于点2的外部
  • 最后,如果alpha=[0,1.0],那么C是1和2的内部

  • 希望这个答案有帮助

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

    为什么精确性很重要?因为这正是op提出的问题。对于一个计算机程序来说,直线上没有点,只有一条直线的ε内的点,而ε是什么需要记录下来

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

    假设一段从(0,0)到(0,2000),我们在应用程序中使用浮点(精度约为7位小数),我们测试(1E-61000)上的一点是否在直线上

    从管段两端到该点的距离为1000.0000000005或1000+5E-10,因此,与该点之间距离相加的差值约为1E-9。但是这些值都不能以足够的精度存储在浮点上,该方法将返回
    true

    如果我们使用更精确的方法,比如计算到直线上最近点的距离,它会返回一个浮点值,该值具有足够的精度来存储,并且根据可接受的ε,我们可能会返回false

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

    一种解决方案是使用BigDecimal,如果性能和内存不受影响,则可以使用任何方法

    一种比比较浮点距离更精确的方法,更重要的是,始终如一地精确,尽管计算成本更高,但计算到直线上最近点的距离


    看起来我在吹毛求疵,但我以前不得不处理这个问题。这是链接几何操作时的一个问题。如果你不能控制你正在处理的精度损失类型,最终你会遇到困难的错误,这将迫使你对代码进行严格的推理以修复它们。

    一个简单的方法是检查3个点形成的角度。
    如果角度ACB为180度(或接近它,取决于您希望的精确度),则点C位于A和B之间。

    我认为这可能会有所帮助

    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
    

    该解决方案只使用整数,因为您只提供整数,这也消除了一些陷阱

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

    注:

  • 方法仅当点位于直线的边界内(它不假定为无限直线)时才会返回true

  • 它将处理垂直或水平线

  • 它计算被检查点与直线的距离,以便允许将公差传递给该方法

     /// <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;
         }
     }
    
    //
    ///检查点C是否在AB线上
    /// 
    公共静态边界线(点A、点B、点C、双公差)
    {
    双最小值=数学最小值(A.X,B.X)-公差;
    double maxX=数学最大值(A.X,B.X)+公差;
    双最小值=数学最小值(A.Y,B.Y)-公差;
    双最大值=数学最大值(A.Y,B.Y)+公差;
    //检查C是否在该行的范围内
    如果(C.X>=ma
    
    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
    
     /// <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;
         }
     }