views:

296

answers:

3

How do I detect collision on line, preferably with mouse click?

I don't use XNA. I use just simple WinForms. And I'm not creating a game.

EDIT: I implemented solution from brone link and got really weird results. Here's small snippet. What I'm doing wrong? Pastebin link

+1  A: 

If you're able to use linear algebra, then you'll want to detect the distance from your test point, to the nearest point on your line segment.

  • Let AB be your line Segment.
  • Let C be your mouse point.
  • Let D be a point on AB such that the line segment CD is minimal.

You want to find the length of CD. Since AB and CD are perpendicular, you know that the slope of AB is the inverse reciprocal of the slope of CD. You know C, and a slope, so you can find the general equation for CD. Then, find the intersection of AB and CD, giving you point D.

Once you have point D, finding the length of CD is trivial. If this distance is less than some threshold value, then you know you've clicked near the line segment you're interested in.

Charlie Salts
+4  A: 

Minimum Distance between a Point and a Line:

http://local.wasp.uwa.edu.au/~pbourke/geometry/pointline/

More referenece material in his general geometry section:

http://local.wasp.uwa.edu.au/~pbourke/geometry/

brone
+1 for saying 'go learn geometry if you want to write a game' without having to actually say it ;)
csharptest.net
Well I was taught parametric definitions of ray in school, I understood it, but it wasn't explained that I could apply that knowledge on this subject.
mnn
I implemented solution on that page, but I got really weird distances between line and mouse like -64321 or so. Here's the code: http://pastebin.com/m3bf3aeac
mnn
It looks as if where 'u' is calculated there are some missing parentheses to sort out the precedence. I submitted an amendment (assuming I'm right).Also note that calculation of length^2 is a bit inefficient, you could just dot the vector against itself and avoid a square root.
brone
A: 

Well, I won't bother explaining it since I don't remember how this works. But I wrote this in C++ back in ... uh... 1995-ish. I'm certain there are much more elegant ways of doing this since I'd only been writing code for about two years at the time. Anyway here it is converted to C#:

static bool PointHitSegment(Point[] line, Point hitPoint, int errorMargin)
{
 if (hitPoint.X >= (Math.Max(line[0].X, line[1].X) + errorMargin) ||
  hitPoint.X <= (Math.Min(line[0].X, line[1].X) - errorMargin) ||
  hitPoint.Y >= (Math.Max(line[0].Y, line[1].Y) + errorMargin) ||
  hitPoint.Y <= (Math.Min(line[0].Y, line[1].Y) - errorMargin))
  return false;

 if (line[0].X == line[1].X || line[0].Y == line[1].Y)
  return true;

 double y1, y2, x1, x2;
 double m, b;
 int ny;

 if (Math.Abs(line[0].Y - line[1].Y) <= Math.Abs(line[0].X - line[1].X))
 {
  y1 = line[0].Y;
  y2 = line[1].Y;
  x1 = line[0].X;
  x2 = line[1].X;
 }
 else
 {
  y1 = line[0].X;
  y2 = line[1].X;
  x1 = line[0].Y;
  x2 = line[1].Y;

  int tmp = hitPoint.Y;
  hitPoint.Y = hitPoint.X;
  hitPoint.X = tmp;
 }

 m = (y2 - y1) / (x2 - x1);
 b = y1 - m * x1;

 ny = (int)((m * ((double)hitPoint.X) + b) + 0.5);

 if (Math.Abs(hitPoint.Y - ny) > errorMargin)
  return false;

 return true;
}
csharptest.net