检测点是否属于线段

Jef*_*ull 3 javascript math pseudocode

如果我有一条线,有点x,y,endx和endy,我怎么能检测出另一个点是否在线上?一个简单的等式,或JavaScript或伪代码中的示例函数将是最有帮助的.

编辑:这是我正在研究的游戏,我正在尝试检测激光是否与物体发生碰撞,以下是示例http://jefnull.com/references/lasers/最常用的文件描述性是http://jefnull.com/references/lasers/lasers.js

Chr*_*ham 12

自从我上次回答说,如何确定一个点是线了,真正的问题似乎是"我怎么能知道,如果该点附近的线路 ",我加入一个新的答案.

这是诀窍:首先找到障碍物到线段两个端点的距离.这两个距离不能唯一地确定障碍物的位置,但它们确实唯一地确定了具有三个特定边长的三角形,然后我们可以立即使用一堆几何体.

边长为A,B,C的三角形

我摆弄了一点颜色.无论如何,我在上面的评论中提到你应该使用点线距离公式来找到障碍物和线之间的距离.但那实际上并不奏效.原因是它是点线距离.因此,对于下面的两个示例,公式将计算图片中的粗体距离H.

急性和钝角三角图

那不对!!

相反,这里是用于找到从障碍物到激光器形成的线段的距离的伪代码:

Find the distance from my point to the line segment!

if the angle at (x,y) is obtuse
    return A
else if the angle at (endx,endy) is obtuse
    return B
else
    return H
Run Code Online (Sandbox Code Playgroud)

以下是可用于实现上述伪代码的数学运算:

  • 要查看角度(x,y)是否为钝角,请查找是否B^2 > A^2 + C^2.如果是这样,角度是钝的.
  • 要查看角度(endx, endy)是否为钝角,请查找是否A^2 > B^2 + C^2.如果是这样,角度是钝的.
  • 要计算H,请使用两种不同的方法来查找三角形的区域 - 通常base*height/2苍鹭的公式.

这意味着你应该:

set s = (A+B+C)/2
The area of the triangle is C*H/2
The area of the triangle is also sqrt(s*(s-A)*(s-B)*(s-C)) 
So H = 2/C * sqrt(s*(s-A)*(s-B)*(s-C)).
Run Code Online (Sandbox Code Playgroud)

最终结果如下:

if B^2 > A^2 + C^2
    return A
else if A^2 > B^2 + C^2
    return B
else
    s = (A+B+C)/2
    return 2/C * sqrt(s*(s-A)*(s-B)*(s-C))
Run Code Online (Sandbox Code Playgroud)

我认为这应该足以让你完成你实际要做的事情.祝你好运,不要放弃!


Chr*_*ham 7

您想要检查点对之间的斜率是否相同.但是你应该注意不要除以零,所以通过检查方程的交叉乘法版本来检查.

更明确地说,如果你的点是A = (Ax, Ay),B = (Bx, By),C = (Cx, Cy),那么你想检查

(Cy - Ay)  / (Cx - Ax) = (By - Ay) / (Bx - Ax)
Run Code Online (Sandbox Code Playgroud)

但你应该检查一下

(Cy - Ay)  * (Bx - Ax) = (By - Ay) * (Cx - Ax).
Run Code Online (Sandbox Code Playgroud)


Flo*_*ens 5

首先,尽管理论性很高,但拉扎克提供的答案是数学上最合理的答案。如果您赞成这个答案,请考虑也赞成他的答案。

我已经在以下有用的javascript函数中实现了他的方法。特别看一下函数calcIsInsideThickLineSegment(...)。请随便使用。

//Returns {.x, .y}, a projected point perpendicular on the (infinite) line.
function calcNearestPointOnLine(line1, line2, pnt) {
    var L2 = ( ((line2.x - line1.x) * (line2.x - line1.x)) + ((line2.y - line1.y) * (line2.y - line1.y)) );
    if(L2 == 0) return false;
    var r = ( ((pnt.x - line1.x) * (line2.x - line1.x)) + ((pnt.y - line1.y) * (line2.y - line1.y)) ) / L2;

    return {
        x: line1.x + (r * (line2.x - line1.x)), 
        y: line1.y + (r * (line2.y - line1.y))
    };
}

//Returns float, the shortest distance to the (infinite) line.
function calcDistancePointToLine(line1, line2, pnt) {
    var L2 = ( ((line2.x - line1.x) * (line2.x - line1.x)) + ((line2.y - line1.y) * (line2.y - line1.y)) );
    if(L2 == 0) return false;
    var s = (((line1.y - pnt.y) * (line2.x - line1.x)) - ((line1.x - pnt.x) * (line2.y - line1.y))) / L2;
    return Math.abs(s) * Math.sqrt(L2);
}

//Returns bool, whether the projected point is actually inside the (finite) line segment.
function calcIsInsideLineSegment(line1, line2, pnt) {
    var L2 = ( ((line2.x - line1.x) * (line2.x - line1.x)) + ((line2.y - line1.y) * (line2.y - line1.y)) );
    if(L2 == 0) return false;
    var r = ( ((pnt.x - line1.x) * (line2.x - line1.x)) + ((pnt.y - line1.y) * (line2.y - line1.y)) ) / L2;

    return (0 <= r) && (r <= 1);
}

//The most useful function. Returns bool true, if the mouse point is actually inside the (finite) line, given a line thickness from the theoretical line away. It also assumes that the line end points are circular, not square.
function calcIsInsideThickLineSegment(line1, line2, pnt, lineThickness) {
    var L2 = ( ((line2.x - line1.x) * (line2.x - line1.x)) + ((line2.y - line1.y) * (line2.y - line1.y)) );
    if(L2 == 0) return false;
    var r = ( ((pnt.x - line1.x) * (line2.x - line1.x)) + ((pnt.y - line1.y) * (line2.y - line1.y)) ) / L2;

    //Assume line thickness is circular
    if(r < 0) {
        //Outside line1
        return (Math.sqrt(( (line1.x - pnt.x) * (line1.x - pnt.x) ) + ( (line1.y - pnt.y) * (line1.y - pnt.y) )) <= lineThickness);
    } else if((0 <= r) && (r <= 1)) {
        //On the line segment
        var s = (((line1.y - pnt.y) * (line2.x - line1.x)) - ((line1.x - pnt.x) * (line2.y - line1.y))) / L2;
        return (Math.abs(s) * Math.sqrt(L2) <= lineThickness);
    } else {
        //Outside line2
        return (Math.sqrt(( (line2.x - pnt.x) * (line2.x - pnt.x) ) + ( (line2.y - pnt.y) * (line2.y - pnt.y) )) <= lineThickness);
    }
}
Run Code Online (Sandbox Code Playgroud)

要使用不错的SVG来查看其中的某些代码,请参阅我用来调试的小提琴:https : //jsfiddle.net/c06zdxtL/2/