- C#示波器控件 ScopeV1.0
- // C#示波器控件 ScopeV1.0 測試版僅供參考
- // C# 2008
- // author: dzrjojo
- // date: 2010.07.28
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Drawing;
- using System.Drawing.Drawing2D;
- using System.Drawing.Imaging;
- using System.Data;
- using System.Linq;
- using System.Text;
- using System.Windows.Forms;
- using System.Threading;
- namespace Dongzr.WindPowerTool
- {
- public partial class Scope : UserControl
- {
- public const int INTERVAL = 1000; // 采樣時間間隔1000ms
- public const int MAX_CURVE_NUM = 10; // 示波器顯示最大曲線數為10
- private const int SCOPE_WIDTH = 500; // 示波器寬度
- private const int SCOPE_HEIGHT = 500; // 示波器高度
- private const int SCOPE_FRAME = 25; // 示波器邊框寬度
- private const int DATA_LENGTH = SCOPE_WIDTH; // 示波器最大采樣點數設為示波器寬度
- private Curve[] curve;
- // private ReaderWriterLock datas_lock; // 單線程不需要讀寫鎖
- private Brush brush;
- private Font font;
- private Pen white_dash_pen;
- private bool hold;
- private Bitmap bitmap;
- public Scope()
- {
- InitializeComponent();
- }
- // 添加曲線
- public bool CreateCurve(int id,Color color,string unit)
- {
- bool re = false;
- if (id >= 0 && id < MAX_CURVE_NUM)
- {
- // datas_lock.AcquireWriterLock(-1);
- if (this.curve[id] == null)
- {
- this.curve[id] = new Curve();
- }
- if (this.curve[id].show == false)
- {
- this.curve[id].Init(true, color, DATA_LENGTH, INTERVAL, unit);
- re = true;
- }
- // datas_lock.ReleaseWriterLock();
- }
- return re;
- }
- // 刪除曲線
- public void RemoveCurve(int id)
- {
- // datas_lock.AcquireWriterLock(-1);
- if (this.curve[id] != null)
- {
- if (this.curve[id].show == true)
- {
- this.curve[id].show = false;
- }
- }
- // datas_lock.ReleaseWriterLock();
- this.Invalidate();
- }
- // 添加單點數據
- public void AddData(int id,float f)
- {
- if (this.hold == false)
- {
- // datas_lock.AcquireWriterLock(-1);
- if (this.curve[id] != null)
- {
- if (this.curve[id].show == true)
- {
- for (int i = Curve.points - 1; i > 0; i--)
- {
- if (this.curve[id].counter == 0)
- {
- this.curve[id].data_raw[i].X = 0;
- }
- else
- {
- this.curve[id].data_raw[i].X = this.curve[id].data_raw[i - 1].X + 1;
- }
- this.curve[id].data_raw[i].Y = this.curve[id].data_raw[i - 1].Y;
- }
- this.curve[id].data_raw[0].X = 0;
- this.curve[id].data_raw[0].Y = f;
- if (this.curve[id].counter < Curve.points)
- {
- this.curve[id].counter++;
- }
- }
- }
- // datas_lock.ReleaseWriterLock();
- this.Invalidate();
- }
- }
- // 暫停波形
- public bool Hold
- {
- set
- {
- this.hold = value;
- }
- }
- // 設置曲線參數
- private void SetCurveOffsetX(int id, int offset_x) // 暫時禁止X軸偏置設置,其原點在右,向左為正方向
- {
- if (this.curve[id] != null)
- {
- Curve.offset_x = offset_x;
- this.Invalidate();
- }
- }
- public void SetCurveOffsetY(int id, int offset_y)
- {
- if (this.curve[id] != null)
- {
- this.curve[id].offset_y = offset_y;
- this.Invalidate();
- }
- }
- public void SetCurveZoomX(int id, float zoom_x)
- {
- if (this.curve[id] != null)
- {
- if (zoom_x >= 1.0f) // 限制X軸縮放比例 >=1
- {
- Curve.zoom_x = zoom_x;
- this.Invalidate();
- }
- }
- }
- public void SetCurveZoomY(int id, float zoom_y)
- {
- if (this.curve[id] != null)
- {
- this.curve[id].zoom_y = zoom_y;
- }
- }
- // 示波器初始化
- private void Scope_Load(object sender, EventArgs e)
- {
- // datas_lock = new ReaderWriterLock();
- curve = new Curve[MAX_CURVE_NUM];
- Curve.InitStatic(DATA_LENGTH, INTERVAL, 0, 1.0f);
- brush = new SolidBrush(Color.Yellow);
- font = new Font("SimSun", 10, System.Drawing.FontStyle.Regular);
- white_dash_pen = new Pen(Color.White, 1);
- white_dash_pen.DashStyle = DashStyle.Dot;
- hold = false;
- }
- // size改變時刷新
- private void Scope_Resize(object sender, EventArgs e)
- {
- this.Invalidate();
- }
- // 右鍵菜單about
- private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
- {
- MessageBox.Show("Scope V1.0\r\n\r\nCopyRight dongzr 2010-2012", "About...");
- }
- // 繪圖,雙緩沖在Scope屬性里設置
- private void Scope_Paint(object sender, PaintEventArgs e)
- {
- Graphics g = e.Graphics;
- g.SmoothingMode = SmoothingMode.HighSpeed;
- g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
- g.Clear(Color.DarkGray);
- g.ScaleTransform(-(float)this.Width / (SCOPE_WIDTH + SCOPE_FRAME*2),
- -(float)this.Height / (SCOPE_HEIGHT + SCOPE_FRAME*2) ); // 縮放,并使XY軸反向
- g.TranslateTransform(-(SCOPE_WIDTH + SCOPE_FRAME) , - (SCOPE_HEIGHT/2 + SCOPE_FRAME)); // 新的坐標原點,位于波形顯示區的右側中點
- // 示波器顯示范圍指示
- g.SetClip(new Rectangle(0, SCOPE_HEIGHT / 2 + 5, SCOPE_WIDTH, SCOPE_FRAME - 10));
- g.Clear(Color.Black);
- g.DrawRectangle(Pens.YellowGreen, new Rectangle(0, SCOPE_HEIGHT / 2 + 10, (int)(SCOPE_WIDTH / Curve.zoom_x), SCOPE_FRAME - 20));
- // 繪制零點指示標志
- g.SetClip(new Rectangle(SCOPE_WIDTH + 5, -SCOPE_HEIGHT / 2, SCOPE_FRAME - 10, SCOPE_HEIGHT));
- g.Clear(Color.Black);
- for (int ls = 0; ls < MAX_CURVE_NUM; ls++)
- {
- if (this.curve[ls] != null)
- {
- if (this.curve[ls].show == true)
- {
- g.DrawLine(this.curve[ls].pen, SCOPE_WIDTH + 5, this.curve[ls].offset_y, SCOPE_WIDTH + 15, this.curve[ls].offset_y + 3);
- g.DrawLine(this.curve[ls].pen, SCOPE_WIDTH + 5, this.curve[ls].offset_y, SCOPE_WIDTH + SCOPE_FRAME - 5, this.curve[ls].offset_y);
- g.DrawLine(this.curve[ls].pen, SCOPE_WIDTH + 5, this.curve[ls].offset_y, SCOPE_WIDTH + 15, this.curve[ls].offset_y - 3);
- }
- }
- }
- // 設置作圖區域為波形顯示區,大小為SCOPE_WIDTH*SCOPE_HEIGHT
- g.SetClip(new Rectangle(0, -SCOPE_HEIGHT / 2, SCOPE_WIDTH, SCOPE_HEIGHT));
- g.Clear(Color.Black);
- // 繪制坐標網格
- for (int step = SCOPE_WIDTH / 50,i = 0; i <= 50; i++)
- {
- if (i % 5 == 0)
- {
- g.DrawLine(white_dash_pen, i * step, -SCOPE_HEIGHT / 2, i * step, SCOPE_HEIGHT / 2);
- }
- else
- {
- g.DrawLine(white_dash_pen, i * step, -SCOPE_HEIGHT / 2, i * step, -SCOPE_HEIGHT / 2 + step / 2);
- // g.DrawLine(white_dash_pen, i * step, -step / 4, i * step, step / 4);
- g.DrawLine(white_dash_pen, i * step, SCOPE_HEIGHT / 2, i * step, SCOPE_HEIGHT / 2 - step / 2);
- }
- }
- for (int step = SCOPE_HEIGHT / 50, i = -25; i <= 25; i++)
- {
- if (i % 5 == 0)
- {
- g.DrawLine(white_dash_pen, SCOPE_WIDTH, i * step, 0, i * step);
- }
- else
- {
- g.DrawLine(white_dash_pen, SCOPE_WIDTH, i * step, SCOPE_WIDTH - step / 2, i * step);
- // g.DrawLine(white_dash_pen, SCOPE_WIDTH / 2 + step / 4, i * step, SCOPE_WIDTH / 2 - step / 4, i * step);
- g.DrawLine(white_dash_pen, step / 2, i * step, 0, i * step);
- }
- }
- // 繪制data
- // datas_lock.AcquireWriterLock(-1);
- for (int ls = 0; ls < MAX_CURVE_NUM; ls++)
- {
- if (this.curve[ls] != null)
- {
- if (this.curve[ls].show == true)
- {
- // data變換
- for (int i = 0; i < Curve.points; i++)
- {
- this.curve[ls].data_show[i].X = this.curve[ls].data_raw[i].X * Curve.zoom_x + Curve.offset_x;
- this.curve[ls].data_show[i].Y = this.curve[ls].data_raw[i].Y * this.curve[ls].zoom_y + this.curve[ls].offset_y;
- }
- // 顯示
- g.DrawLines(this.curve[ls].pen, this.curve[ls].data_show);
- }
- }
- }
- // datas_lock.ReleaseWriterLock();
- // 繪制單位坐標
- g.ScaleTransform(-1, -1);
- g.SetClip(new Rectangle(-SCOPE_WIDTH, SCOPE_HEIGHT / 2 + 5, SCOPE_WIDTH, SCOPE_FRAME - 10));
- g.Clear(Color.Black);
- g.DrawString("10 9 8 7 6 5 4 3 2 1 0", font, brush, -SCOPE_WIDTH, SCOPE_HEIGHT / 2 + 5);
- g.RotateTransform(-90);
- g.SetClip(new Rectangle(-SCOPE_HEIGHT / 2 , 5, SCOPE_HEIGHT, SCOPE_FRAME - 10));
- g.Clear(Color.Black);
- g.DrawString("-5 -4 -3 -2 -1 0 1 2 3 4 5", font, brush, -SCOPE_HEIGHT / 2, 5);
- }
- private void saveToolStripMenuItem_Click(object sender, EventArgs e)
- {
- bool isSave = true;
- SaveFileDialog saveImageDialog = new SaveFileDialog();
- saveImageDialog.Title = "Save Scope image";
- saveImageDialog.Filter = @".bmp|*.bmp";
- if (saveImageDialog.ShowDialog() == DialogResult.OK)
- {
- string fileName = saveImageDialog.FileName.ToString();
- if (fileName != "" && fileName != null)
- {
- System.Drawing.Imaging.ImageFormat imgformat = null;
- imgformat = System.Drawing.Imaging.ImageFormat.Bmp;
- if (isSave)
- {
- try
- {
- bitmap = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
- this.DrawToBitmap(bitmap, this.ClientRectangle);
- bitmap.Save(fileName, imgformat);
- MessageBox.Show("圖片已經成功保存!");
- }
- catch
- {
- MessageBox.Show("保存失敗!");
- }
- finally
- {
- bitmap.Dispose();
- }
- }
- }
- }
- }
- }
- internal class Curve
- {
- public bool show; // 是否顯示
- public PointF[] data_raw; // 數據原始值
- public PointF[] data_show; // 數據顯示值
- public Pen pen; // 畫筆
- public static int points; // 采樣點數
- public string unit; // 數據的單位
- public static int interval; // 采樣點的時間間隔,單位ms
- public static int offset_x; // 橫軸偏置
- public int offset_y; // 縱軸偏置
- public static float zoom_x; // 橫軸縮放比例
- public float zoom_y; // 縱軸縮放比例
- public int counter;
- public Curve()
- {
- this.show = false;
- }
- public static void InitStatic(int points, int interval, int offset_x, float zoom_x)
- {
- Curve.points = points;
- Curve.interval = interval;
- Curve.offset_x = offset_x;
- Curve.zoom_x = zoom_x;
- }
- public void Init(bool show, Color color, int points, int interval, string unit)
- {
- this.show = show;
- this.unit = unit;
- this.pen = new Pen(color, 1);
- this.data_raw = new PointF[Curve.points];
- this.data_show = new PointF[Curve.points];
- this.offset_y = 0;
- this.zoom_y = 1.0f;
- this.counter = 0;
- }
- }
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- this.scope1.CreateCurve(0, Color.Yellow, "");
- this.scope1.SetCurveZoomY(0,100);
- this.scope1.CreateCurve(1, Color.Cyan, "");
- for(int i = 0;i<500;i++)
- {
- this.scope1.AddData(0,sin(3.14* i / 100));
- this.scope1.AddData(1,cos(3.14* i / 100));
- }
- this.scope1.RemoveCurve(1);
復制代碼
|