Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding if a point is on a line

Let's say I have a line drawn as so in HTML5 Canvas:

...
ctx.beginPath();
ctx.moveTo(x,y);
ctx.lineTo(x1,y1);
ctx.closePath();
...

I want to find out if the mouse down event happened on this line, and I have code like this:

var handleMouseDown = function(e) {
  var coords = translateCoords(e.x,e.y);
  ...
  if (ctx.isPointInPath(coords.x, coords.y) {
    ...

Now, this code works fine in the case of circles & rectangles, but not for lines. I have 2 questions:

  1. My thinking is that perhaps calling closePath() on a line itself is incorrect. Question - how can I check if the mouse down event happened on this line?

  2. How can I extend this to find if the mouse down event happened near the line?

like image 691
appa Avatar asked Dec 08 '22 18:12

appa


2 Answers

The first step is to find the normal projection of the point onto the line. This is actually quite simple: take the distance from point 1 to the target, and point 2 to the target, and call them D1 and D2 respectively. Then calculate D1+(D2-D1)/2. This is the distance to the projected point on the line from point 1.

You can now find that point, and get the distance from that point to the target. If the distance is zero, then the target is exactly on the line. If the distance is less than 5, then the target was less than 5px away, and so on.

EDIT: A picture is worth a thousand words. Here's a diagram:

Diagram
(source: adamhaskell.net)

(In hindsight, probably should have made those circles a different colour... Also, the purple line is supposed to be perpendicular to line AB. Blame my terrible aim with the blue line!)

like image 177
Niet the Dark Absol Avatar answered Dec 11 '22 09:12

Niet the Dark Absol


Here is the approach taken from Wikipedia article Distance from a point to a line (Line defined by two points)

        var Dx = x2 - x1;
        var Dy = y2 - y1;
        var d = Math.abs(Dy*x0 - Dx*y0 - x1*y2+x2*y1)/Math.sqrt(Math.pow(Dx, 2) + Math.pow(Dy, 2));

where (x0,y0) is your Point coordinates and your Line is ((x1,y1),(x2,y2)) However, this does not checks for boundaries of the line, so I had to add another check for it.

    function inBox(x0, y0, rect) {
        var x1 = Math.min(rect.startX, rect.startX + rect.w);
        var x2 = Math.max(rect.startX, rect.startX + rect.w);
        var y1 = Math.min(rect.startY, rect.startY + rect.h);
        var y2 = Math.max(rect.startY, rect.startY + rect.h);
        return (x1 <= x0 && x0 <= x2 && y1 <= y0 && y0 <= y2);
    }

Where your Line defined as rectangle. Hope this helps.

like image 38
user3175112 Avatar answered Dec 11 '22 08:12

user3175112