2013-10-18 74 views
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); 

在此先感谢!

+1

为什么你需要转换为像素坐标? – HappyLee

+0

它看起来像你要求一个最合适的线:[散点图'最适合'线的算法](http://stackoverflow.com/questions/12946341/algorithm-for-scatter-plot-best-fit -线)。 –

+0

@HappyLee我怀疑OP意味着屏幕坐标而不是像素坐标。 –

回答

1

我认为这个问题是因为你的观点是整数。精确度失去了。

尝试使用

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

,而不是

int x = (int)((Values[i] ... 
List<System.Drawing.Point> Points; 
+0

Lol,没有注意到DrawLine也使用PointF。是的,这解决了这个问题。虽然其他答案是有用的信息,我很感激,这是目前我所需要的,并且是我需要做的最低限度的改变:)我想我提出这个问题有点过早了!谢谢! – rozina

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; 

应足够。

2

既然你是做图形,我有件值的基本框架,像这个例子中的控制范围内:

Form1

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