检测点是否属于线段

时间:2011-07-28 21:20:55

标签: javascript math pseudocode

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

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

7 个答案:

答案 0 :(得分:12)

由于我之前的回答是如何确定一个点是否 该行,并且真正的问题似乎是“我怎么能判断该点是否 “,我正在添加新答案。

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

Triangle with sides A, B, C

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

Acute and Obtuse Triangle Diagrams

那不对!!

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

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

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

  • 要查看(x,y)处的角度是否为钝角,请查找B^2 > A^2 + C^2。如果是这样,角度就会变钝。
  • 要查看(endx, endy)处的角度是否为钝角,请查找A^2 > B^2 + C^2。如果是这样,角度就会变钝。
  • 要计算H,请使用两种不同的方法来查找三角形的区域 - 通常为base*height/2Heron's Formula

这意味着你应该:

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)).

最终结果如下:

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))

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

答案 1 :(得分:7)

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

更明确地说,如果您的积分是A = (Ax, Ay)B = (Bx, By)C = (Cx, Cy),那么您想检查一下

(Cy - Ay)  / (Cx - Ax) = (By - Ay) / (Bx - Ax)

但你应该检查

(Cy - Ay)  * (Bx - Ax) = (By - Ay) * (Cx - Ax).

答案 2 :(得分:2)

function isOnLine(x, y, endx, endy, px, py) {
    var f = function(somex) { return (endy - y) / (endx - x) * (somex - x) + y; };
    return Math.abs(f(px) - py) < 1e-6 // tolerance, rounding errors
        && px >= x && px <= endx;      // are they also on this segment?
}

x, y, endx and endy是定义线的点,使用它可以构建该线的等式。然后,填写px并查看是否f(px) = py(实际上由于舍入错误而检查得足够小)。最后,检查是否在x ... endx区间定义了线段。

答案 3 :(得分:1)

根据直线方程y = mx + b,其中m是斜率,x是x轴处的点的值,b是y截距(线截距y轴的点)。

m(坡度)= endy - y / endx - x; 例如如果一条线从(0,0)开始并且结束(4,2)那么m = 4-0 / 2-0 = 2;

b(y截距)= 0;

现在例如,您将获得一个点(1,2),以查看它是否在线。好的,在x坐标的帮助下计算你的y坐标。即

y = mx + b

y = 2(1)+ 0; //这里x是给定点的x坐标 y = 2;这与您给定点的y坐标完全相同,因此我们可以得出结论。如果该点具有根据等式的值(2,2),则它将评估为y = 4,其不等于您给出的点的y坐标,因此它不在线上。

    function isOnLine(initial_x, initial_y, endx, endy, pointx, pointy, tolerate) {
         var slope = (endy-initial_y)/(endx-initial_x);
         var y = slope * pointx + initial_y;

         if((y <= pointy+tolerate && y >= pointy-tolerate) && (pointx >= initial_x && pointx <= endx)) {
             return true;
         }
         return false;
    }

答案 4 :(得分:1)

function is_point_on_segment (startPoint, checkPoint, endPoint) {

    return ((endPoint.y - startPoint.y) * (checkPoint.x - startPoint.x)).toFixed(0) === ((checkPoint.y - startPoint.y) * (endPoint.x - startPoint.x)).toFixed(0) &&
            ((startPoint.x > checkPoint.x && checkPoint.x > endPoint.x) || (startPoint.x < checkPoint.x && checkPoint.x < endPoint.x)) &&
            ((startPoint.y >= checkPoint.y && checkPoint.y >= endPoint.y) || (startPoint.y <= checkPoint.y && checkPoint.y <= endPoint.y));


}

测试:

var startPoint = {x:30,y:30};
var checkPoint = {x:40,y:40};
var endPoint = {x:50,y:50};

console.log(is_point_on_segment(startPoint ,checkPoint ,endPoint ));

答案 5 :(得分:0)

设点为C(Cx,Cy),线为AB(Ax,Ay)至(Bx,By)。     设P是C在AB上的垂直投影点。参数     r表示P沿AB的位置,由点积计算     AC和AB除以AB长度的平方:

(1)     AC dot AB
r = ---------  
||AB||^2

r has the following meaning:

r=0      P = A
r=1      P = B
r<0      P is on the backward extension of AB
r>1      P is on the forward extension of AB
0<r<1    P is interior to AB

The length of a line segment in d dimensions, AB is computed by:

L = sqrt( (Bx-Ax)^2 + (By-Ay)^2 + ... + (Bd-Ad)^2)

so in 2D:   

L = sqrt( (Bx-Ax)^2 + (By-Ay)^2 )

and the dot product of two vectors in d dimensions, U dot V is computed:

D = (Ux * Vx) + (Uy * Vy) + ... + (Ud * Vd)

so in 2D:   

D = (Ux * Vx) + (Uy * Vy) 

So (1) expands to:

(Cx-Ax)(Bx-Ax) + (Cy-Ay)(By-Ay)
r = -------------------------------
L^2

The point P can then be found:

Px = Ax + r(Bx-Ax)
Py = Ay + r(By-Ay)

And the distance from A to P = r*L.

Use another parameter s to indicate the location along PC, with the 
following meaning:
s<0      C is left of AB
s>0      C is right of AB
s=0      C is on AB

Compute s as follows:

(Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay)
s = -----------------------------
L^2


Then the distance from C to P = |s|*L.

答案 6 :(得分:0)

这是我对isOnLine的实现

function isOnLine(a, b, p, tolerance) {
    var dy = a.y - b.y;
    var dx = a.x - b.x;
    if(dy == 0) { //horizontal line
        if(p.y == a.y) {
            if(a.x > b.x) {
                if(p.x <= a.x && p.x >= b.x)
                    return true;
            }
            else {
                if(p.x >= a.x && p.x <= b.x)
                    return true;
            }
        }
    }
    else if(dx == 0) { //vertical line
        if(p.x == a.x) {
            if(a.y > b.y) {
                if(p.y <= a.y && p.y >= b.y)
                    return true;
            }
            else {
                if(p.y >= a.y && p.y <= b.y)
                    return true;
            }
        }
    }
    else { //slope line
        var p = dy/dx;
        var py = p * p.x;
        if(py <= p.y + tolerance && py >= p.y - tolerance) {
            if(a.x > b.x) {
                if(p.x <= a.x && p.x >= b.x)
                    return true;
            }
            else {
                if(p.x >= a.x && p.x <= b.x)
                    return true;
            }
        }
    }
    return false;
}