如何使用鼠标画线和每 5 度锁定角度

How to drawline using mouse and locking angle each 5 degrees

我有一个问题,我需要使用鼠标画一条线并每 5 度锁定一次角度。

我可以水平和垂直锁定线,但我无法锁定角度

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();
}

在上面的代码中,我在按住 ctrl 时锁定到 0 度,在按住 shift + ctrl 时锁定到 90 度。 但是我需要允许用户将线移动 5 度,如果他愿意的话,我不知道该怎么做。

有人能帮帮我吗? 对不起我的英语。

编辑----------------

我想我解决了问题,但还有一个细节。

使用follow方法移动鼠标可以旋转5度

 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)
            };
        }

我这样调用 mouseMove 事件中的方法:

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);

所以我有一条线,从 0 度开始,如果我向上移动鼠标,它会变成 5 度,如果我向下移动,它会变成 -5 度。完美的!但是,如果我继续向上或向下移动鼠标,倾斜度不会增加 5 度。也就是说,我只能向上或向下移动5度一次。

如何在移动鼠标时保持线条旋转?

编辑--------------------

好的,我在@amin29 a 的帮助下得到了它。谢谢队友!

_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;

使用这些方法

    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);
    }

你的代码应该是这样的

        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();
        }

编辑---------------------------------------- -------------- 检查此代码,它是 windows 形式

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;
    }

}

编辑---------- 我编辑了你的代码以获得更好的性能,如果你想使用左键单击,你可以添加 MouseUp 和 MouseDown 事件。 (如果您的 canvas 有 DoubleBuffered 属性 将其设置为 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);
    }

}