当前位置:网站首页>WPF development essays Collection - ECG curve drawing

WPF development essays Collection - ECG curve drawing

2022-06-25 16:36:00 Wandering G

One 、 Preface

The project involves the drawing of fetal heart rate graph curve , Recently, the project also needs to add the drawing function of ECG curve and blood sample curve . Today, let's share the drawing method of ECG curve ;

Two 、 Text

1、 The fetal heart rate curve is drawn by DrawingVisual To achieve , I also use the same method to realize the ECG curve here , Only the data of the two curves are different . The ECG data server sends a packet to the client every second , There are about 100 ECG data in a packet , Those who have seen ECG should know , The effect of ECG is drawn at a constant speed , Instead of drawing a hundred points at once ; In the project, the data is stored in the data buffer , Then push data to the drawing end through the thread , The thread will dynamically control the speed of data according to the existing data amount in the buffer ; In the example here, I will directly demonstrate how to implement... By pushing data regularly ;

2、 New project , Add a class inheritance FrameworkElement, Then the corresponding data receiving and drawing functions are added , All the codes are posted directly here , The specific details have been written before when drawing the high-performance curve , For those unclear, please refer to the previous ;( In fact, it is used for drawing part Canvas It can also be realized , use DrawingVisual In fact, one data is pushed every time , The entire view has been redrawn , I use this because I want to support autoscale )

public class EcgDrawingVisual : FrameworkElement
{
    private readonly List<Visual> visuals = new List<Visual>();
    private DrawingVisual Layer;

    private Pen ecg_pen = new Pen(Brushes.Orange, 1.5);

    private int?[] ecg_points = new int?[2000];

    private int currentStart = 0;

    private double y_offset = 0;

    private int ecg_max = 60;
    private int ecg_min = -25;

    public EcgDrawingVisual()
    {
        ecg_pen.Freeze();

        Layer = new DrawingVisual();
        visuals.Add(Layer);
    }

    public void SetupData(int ecg)
    {
        ecg_points[currentStart] = ecg;
        for (int i = 1; i <= 20; i++)
        {
            ecg_points[currentStart + i] = null;
        }

        currentStart++;
        if (currentStart >= RenderSize.Width / 2)
        {
            currentStart = 0;
        }

        DrawEcgLine();
        InvalidateVisual();
    }

    private void DrawEcgLine()
    {
        var scale = RenderSize.Height / (ecg_max - ecg_min);
        y_offset = ecg_min * -scale;

        DrawingContext dc = Layer.RenderOpen();
        Matrix mat = new Matrix();
        mat.ScaleAt(1, -1, 0, RenderSize.Height / 2);
        dc.PushTransform(new MatrixTransform(mat));

        for (int i = 0, left = 0; left < RenderSize.Width; i++, left += 2)
        {
            if (ecg_points[i] == null || ecg_points[i + 1] == null) continue;
            dc.DrawLine(ecg_pen, new Point(left, ecg_points[i].Value * scale + y_offset), new Point(left + 2, ecg_points[i + 1].Value * scale + y_offset));
        }

        dc.Pop();
        dc.Close();
    }

    protected override int VisualChildrenCount => visuals.Count;
    protected override Visual GetVisualChild(int index)
    {
        return visuals[index];
    }

    protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
    {
        base.OnRenderSizeChanged(sizeInfo);
    }

    protected override void OnRender(DrawingContext drawingContext)
    {
        drawingContext.DrawRectangle(Brushes.White, null, new Rect(0, 0, RenderSize.Width, RenderSize.Height));
        base.OnRender(drawingContext);
    }
}

3、 Add this control to the main interface , Then add the corresponding thread to push data in the background , Here I push a data to the drawing end every ten milliseconds .

public partial class MainWindow : Window
{
    private List<int> points = new List<int>() { 4, 4, 3, -1, -2, -2, -2, -2, -2, -2, -2, -2, -4, -3, 25, 37, 8, -7, -5, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -1, -1, 3, 5, 8, 9, 9, 10, 9, 7, 5, 1, -1, -4, -4, -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -2, -1, 1, 3 };
    private bool flag = true;
    private int currentIndex = 0;

    public MainWindow()
    {
        InitializeComponent();

        new Thread(() =>
        {
            while (flag)
            {
                Thread.Sleep(10);
                this.Dispatcher.BeginInvoke(new Action(() =>
                {
                    if (currentIndex == points.Count) currentIndex = 0;
                    ecgDrawingVisual.SetupData(points[currentIndex]);
                    currentIndex++;
                }));
            }
        }).Start();
    }

    protected override void OnClosed(EventArgs e)
    {
        base.OnClosed(e);
        flag = false;
    }
}

4、 Final effect

 

 

原网站

版权声明
本文为[Wandering G]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/176/202206251554490961.html