ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

WPF开发随笔收录-心电图曲线绘制

2022-06-26 22:00:43  阅读:174  来源: 互联网

标签:ecg int 心电图 private points new WPF 随笔 绘制


WPF开发随笔收录-心电图曲线绘制

 

一、前言

项目中之前涉及到胎儿心率图曲线的绘制,最近项目中还需要添加心电曲线和血样曲线的绘制功能。今天就来分享一下心电曲线的绘制方式;

二、正文

1、胎儿心率曲线的绘制是通过DrawingVisual来实现的,这里的心电曲线我也是采用差不多相同的方式来实现的,只是两者曲线的数据有所区别。心电图的数据服务器端每秒发送至客户端一个数据包,一个数据包钟心电的数据大概一百个左右,看过心电图的应该知道,心电图的效果是匀速绘制出来的,而不是一次性将一百个点绘制出来;项目中是通过将数据存到数据缓冲区,然后通过线程定时推送数据到绘图端,线程里会根据缓冲区现有数据量来动态控制数据的快慢;这里的例子我就直接通过定时推数据来直接演示如何实现;

2、新建个项目,添加一个类继承FrameworkElement,然后加上对应的数据接收和绘制功能,这里直接贴出所有代码,具体细节之前写绘制高性能曲线时写过了,不清楚的可以参考之前的;(实际上绘图部分用Canvas实现也可以,用DrawingVisual其实每次推送了一个数据,整个视图都重新绘制了,我之所以用这个是因为我要支持自动缩放功能)

复制代码
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、主界面添加这个控件,然后后台添加对应的推送数据的线程,这里我是定时每隔十毫秒推送一个数据给到绘图端。

复制代码
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、最终实现效果

 

 

标签:ecg,int,心电图,private,points,new,WPF,随笔,绘制
来源: https://www.cnblogs.com/sexintercourse/p/16414492.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有