Search code examples
c#unity-game-enginehittest

Detect point on wide line


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


Solution

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