• 判断顶点是否位于线段上


    假设线段的两个端点分别为:A、B,另外一点为 P。
    问题:判断 P 点是否位于线段 AB 上。

    方法1:通过线段确定的直线方程判断。
    (1) 在二维空间中,三点坐标表示为:A(xa,ya), B(xb,yb), P(xp,yp)。
    AB确定的直线方程(点斜式)为:
          k = (yb - ya) * 1 / (xb - xa) 
          y = k * (x - xa) + ya
    P点若位于直线上,首先应该满足直线的方程:
          yp = k * (xp - xa) + ya。
    若上式成立,说明A、B、P共线,接下来只需判断 P 位于 A 和 B 中间,即
         (xa <= xb && xa <= xp <= xb) || (xa > xb && xa >= xp >= xb)
         (ya <= yb && ya <= yp <= yb) || (ya > yb && ya >= yp >= yb)
    同时成立。否则,P 不在线段AB上。

    注意到直线方程中有除法运算,需做一步AB是否重合的判断,否则除数为零。上式稍作变形,便可去掉除法运算,即:
         (y - ya) / (yb - ya) = (x - xa) / (xb - xa)
    进而
         (y - ya) * (xb - xa) - (yb - ya) * (x - xa) = 0。
    上式成立的条件,(x,y)与A或B点重合,或者(x,y)、A、B三点共线。接下来再做 P 是否位于AB中间的判断即可。

    上述变形后的等式,其实表示的是二维平面中向量的一种运算:叉积(cross product),
          A x B = xa*yb - ya*xb
    由直线方程的启示,不难理解叉积为零,则可判定两向量共线或者一个向量为零。

    变形后的直线方程和向量的叉积是二维空间向三维空间推广的基础。

    (2) 在三维空间中,三点坐标分别为A(xa,ya,za), B(xb,yb,zb), P(xp,yp,zp)。
    AB确定的直线方程相应变为:
         (y - ya) / (yb - ya) = (x - xa) / (xb - xa) = (z - za) / (zb - za)。
    按(1)中所述,将P点代入直线方程成立后,只需再多做一步 z 轴坐标的判断:
         (za <= zb && za <= zp <= zb) || (za > zb && za >= zp >= zb)。
    所有条件同时成立,则 P 点位于线段 AB 上。

    三维空间中的叉积判断就是接下来的方法2。

    方法2:利用向量的叉积做判断[3]。
    二维空间中的叉积定义已经介绍,三维空间的描述可以参考「4」,叉积可以作为判定两个向量是否共线的一个工具,三维空间中的叉积结果会得到一个新的向量。
    先求得两个向量:v1 = B - A, v2 = P - A。然后 v1 和 v2 做叉积:v = v1 x v2,如果 v 是零向量,即 v 的x、y、z分量都为 0,则v1 和 v2 至少有一个为零或者两个向量共线。
          if v2 == 0,then P == A;
          else if v1 == 0 then  A == B  AND P doesn't lie in AB ; // v2 != 0
          else P,A,B are colinear;
          end
    如果判定共线后,接下来判断 P 是否位于 AB 内的方式同方法1.

    方法3:面积法。
    如果A、B、P三点组成的三角形的面积为零,那么可以得出三点共线的结论。
    三角形面积可以使用海伦公式直接得出,另外上述v1和v2叉积得到的向量的长度的一半,也是三点组成的三角形的面积(参考叉积的定义)。
    不过这两种方式都涉及到开根号的运算,代价较高。

    另外在判定了三点共线后,v1 和 v2 的夹角要么0度,要么180度,点积的符号可以用来确定P点的位置,如:v1 ・ v2  < 0。那么,v1 和 v2 夹角为180,反向,P点位于AB之外。
    接下来再以 B 点为基准做两个向量v1’ = A - B, v2’ = P - B,若v1’ ・ v2’ > 0,即可断定 P 位于线段AB上。
    如果不以 B 为基准做两个向量,可以通过长度来判断,由内积的定义可以知道:
         v1 ・ v2 = |v1| |v2| cos<v1, v2> = |v1| |v2| cos(0) = |v1| |v2|。
    如果v1 ・ v2  > |v1|*|v1| = v1 ・ v1 => |v2| > |v1|,即PA的长度大于BA,又PA和BA同向,那么P点一定位于AB之外。

    不过上述的点积判定符号的方法,包含了许多乘法的运算,进行坐标比较的方法反而更加直接简单。综上所述,方法2更值得推荐。

    参考:
    [1] http://stackoverflow.com/questions/328107/how-can-you-determine-a-point-is-between-two-other-points-on-a-line-segment
    [2] http://stackoverflow.com/questions/7050186/find-if-point-lay-on-line-segment
  • 相关阅读:
    JSP,TOMCAT,JD,mysql环境搭建和连接数据库
    jsp基础学习记录
    将d盘根目录下的troydll.dll插入到ID为4000的进程中
    WebSocket内部原理
    基于流(Comet Streaming)
    短轮询
    DjangoWebSocket
    01WebSocket是什么
    Python实现WebSocket
    WebSocket
  • 原文地址:https://www.cnblogs.com/xinyuyuanm/p/3206294.html
Copyright © 2020-2023  润新知