I have a problem where I need to draw a line using a mouse and lock the angle every 5 degrees.
I can lock the line horizontally and vertically but I can't lock in an angle
if (e.Button == MouseButtons.Left)
{
if (e.Button != MouseButtons.Left)
{
return;
}
startLine = new Point();
endLine = new Point();
if (ModifierKeys == Keys.Control)
{
pointLineDest = new Point(e.X, pointLineOrigin.Y);
}
else if (ModifierKeys == (Keys.Control | Keys.Shift))
{
pointLineDest = new Point(pointLineOrigin.X, e.Y);
}
else
{
pointLineDest = e.Location;
Globals.AddOutputLog($"{CalculeAngle(pointLineOrigin, pointLineDest)}");
}
startLine = new Point(pointLineOrigin.X, pointLineOrigin.Y);
endLine = new Point(pointLineDest.X, pointLineDest.Y);
canvas.Refresh();
}
in the above code i lock to 0 degree when hold ctrl and hold 90 degree when hold shift + ctrl. But I need to allow the user to move the line 5 degrees if he wants and I have no idea how to do that.
Can anyone help me, please? sorry for my English.
Edit -----------------
I think I solved the problem but there is still a detail.
Using the follow method i can rotate 5 degrees when i move the mouse.
static Point RotatePoint(Point pointToRotate, Point centerPoint, double angleInDegrees)
{
double angleInRadians = angleInDegrees * (Math.PI / 180);
double cosTheta = Math.Cos(angleInRadians);
double sinTheta = Math.Sin(angleInRadians);
return new Point
{
X = (int)(cosTheta * (pointToRotate.X - centerPoint.X) -
sinTheta * (pointToRotate.Y - centerPoint.Y) + centerPoint.X),
Y = (int)(sinTheta * (pointToRotate.X - centerPoint.X) +
cosTheta * (pointToRotate.Y - centerPoint.Y) + centerPoint.Y)
};
}
I call the method inside mouseMove event like this:
Point tempP = new Point(e.X, pointLineOrigin.Y);
int dy = e.Y - pointLineOrigin.Y;
int dir = (dy > 0) ? -1 : 1;
if (dir == -1)
pointLineDest = RotatePoint(tempP, pointLineOrigin, -5);
else
pointLineDest = RotatePoint(tempP, pointLineOrigin, 5);
startLine = new Point(pointLineOrigin.X, pointLineOrigin.Y);
endLine = new Point(pointLineDest.X, pointLineDest.Y);
So I have a line that starts at 0 degrees and if I move the mouse up it changes to 5 degrees, if I move down it changes to -5 degrees. Perfect! But if I keep moving the mouse up or down it doesn't increase the incline by 5 degrees. That is, I can only move 5 degrees up or down once.
How can I keep the line rotating as I move the mouse?
Edit --------------------
Ok, i got it with help from @amin29 a. Thank you mate!
_rad5 = DegreeToRadian(5);
float rad = (float)Math.Atan2(e.Y - pointLineOrigin.Y, e.X - pointLineOrigin.X);
int x = pointLineOrigin.X;
int y = pointLineOrigin.Y;
float angle = rad;
double step = _rad5;
double finalAngle;
double c = rad % _rad5;
finalAngle = angle - c;
if (c > step / 2)
finalAngle = (angle - c) + step;
double length = Math.Sqrt((Math.Pow(pointLineOrigin.X - e.X, 2) + Math.Pow(pointLineOrigin.Y - e.Y, 2)));
// Create points that define line.
Point point1 = new Point(x, y);
Point point2 = new Point((int)(x + Math.Cos(finalAngle) * length), (int)(y + Math.Sin(finalAngle) * length));
startLine = point1;
endLine = point2;
use these methods
private double DegreeToRadian(double degree)
{
return degree * Math.PI / 180;
}
private Point LockInAngle(Point pt, double degree)
{
int y = (int)(pt.X * Math.Tan(DegreeToRadian(degree)));
return new Point(pt.X, y);
}
and your code shoud be like this
if (e.Button == MouseButtons.Left)
{
startLine = new Point();
endLine = new Point();
if (ModifierKeys == Keys.Control)
{
pointLineDest = new Point(e.X, pointLineOrigin.Y);
}
else if (ModifierKeys == (Keys.Control | Keys.Shift))
{
pointLineDest = new Point(pointLineOrigin.X, e.Y);
}
else
{
pointLineDest = LockInAngle(e.Location, 5);
}
startLine = new Point(pointLineOrigin.X, pointLineOrigin.Y);
endLine = new Point(pointLineDest.X, pointLineDest.Y);
canvas.Refresh();
}
Edit --------------------------------------------------------- check this code ,it is windows forms
public partial class Form1 : Form
{
Point startLine;
Point endLine;
Point pointLineDest;
Point pointLineOrigin;
double _rad5;
public Form1()
{
InitializeComponent();
startLine = Point.Empty;
endLine = Point.Empty;
pointLineOrigin = new Point(Width / 2, Height / 2);
Paint += Form1_Paint;
SizeChanged += Form1_SizeChanged;
_rad5 = DegreeToRadian(5);
}
private void Form1_SizeChanged(object sender, EventArgs e)
{
pointLineOrigin = new Point(Width / 2, Height / 2);
Invalidate(false);
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; ;
e.Graphics.DrawLine(Pens.Red, startLine, endLine);
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (ModifierKeys == Keys.Control)
{
pointLineDest = new Point(e.X, pointLineOrigin.Y);
startLine = new Point(pointLineOrigin.X, pointLineOrigin.Y);
endLine = new Point(pointLineDest.X, pointLineDest.Y);
Invalidate(false);
}
else if (ModifierKeys == (Keys.Control | Keys.Shift))
{
pointLineDest = new Point(pointLineOrigin.X, e.Y);
startLine = new Point(pointLineOrigin.X, pointLineOrigin.Y);
endLine = new Point(pointLineDest.X, pointLineDest.Y);
Invalidate(false);
}
else
{
float rad =(float) Math.Atan2(e.Y - pointLineOrigin.Y, e.X - pointLineOrigin.X);
if (Math.Abs(rad % _rad5) < 0.005)
{
pointLineDest = e.Location;
startLine = new Point(pointLineOrigin.X, pointLineOrigin.Y);
endLine = new Point(pointLineDest.X, pointLineDest.Y);
Invalidate(false);
}
}
}
private double DegreeToRadian(double degree)
{
return degree * Math.PI / 180;
}
}
Edit---------- I edited your code for better performance and you can add MouseUp and MouseDown event if you want to work with left click. (If your canvas have DoubleBuffered property set it to true)
public partial class Form1 : Form
{
bool _isMouseDown;
Point startLine;
Point endLine;
Point pointLineDest;
Point pointLineOrigin;
float _rad5;
float _rad5DivideBy2;
public Form1()
{
InitializeComponent();
this.DoubleBuffered = true;
_rad5 = DegreeToRadian(5);
_rad5DivideBy2 = _rad5 / 2;
startLine = Point.Empty;
endLine = Point.Empty;
pointLineOrigin = new Point(Width / 2, Height / 2);
Paint += Form1_Paint;
SizeChanged += Form1_SizeChanged;
}
private void Form1_SizeChanged(object sender, EventArgs e)
{
pointLineOrigin = new Point(Width / 2, Height / 2);
Invalidate(false);
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bilinear;
e.Graphics.DrawLine(Pens.Red, startLine, endLine);
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
_isMouseDown = true;
}
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
_isMouseDown = false;
}
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (_isMouseDown)
{
if (ModifierKeys == Keys.Control)
{
pointLineDest = new Point(e.X, pointLineOrigin.Y);
startLine = new Point(pointLineOrigin.X, pointLineOrigin.Y);
endLine = new Point(pointLineDest.X, pointLineDest.Y);
Invalidate(false);
}
else if (ModifierKeys == (Keys.Control | Keys.Shift))
{
pointLineDest = new Point(pointLineOrigin.X, e.Y);
startLine = new Point(pointLineOrigin.X, pointLineOrigin.Y);
endLine = new Point(pointLineDest.X, pointLineDest.Y);
Invalidate(false);
}
else
{
int dx = e.X - pointLineOrigin.X;
int dy = e.Y - pointLineOrigin.Y;
float rad = (float)Math.Atan2(dy, dx);
if (rad < 0)
{
rad += (float)(2 * Math.PI);
}
float rem = rad % _rad5;
float finalAngle = rad - rem;
if (rem > _rad5DivideBy2)
{
finalAngle += _rad5;
}
float length = (float)Math.Sqrt(dx * dx + dy * dy);
pointLineDest = new Point((int)(Math.Cos(finalAngle) * length), (int)(Math.Sin(finalAngle) * length));
pointLineDest.Offset(pointLineOrigin);
startLine = new Point(pointLineOrigin.X, pointLineOrigin.Y);
endLine = new Point(pointLineDest.X, pointLineDest.Y);
Invalidate(false);
}
}
}
private float DegreeToRadian(float degree)
{
return (float)(degree * Math.PI / 180);
}
}