Detect point on wide line

102 Views Asked by At

I would like to be able to detect click on a wide line. I've got a function taken from there which manages to detect if a point is exactly on it, but I'd like to add some tolerance to detect click on all the rendered line.

Here is my current function, (taken from there Determine if a point is between 2 other points on a line) :

    public bool PointIsOnLine(Vector2 currPoint, UILineRenderer line)
{
    Vector2 point1 = line.points[0];
    Vector2 point2 = line.points[1];

    float dxc = currPoint.x - point1.x;
    float dyc = currPoint.y - point1.y;

    float dxl = point2.x - point1.x;
    float dyl = point2.y - point1.y;

    float cross = dxc * dyl - dyc * dxl;

    if (cross != 0)
        return false;


    if (Mathf.Abs(dxl) >= Mathf.Abs(dyl))
        return dxl > 0 ?
          point1.x <= currPoint.x && currPoint.x <= point2.x :
          point2.x <= currPoint.x && currPoint.x <= point1.x;
    else
        return dyl > 0 ?
          point1.y <= currPoint.y && currPoint.y <= point2.y :
          point2.y <= currPoint.y && currPoint.y <= point1.y;
}

You can access the line's thickness using line.thickness

2

There are 2 best solutions below

5
JonasH On BEST ANSWER

To check if a point is near a line segment you would first find the projection of the point on the line:

var dirNorm = (point2 - point1).Normalized;
var t = Vector2.Dot(currPoint - point1, dirNorm );

Next step is to clamp the t value. If you have a line segment the limits should be [0, Length].

var tClamped = Mathf.Clamp(t, 0, (point2 - point1).Length); 

You can then convert it back to a point by

var closestPoint = point1 + dirNorm  * tClamped;

And you can then get the distance by

var dist = Vector2.Distance(currPoint, closestPoint);

Add a check to see if the distance is smaller than some value and you get your answer.

Note that you would want to keep things as vectors as much as possible. Don't go down to individual x/y values unless you absolutely have to. Unity3D have a fairly good selection of vector functions, use them! Also note that this could probably be optimized a bit, but it may be useful to divide this in individual functions, i.e. one function get the t-value, one to get the closest point, another to get the distance etc. These functions can probably be reused for other things.

0
Majellan On

Here is my (working) solution now, thanks to the help of @JonasH!

public bool PointIsOnLine(Vector3 point, UILineRenderer line)
    {
        Vector3 point1 = line.points[0];
        Vector3 point2 = line.points[1];

        var dirNorm = (point2 - point1).normalized;
        var t = Vector2.Dot(point - point1, dirNorm);
        var tClamped = Mathf.Clamp(t, 0, (point2 - point1).magnitude);
        var closestPoint = point1 + dirNorm * tClamped;

        var dist = Vector2.Distance(point, closestPoint);


        if(dist < line.thickness / 2)
        {
            return true;
        }

        return false;
    }