2013-10-18 89 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();