从具有给定角度θ的点绘制线

时间:2013-12-29 19:15:51

标签: c# winforms graphics gdi+

用一定程度或角度绘制一条直线的最佳方法是什么。

例如,如果x=y那么这意味着点数为45度。 展示 enter image description here

但是我想将θ作为参数并在循环中绘制一个θ度的线,我有以下代码,但我不知道如何继续。

您能解释一下影响θ点数的最佳方法吗?

public struct MyPoint
{
    public double X { set; get; }
    public double Y { set; get; }

    public PointF ToPoint()
    {
        return new PointF((float)X, (float)Y);
    }
}

public partial class Form1 : Form
{
    List<MyPoint> points;
    public Form1()
    {
        InitializeComponent();

        // Initialize points to draw
        //-----------THIS IS PART TO DRAW LINE x=i and y = i meaning θ=45
        // [x,y] = [xcos(θ)−ysin(θ),xsin(θ)+ycos(θ)] 
        points=new List<MyPoint>(100);
        for (int i=0; i<=100; i++)
        {
            double θ=45;
            double x=i; //(i * Math.Cos(θ) - i * Math.Sin(θ));
            double y=i; //(i *Math.Sin(θ) + i * Math.Cos(θ));
            points.Add(new MyPoint() { X=x, Y=y });
        }
        //------------------------------
    }

    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        // smooth graphics
        e.Graphics.SmoothingMode=SmoothingMode.AntiAlias;            
        // set margins inside the control client area in pixels
        var margin=new System.Drawing.Printing.Margins(16, 16, 16, 16);
        // set the domain of (x,y) values
        var range=new RectangleF(-3, -3, 6, 6);
        // scale graphics
        ScaleGraphics(e.Graphics, pictureBox1, range, margin);            
        // convert points to pixels
        PointF[] pixels=points.Select((v) => v.ToPoint()).ToArray();
        // draw arrow axes
        using (var pen=new Pen(Color.Black, 0))
        {
            pen.EndCap=System.Drawing.Drawing2D.LineCap.ArrowAnchor;
            e.Graphics.DrawLine(pen, range.Left, 0.0f, range.Right, 0.0f);
            e.Graphics.DrawLine(pen, 0.0f, range.Top, 0.0f, range.Bottom);
        }
        // draw bounding rectangle (on margin)
        using (var pen=new Pen(Color.LightGray, 0))
        {
            pen.DashStyle=DashStyle.Dash;
            e.Graphics.DrawRectangle(pen, Rectangle.Round(range));
        }
        // draw curve
        using (var pen = new Pen(Color.Blue, 0))
        {                
            //e.Graphics.DrawLines(pen, pixels);
            e.Graphics.DrawCurve(pen, pixels);
        }            
    }
    /// <summary>
    /// Scales the Graphics to fit a Control, given a domain of x,y values and side margins in pixels
    /// </summary>
    /// <param name="g">The Graphics object</param>
    /// <param name="control">The Control</param>
    /// <param name="domain">The value domain</param>
    /// <param name="margin">The margin</param>
    void ScaleGraphics(Graphics g, Control control, RectangleF domain, Margins margin)
    {
        // Find the drawable area in pixels (control-margins)
        int W=control.Width-margin.Left-margin.Right;
        int H=control.Height-margin.Bottom-margin.Top;
        // Ensure drawable area is at least 1 pixel wide
        W=Math.Max(1, W);
        H=Math.Max(1, H);
        // Find the origin (0,0) in pixels
        float OX=margin.Left-W*(domain.Left/domain.Width);
        float OY=margin.Top+H*(1+domain.Top/domain.Height);
        // Find the scale to fit the control
        float SX=W/domain.Width;
        float SY=H/domain.Height;
        // Transform the Graphics
        g.TranslateTransform(OX, OY);
        g.ScaleTransform(SX, -SY);
    }

    private void pictureBox1_SizeChanged(object sender, EventArgs e)
    {
        // redraw on resize
        pictureBox1.Refresh();
    }
}

1 个答案:

答案 0 :(得分:2)

让线坐标以一定角度穿过一个点是很容易的部分。找到要包含在显示矩形中的行的终点稍微复杂一些。

通过角度θ的点P=(xp,yp)的直线满足等式

(x-xp)*SIN(θ)-(y-yp)*COS(θ) = 0

以参数形式,上面是

P(t) = ( xp+t*COS(θ), yp+t*SIN(θ) )

其中t是从 P 点开始的距离。

因此,如果您想要一条线跨越整个绘图边界(代码中的range变量),您必须找到哪个t对应于顶部,底部,左侧和右侧边界并在中间的两个。

// example angle at 15° through xp=2.0, yp=1.0
RectangleF range = new RectangleF(-3.0,-3.0, 6.0, 6.0);
double xp=2.0, yp=1.0;
double θ = 15.0*(Math.PI/180);   
// If angle is 0°, 90° etc, the following will fail
double[] t = new double[4];
t[0] = (range.Left-xp)/Math.Cos(θ);
t[1] = (range.Right-xp)/Math.Cos(θ);
t[2] = (range.Top-yp)/Math.Sin(θ);
t[3] = (range.Bottom-yp)/Math.Sin(θ);
Array.Sort(t);
// pick middle two points
var A = new MyPoint() { X = xp+t[1]*Math.Cos(θ), Y = yp+t[1]*Math.Sin(θ) };
var B = new MyPoint() { X = xp+t[2]*Math.Cos(θ), Y = yp+t[2]*Math.Sin(θ) };
g.DrawLine(pen, A.ToPoint(), B.ToPoint());