.NET Ascertaining mouse is on line drawn between two arbitrary points
If you want to easly make hit tests on arbitrary drawn shapes, you can create a path containing your drawing, then widden the path and make a visibility test using only framework functions.
For instance, here we create a path with a line:
GraphicsPath path = new GraphicsPath();
path.AddLine(x1, y1, x2, y2);
path.CloseFigure();
Then, widen the path and create a region for the hit test:
path.Widen(new Pen(Color.Black, 3));
region = new Region(path);
Finally, the hit test:
region.IsVisible(point);
The advantage of that method is it can easily extend to splines, arrows, arc, pies or pretty much anything drawable with GDI+. The same path can be used in both the HitTest
and Draw
logic by extracting it.
Here is the code combining it all:
public GraphicsPath Path
{
get {
GraphicsPath path = new GraphicsPath();
path.AddLine(x1, y1, x2, y2);
path.CloseFigure();
return path;
}
}
bool HitTest(Point point)
{
using(Pen new pen = Pen(Color.Black, 3))
using(GraphicsPaht path = Path)
{
path.Widen(pen);
using(Region region = new Region(path))
return region.IsVisible(point);
}
}
void Draw(Graphics graphics)
{
using(Pen pen = new Pen(Color.Blue, 0))
using(GraphicsPaht path = Path)
graphics.DrawPath(pen, path);
}
To answer "Is the mouse hovering over this line?", you need to check for point-line intersection. However, since you're asking "is the mouse near the line?", it sounds like you want to calculate the distance between the mouse point and the line.
Here's a reasonably thorough explanation of point-line distance: http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html
I'd say you need to implement this formula in your code: (stolen from wolfram.com)
Where:
- (x0, x0) is the location of the mouse pointer
- (x1, y1) is one end of the line
- (x2, y2) is the other end of the line
|n|
isMath.Abs(n)
- The bottom half is
Math.Sqrt
- You can ignore the
|v.r|
if you want
I would calculate the Slope-Intercept equation (y = mx + b) for my line and then use that to test the mouse coordinates. You could easily put a range around y to see if you're "close."
Edit for sample.
I think something like this works:
PointF currentPoint;
PointF p1, p2;
float threshold = 2.0f;
float m = (p1.Y - p2.Y) / (p1.X - p2.X);
float b = p1.Y - (m * p1.X);
if (Math.Abs(((m * currentPoint.X) + b) - currentPoint.Y) <= threshold)
{
//On it.
}