SOLVED point_in_line?

Mehdi

Member
Hello,
Does anyone know how to write a script that checks whether a point is in collision with a line?
GM has the function
GML:
collision_line
, but that one looks for an object in contact with a line. Whereas, the thing I want is checking the line against a point.
Furthermore, there are functions :
Code:
point_in_circle
,
Code:
point_in_triangle
and
Code:
point_in_rectangle
But there isn't any for point_in line.

Could you please help me?
 

Nobody

Member
Code:
s = (y2 - y1) * x + (x1 - x2) * y + (x2 * y1 - x1 * y2);
x & y is the point to test. If s equals zero, the point is on the line.

I haven’t tested this, as I don’t have GMS open. But see how it goes,
 

Bart

WiseBart
A line defines the set of points given by an equation of the form y = m * x + q. So if you want to know if a point is on a line (technically it can't be in since a line has no width) you fill in the point's coordinates (x and y) in the line's equation. If the result makes sense then that point is on the line.
So you calculate m * x + q - y for a given x and y. From the above equation you see that that result should be equal to zero.
 
Last edited:

Amon

Member
I don't know how you guys are able to comprehend this kind of math. I'm bowing to your math skills.
 

Nobody

Member
I don't know how you guys are able to comprehend this kind of math. I'm bowing to your math skills.
I googled it. :p

 

Mehdi

Member
Code:
s = (y2 - y1) * x + (x1 - x2) * y + (x2 * y1 - x1 * y2);
x & y is the point to test. If s equals zero, the point is on the line.

I haven’t tested this, as I don’t have GMS open. But see how it goes,
Thanks "Nobody"! Your solution seems smart!
However I want the collision exactly in between 2 points, whereas your equation accepts the point on the extension of the line too.
 

Mehdi

Member
A line defines the set of points given by an equation of the form y = m * x + q. So if you want to know if a point is on a line (technically it can't be in since a line has no width) you fill in the point's coordinates (x and y) in the line's equation. If the result makes sense then that point is on the line.
So you calculate m * x + q - y for a given x and y. From the above equation you see that that result should be equal to zero.
Thanks bart.
But this kind of equation covers the points on the extension of the line too. The thing that I need is the point right between two specific points, not on the extension of it.
 

TheSnidr

Heavy metal viking dentist
GMC Elder
An arbitrary point will "never" fall onto an arbitrary line (in fact, the chance of a random point being exactly on a line is infinitesimal), so checking whether or not a point is on a line will pretty much always be false unless the point has been defined to be on that line.
It's much more interesting to check for the distance between a point and a line, and check whether that distance is less than some threshold value. This will give your line some thickness.
Projecting the vector from one of the line's endpoints to the coordinate onto the line itself gives you the closest coordinate on the line to the point you're checking. Then you can use point_distance to find the distance between them, and compare that to the threshold:
Code:
function pointOnLine(x, y, x1, y1, x2, y2, lineThickness, rounded = false, infinite = false)
{
    //Find the dot product between the line vector and the vector from the first endpoint to the coordinate we're checking
    var t = dot_product(x2 - x1, y2 - y1, x - x1, y - y1);

    //Divide t by the square of the length of the line segment so that a coordinate at (x1, y1) corresponds to 0, and a coordinate at (x2, y2) corresponds to 1
    t /= dot_product(x2 - x1, y2 - y1, x2 - x1, y2 - y1);

    //Clamp t so that it is always between 0 and 1
    if (!infinite)
    {
        if (rounded)
        {
            //Rounded edges
            t = clamp(t, 0, 1);
        }
        else if (t < 0 || t > 1)
        {
            //Flat edges
            return false;
        }
    }

    //Find the projected coordinates on the line segment
    var px = lerp(x1, x2, t);
    var py = lerp(y1, y2, t);

    //Find the distance between the point and the line segment
    var d = point_distance(x, y, px, py);

    //Check if the distance is above some threshold value, ie. the thickness of the line
    if (d > lineThickness){return false;}

    return true;
}
Edit: Code is untested, may have typos
Edit2: t was wrong, it has to be divided by the square of the length of the line segment
Edit3: Code is now tested and optimized slightly. Added options for rounded or flat line segments.
 
Last edited:

Alice

Darts addict
Forum Staff
Moderator
To check strictly between the ends of the line, you can check for x >= xlow && x <= xhi, where "xlow" and "xhi" are minimum and maximum values of x1/x2, respectively. To account for strictly vertical line (where every point has the same x coordinate) you can check for y >= ylow && y <= yhi too (so the whole condition would be "x between xlow and xhi AND y between ylow and yhi").
 

Mehdi

Member
//Find the dot product between the line vector and the vector from the first endpoint to the coordinate we're checking var t = dot_product(x2 - x1, y2 - y1, x - x1, y - y1); //Divide t by the square of the length of the line segment so that a coordinate at (x1, y1) corresponds to 0, and a coordinate at (x2, y2) corresponds to 1 t /= sqr(point_distance(x1, y1, x2, y2)); //Clamp t so that it is always between 0 and 1. If your line should extend infinitely in either direction you can skip this step! t = clamp(t, 0, 1); //Find the projected coordinates on the line segment var px = lerp(x1, x2, t); var py = lerp(y1, y2, t); //Find the distance between the point and the line segment var d = point_distance(x, y, px, py); //Check if the distance is below some threshold value, ie. the thickness of the line if (d < lineThickness){return true;}
Thank you @TheSnidr
However it doesn't work as expected. Could you please double check whether something is wrong in the formulas.
 

TheSnidr

Heavy metal viking dentist
GMC Elder
Excellent!
The shape of the line will be rounded at the edges if you do it like I posted. If you instead want perfectly flat edges, you can do this instead of clamping:
Code:
if (t < 0 || t > 1){return false;}
 

Mehdi

Member
Excellent!
The shape of the line will be rounded at the edges if you do it like I posted. If you instead want perfectly flat edges, you can do this instead of clamping:
Code:
if (t < 0 || t > 1){return false;}
Thank you again and yes, flat edges were needed. 🙏
 
Top