2

我正在尝试制作一个简单的图表应用程序,但偶然发现了一个问题。我有一个点数组,代表 100 个点的 45 度线(y = x)。然后我尝试通过将每个点的值转换为其像素值来绘制线,然后使用graphic.DrawLines().

基本代码:

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

List<MyPoint> Values;
List<System.Drawing.Point> Points;

for (int i = 0; i < Values.Count; i++)
    {
        // convert point value to pixel coordinate
        int x = (int)((Values[i].X - MinimumX) * (double)Control.Width / (MaximumX - MinimumX) + 0.5);
        int y = (int)((Values[i].Y - MinimumY) * (double)Control.Height / (MaximumY - MinimumY)) + 0.5;

        Points.Add(new System.Drawing.Point(x, y));
    }

    graphic.DrawLines(pen, Points.ToArray());

注意:MaximumX 和 MaximumY 为 100(点数),最小值为 0。

问题是这种线不是很直:) 所以我的问题是,我如何通过这些点画一条直线,这样它看起来就像

graphic.DrawLine(pen, 0, 0, Control.Width-1, Control.Height-1);

提前致谢!

4

4 回答 4

2

由于您正在制作图表,因此我有一个基本框架用于在控件中拟合值,如下例所示:

表格1

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

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

/// <summary>
/// For http://stackoverflow.com/questions/19459519/drawing-a-straight-line-from-points
/// </summary>
public partial class Form1 : Form
{
    List<MyPoint> points;
    public Form1()
    {
        InitializeComponent();

        // Initialize points to draw
        points=new List<MyPoint>(100);
        for (int i=0; i<=100; i++)
        {
            double θ=2*Math.PI*(i/100.0);
            double x=(1+θ/Math.PI)*Math.Cos(θ);
            double y=(1+θ/Math.PI)*Math.Sin(θ);
            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();
    }
}
于 2013-10-19T03:15:18.370 回答
1

我认为问题在于您的积分是整数。精度丢失。

尝试使用

float x = (float)((Values[i] ...
List<System.Drawing.PointF> PointFs;

代替

int x = (int)((Values[i] ...
List<System.Drawing.Point> Points;
于 2013-10-18T22:14:39.617 回答
0

这是我的解决方案:

 System.Drawing.Pen myPen;
 myPen = new System.Drawing.Pen(System.Drawing.Color.Red);
 System.Drawing.Graphics formGraphics = this.CreateGraphics();
 formGraphics.DrawLine(myPen, 0, 0, 200, 200);
 myPen.Dispose();
 formGraphics.Dispose();
于 2015-03-17T10:19:19.553 回答
0

你可能需要这样的东西:

private void DrawLine()
{
    int xInitial = 0, yInitial = 0, xFinal = Control.Width - 1, yFinal = Control.Height - 1;
    int dx = xFinal - xInitial, dy = yFinal - yInitial, steps, k, xf, yf;
    float xIncrement, yIncrement, x = xInitial, y = yInitial;

    if (Math.Abs(dx) > Math.Abs(dy))
        steps = Math.Abs(dx);
    else 
        steps = Math.Abs(dy);

    xIncrement = dx / (float)steps;
    yIncrement = dy / (float)steps;

    for (k = 0; k < steps; k++)
    {
        x += xIncrement;
        xf = (int)x;
        y += yIncrement;
        yf = (int)y;

        Points.Add(new System.Drawing.Point(xf, yf));
    }
    graphic.DrawLines(pen, Points.ToArray());
}

更多细节参见: Bresenham's line algorithm

如果您的积分已经通过算法正确计算,那么简单:

int x = (int) Values[i].X;
int y = (int) Values[i].Y;

应该够了。

于 2013-10-18T22:14:03.463 回答