Reputation: 13790
I have a winforms application
Here is my code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication12
{
public partial class Form1 : Form
{
Graphics gr;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
gr = this.CreateGraphics();
MyLine myline = new MyLine();
myline.P1 = new Point(100, 0);
myline.P2 = new Point(200, 80);
gr.DrawLine(new Pen(Color.Red), myline.P1,myline.P2);
Rectangle r = new Rectangle(0, 0, 50, 50);
gr.DrawRectangle(new Pen(Color.Teal, 5), r);
if (r.Contains(0,25)) MessageBox.Show("within");
}
private void btnClear_Click(object sender, EventArgs e)
{
gr.Clear(this.BackColor);
}
}
}
class MyLine
{
public Point P1 {get; set;}
public Point P2 { get; set; }
}
My problem is this..
I can draw a rectangle, and I can see whether a point is within it.
So I could extend the program to say "yes" when a click on the form is within the rectangle. The Rectangle has a Contains function which is great.
But I want to do the same for Line.
The problem, is that winforms has no Line class. I could write my own Line class, but the problem remains.. how to find whether a click landed on it?
I notice that WPF has such a class How do I recognize a mouse click on a line?
But i'm using winforms.
Upvotes: 3
Views: 3755
Reputation: 125292
Using GraphicsPath.IsOutlineVisible
method you can determine whether the specified point is under the outline of the path when drawn with the specified Pen
. You can set width of the pen.
So you can create a GraphicsPath
and then add a line using GraphicsPath.AddLine
to the path and check if the path contains the point.
Example:
The below method, checks if the p
is on the line with end points p1
and p2
using the specified width.
You can use wider width to increase the tolerance or if the line is wider than 1:
//using System.Drawing;
//using System.Drawing.Drawing2D;
bool IsOnLine(Point p1, Point p2, Point p, int width = 1)
{
using (var path = new GraphicsPath())
{
using (var pen = new Pen(Brushes.Black, width))
{
path.AddLine(p1, p2);
return path.IsOutlineVisible(p, pen);
}
}
}
Upvotes: 6
Reputation: 4945
I implemented a simple Line
class to check if a dot fall on the line.
You can capture a mouse position out of Form_Click
event
Here's the snippet
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication
{
public partial class Form1 : Form
{
Line myLine;
int x1 = 10;
int x2 = 40;
int y1 = 0;
int y2 = 30;
public Form1()
{
InitializeComponent();
myLine = new Line() { Start = new Point(x1, y1), Stop = new Point(x2, y2), Epsilon = 10 };
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Pen pen = new Pen(Color.FromArgb(255, 0, 0, 0));
e.Graphics.DrawLine(pen, x1, y1, x2, y2);
pen.Dispose();
}
private void Form1_Click(object sender, EventArgs e)
{
MouseEventArgs me = (MouseEventArgs)e;
bool contain = myLine.contain(new Point(me.X,me.Y));
}
}
public class Line
{
public Point Start { get; set; }
public Point Stop { get; set; }
public float Epsilon { get; set; }
public bool contain(Point p)
{
// y = mx + c
float m = (Stop.Y - Start.Y) / (Stop.X - Start.X);
float c = Stop.Y - (m * Stop.X);
return p.X >= Math.Min(Start.X, Stop.X)
&& p.X <= Math.Max(Start.X, Stop.X)
&& p.Y >= Math.Min(Start.Y, Stop.Y)
&& p.Y <= Math.Max(Start.Y, Stop.Y)
&& Math.Abs(Math.Abs(p.Y) - Math.Abs((m * p.X) + c)) < epsilon; //with relax rules
//&& (p.Y == (m*p.X)+c); // strict version
}
}
UPDATE
careful of a case where X1 == X2. It will throw exception.
Upvotes: 1