确定:是线段上的点

determinate: is point on line segment

我正在尝试编写一个 java 方法,其中 returns 如果点 (x,y) 在线段上则为布尔值 true,否则为 false。

我试过这个:

public static boolean OnDistance(MyLocation a, MyLocation b, MyLocation queryPoint) {

    double value = java.lang.Math.signum((a.mLongitude - b.mLongitude) * (queryPoint.mLatitude - a.mLatitude)
            - (b.mLatitude - a.mLatitude) * (queryPoint.mLongitude - a.mLongitude));
    double compare = 1;
    if (value == compare) {
        return true;
    }

    return false;
}

但是没用。

我不是 JAVA 编码员,所以我坚持数学背后......对于初学者,假设你在平面上(不是球面)

  1. 我会使用矢量数学,所以让:


    a,b - 是线的端点
    q - 查询点
    c=q-a - 查询的线方向向量
    d=b-a - 直线方向矢量

  2. 参数提取使用点积

    t=dot(c,d)/(|c|*|d|)
    


    t 是行参数 <0,1> 如果超出范围 q 不在行内
    |c|=sqrt(c.x*c.x+c.y*c.y) 矢量大小
    dot(c,d)=c.x*d.x+c.y*d.y 标量向量相乘

  3. 现在计算线上的对应点

    e=a+(t*d)
    


    e 是直线 ab

  4. 上最接近 q 的点
  5. 计算qab

    的垂直距离
    l=|q-e|;
    

    if (l>treshold) then q 不在行 ab 否则它在行 ab。阈值是距离您仍接受为内线的最大距离。无需 l sqrt-ed 阈值常量可以由 2 代替以提高速度。

  6. 如果将所有这些添加到单个方程式

    然后有些事情会自己简化(希望没有犯一些愚蠢的数学错误)

    l=|(q-a)-(b-a)*(dot(q-a,b-a)/|b-a|^2)|;
    return (l<=treshold);
    

    l=|c-(d*dot(c,d)/|d|^2)|;
    return (l<=treshold);
    

    如您所见,我们甚至不需要 sqrt :)

[注释]

如果您需要球面或椭圆面,那么您需要将其指定得更近一些,即半轴是什么。该线变为 arc/curve 并需要根据表面形状进行一些修正,请参见

但也可以通过近似来完成,也可以通过点 e 的二进制搜索来完成,请参阅:

  • mine approx class in C++

所用到的矢量数学可以在文末找到:

这里是3D C++实现(名称不同):

double distance_point_axis(double *p,double *p0,double *dp)
    {
    int i;
    double l,d,q[3];
    for (i=0;i<3;i++) q[i]=p[i]-p0[i];                  // q = p-p0
    for (l=0.0,i=0;i<3;i++) l+=dp[i]*dp[i];             // l = |dp|^2
    for (d=0.0,i=0;i<3;i++) d+=q[i]*dp[i];              // d = dot(q,dp)
    if (l<1e-10) d=0.0; else d/=l;                      // d = dot(q,dp)/|dp|^2
    for (i=0;i<3;i++) q[i]-=dp[i]*d;                    // q=q-dp*dot(q,dp)/|dp|^2
    for (l=0.0,i=0;i<3;i++) l+=q[i]*q[i]; l=sqrt(l);    // l = |q|
    return l;
    }

其中p0[3]为轴上任意点,dp[3]为轴方向向量。 p[3] 是您想要轴距离的查询点。