Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting if a point is of a line segment

If I have a line, with the points x,y,endx and endy how can I detect if another point is on the line? A simple equation, or example functions in JavaScript or pseudocode will be most helpful.

EDIT: This is for a game I'm working on, I'm trying to detect if a laser is colliding with an object, Here is the sample http://jefnull.com/references/lasers/ The file that will be most descriptive is http://jefnull.com/references/lasers/lasers.js

like image 801
Jef Null Avatar asked Jul 28 '11 21:07

Jef Null


People also ask

How do you determine if a point is on a line 3d?

Normalize the vectors. Check if the normals match. Find the greatest value, divide all of the other values by that value so you get a vector normal. Any point on a line should have the same vector normal.

How do you find if a point lies between two points?

The simplest is as follows. if (x-x1)/(x2-x1) = (y-y1)/(y2-y1) = alpha (a constant), then the point C(x,y) will lie on the line between pts 1 & 2.

What is the line segment formula?

Line Segment Formula Now, let us see how to find the length of a line segment when the coordinates of the two endpoints are given. In this case, we use the distance formula, that is, D = √[(x2−x1 x 2 − x 1 )2 + (y2−y1 y 2 − y 1 )2].


2 Answers

You want to check whether the slopes are the same between the pairs of points. But you should be careful not to ever divide by zero, so check by checking the cross-multiplied version of the equations.

More explicitly, if your points are A = (Ax, Ay), B = (Bx, By), C = (Cx, Cy), then you would like to check that

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

But instead you should check that

(Cy - Ay)  * (Bx - Ax) = (By - Ay) * (Cx - Ax).
like image 51
Chris Cunningham Avatar answered Oct 06 '22 18:10

Chris Cunningham


First of all, the answer provided by Razack was the most mathematically sound answer, though highly theoretical. If you are upvoting this answer, please consider upvoting his answer too.

I have implemented his methods in the following useful javascript functions. Have a look in particular at function calcIsInsideThickLineSegment(...). Use as you please.

//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);
    }
}

To see some of this code in action using a nice SVG, see this fiddle which I used to debug: https://jsfiddle.net/c06zdxtL/2/

like image 24
Florian Mertens Avatar answered Oct 06 '22 18:10

Florian Mertens