Core Graphics使用 >> 绘制心电图

来源:互联网 发布:中金智德 知乎 编辑:程序博客网 时间:2024/04/29 02:18

IOS 绘制心电图

这两天公司做一个医疗的项目,其中一个需求是接受传感器的病人心跳数据,将之在UI上面绘制成心电图. 在网上看了很多demo,废话不多说直接切入.(漏洞百出,欢迎批评指正) 

因为除了逻辑其实很简单,代码就没有放到githup上面。点击打开链接 这是demo的下载地址

一.Core Graphics

Core Graphics 是一个基于c的api编写的图形核心绘制引擎。提供比较底层的,轻量级的二维渲染和非常好的输出保真度

使用Core Graphics画出你想要的东西,一个很重要的实情就是 你需要一个能够让你画图的地方(俗称 画布),基本上三中方法


//搬运别人的 总结就是这样

第一种:创建图片类型的画布。调用UIGraphicsBeginImageContextWithOptions函数就可获得用来处理图片的图形上下文。

第二种:利用cocoa自动为你生成画布。当你子类化了一个UIView并实现了自己的drawRect:方法后,一旦drawRect:方法被调用,Cocoa就会为你创建一个图形上下文,

这上面2种都是自己弄的画布,没有引用当前图像所在的画布,如果自己不想创建画布,可以用当前的画布(类型是:CGContextRef)

具体看代码:

画图展示需要我们自定义一个UIView,重写初始化方法.

[objc] view plain copy
 print?
  1. self.clearsContextBeforeDrawing = YES;//这个方法 是保证我们的改变挥着绘图能够生效  
[objc] view plain copy
 print?
  1. - (instancetype)initWithFrame:(CGRect)frame{  
  2.   
  3.     self = [super initWithFrame:frame];  
  4.     if (self) {  
  5.         self.clearsContextBeforeDrawing = YES;  
  6.     }  
  7.     return self;  
  8. }  
在重写系统方法- (void)drawRect:(CGRect)rect 这时候系统就知道 你要发挥你的绘画天赋了,并已经准好了

[objc] view plain copy
 print?
  1. - (void)drawRect:(CGRect)rect {  
  2.     [self drawCurve]; // 绘制心电图型  
  3.     [self drawGrid]; //绘制心电图 背景网格  
  4. }  



//因为画的是心电图  所以 必须要有心跳的背景网格对不对 所以第一步 就是先画出背景的网格

[objc] view plain copy
 print?
  1. //绘制背景的网格  
  2. - (void)drawGrid{  
  3.   
  4.     CGContextRef context = UIGraphicsGetCurrentContext();//获取上下文 知道你要画图的地方 (就是画布)  
  5.     CGFloat height = self.frame.size.height;  
  6.     CGFloat width = self.frame.size.width;  
  7.    // NSLog(@"高 >>%f 宽 >> width %f",height,width);  
  8.     CGFloat cell_square_width = 30;//设置每一个格子的宽度   
  9.       
  10.     CGContextSetLineWidth(context, 1); //设置线宽  
  11.     CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor); //设置线的颜色  
  12.       
  13. //    设置绘制表格的起始点  
  14.     NSInteger pos_x = 1;  
  15.     while (pos_x <= width) {  
  16.         CGContextSetLineWidth(context, 0.2);  
  17. //        起始点  
  18.         CGContextMoveToPoint(context, pos_x, 1);  
  19.         CGContextAddLineToPoint(context, pos_x, height);  
  20.         pos_x += cell_square_width;  
  21.         CGContextStrokePath(context);  
  22.     }  
  23.       
  24.     NSInteger pos_y = 1;  
  25.       
  26.     while (pos_y <= height) {  
  27.         CGContextMoveToPoint(context, 1, pos_y);  
  28.         CGContextAddLineToPoint(context, width,pos_y);  
  29.         pos_y += cell_square_width;  
  30.         CGContextStrokePath(context);  
  31.     }  
  32.     cell_square_width = cell_square_width / 5//刚才设置大格  现在 绘制小格  
  33.       
  34.      pos_x = 1;  
  35.     while (pos_x <= width) {  
  36.         CGContextSetLineWidth(context, 0.2);  
  37.         //        起始点  
  38.         CGContextMoveToPoint(context, pos_x, 1);  
  39.         CGContextAddLineToPoint(context, pos_x, height);  
  40.         pos_x += cell_square_width;  
  41.         CGContextStrokePath(context);  
  42.     }  
  43.       
  44.      pos_y = 1;  
  45.       
  46.     while (pos_y <= height) {  
  47.         CGContextMoveToPoint(context, 1, pos_y);  
  48.         CGContextAddLineToPoint(context, width,pos_y);  
  49.         pos_y += cell_square_width;  
  50.         CGContextStrokePath(context);  
  51.     }  
  52.       
  53. }  

绘制玩背景 就要在背景上 开始描绘心跳了


[objc] view plain copy
 print?
  1. //  这是绘制曲线的  
  2. - (void)drawCurve{  
  3.   
  4.     if (self.cunrrentPointCount == 0) { //当前点得数量 没有点 就不画了  
  5.         return;  
  6.     }  
  7.     CGFloat curveWidth = 0.8//宽度  
  8.     CGContextRef currentContext = UIGraphicsGetCurrentContext(); //跟上面一样  
  9.     CGContextSetLineWidth(currentContext, curveWidth);  
  10. //    设置心跳的颜色  
  11.     CGContextSetStrokeColorWithColor(currentContext, [UIColor greenColor].CGColor);  
  12.   
  13.  CGContextMoveToPoint(currentContext, self.points[0].xself.points[0].y);  //self.points 是一个CGPoint的属性  
  14.     for (int i = 0; i != self.cunrrentPointCount; ++ i) {  
  15.         if (self.points[i - 1].x < self.points[i].x) {                      //这里的意思是 在已经获知 所有的点 我判断连个点得位置  
  16.                                                                             //如果我右边 还有点 我就连上去 如果没有 我就移动到那  
  17.                                                                             //什么也不干(等待下一组数据)  
  18.  CGContextAddLineToPoint(currentContext, self.points[i].xself.points[i].y);  
  19.         } else {  
  20.             CGContextMoveToPoint(currentContext, self.points[i].xself.points[i].y);  
  21.         }  
  22.     }  
  23.       
  24.     CGContextStrokePath(currentContext);  
  25.      
  26.       
  27. }  

实现心电图有两种方式 一种是是平移的 就是我们经常在医院或者电视上看到的那种走纸带的,还有一种就是一个亮点在屏幕上来回移动画出心电图

[objc] view plain copy
 print?
  1. // 刷新  
  2. - (void)addPointAsRefreshChangeform:(CGPoint)point{  
  3.   
  4.     static NSInteger currentPointsCount = 0;   //设置当前开始从0 刷新 使用static 保证只执行一次 不产生其他影响  
  5.     if (currentPointsCount < kMaxContainerCapacity) {    
  6.         self.numberOfRefreshElements = currentPointsCount + 1;  
  7.         self.refreshPointContainer[currentPointsCount] = point;  
  8.         currentPointsCount ++;  
  9.     }else{  
  10.       
  11.         NSInteger workIndex = 0;  
  12.         while (workIndex != kMaxContainerCapacity - 1) {  
  13.             self.refreshPointContainer[workIndex] = self.refreshPointContainer[workIndex + 1];  
  14.             workIndex ++;  
  15.         }  
  16.         self.refreshPointContainer[kMaxContainerCapacity - 1] = point;  
  17.          self.numberOfRefreshElements = kMaxContainerCapacity;  
  18.     }  
  19.   
  20.   
  21. }  

经过一番折腾 为了便于理解画图  讲drawCruve得方法 简化

[objc] view plain copy
 print?
  1. - (void)drawCurve:(CGContextRef)ctx{  
  2.       
  3.   
  4.     CGContextSetLineWidth(ctx, lineWidth_LiveMonitor);  
  5.     CGContextSetStrokeColorWithColor(ctx, [UIColor greenColor].CGColor);  
  6.       
  7.     //    开始画线  
  8.   
  9.     //将数组里的点画成连续的线  点进去介绍的很明白<span style="font-family: Arial, Helvetica, sans-serif;">  </span>  
  10.     CGContextAddLines(ctx, drawingPoints, _pointArray.count );   
  11.     //这样 以后 我们只要把 要画的点传进drawdingPoints 然后调用 drawrect 就行  
  12.     CGContextStrokePath(ctx);  
  13.       
  14.     
  15. }  



有了drawrect里面的两个方法 就能完成画图 现在怎么样传递数据  

写一个方法 用于外部调用. 用来传递数据

[objc] view plain copy
 print?
  1. - (void)fireDrawing{  
  2.       
  3. // 外面的数据先传给 pointArray  再将pointArray的值取出来 转成坐标  
  4.     for (int i = 0 ; i < _pointArray.count ; i++) {  
  5.           
  6. //textX 是我定义的X的坐标 当它 < 屏幕的宽度是 就一直++ (实现左移)  pointMartin 是每次左移的距离  
  7.         if (testX < self.width) {  
  8.               
  9.   
  10.             drawingPoints[i] =   CGPointMake(testX,self.height/2 - [_pointArray[i] intValue] / 10);  
  11.             testX = testX + pointMartin;  
  12.         } else {  
  13.             testX = 0;  
  14.         }  
  15.     }  
  16.         //        一部分 需要重画  在这里设置  心电图中间的黑格  
  17.         //        因为 drawingPoints[1].x  一直在位移  所以重画的部分 也在偏移  
  18.     <span style="white-space:pre">    </span>//  设置每次需要重新绘制的rect  
  19.         CGRect reck = CGRectMake(testX - _pointArray.count * pointMartin, 0,    +  10self.height);  
  20.       
  21.     dispatch_async(dispatch_get_main_queue(), ^{  
  22.         [self setNeedsDisplayInRect:reck];  
[objc] view plain copy
 print?
  1. <pre name="code" class="objc">//            每次画图的第一个点 应该是上次画的最后一个点  
testX = testX - pointMartin; }); }

外部 调用fireDrawing的时候 传进来数据 就可以实现绘制

在控制器中引入 头文件 开始使用数据绘图

[objc] view plain copy
 print?
  1. - (void)viewWillAppear:(BOOL)animated{  
  2.   
  3.     [self popDataTimerEvent];  
  4.       
  5.   
  6. }  
  7. - (void)popDataTimerEvent{  
  8. <span style="white-space:pre">    </span>//注意定时器的用法  如何释放 这里定时器会让self的引用计数 + 1,  
  9.     self.popDataTimer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(popData) userInfo:nil repeats:YES];  
  10.     _index = 0;  
  11.       
  12.     [[NSRunLoop currentRunLoop] addTimer:self.popDataTimer forMode:NSDefaultRunLoopMode];  
  13.       
  14.   
  15. }  


[objc] view plain copy
 print?
  1. - (void)popData{  
  2.       
  3.       
  4.       
  5.   
  6.         TripleECGView *view = self.ecgViewsArr[0];  
  7.     NSMutableArray *temparr = [NSMutableArray array];  
  8.         for (int i = 0; i < _drawingCountOnce; i++) {  
  9.             [temparr addObject:_testArr[_index + i]];  
  10.       
  11.         }  
  12.       
  13.   
  14.     //传入数据  
  15.     view.pointArray = temparr;  
  16.       
  17. //    for (int i = 0; i < 3; i++) {  
  18. //        [view.pointArray addObject:_testArr[_index + i]];  
  19. //  
  20. //    }  
  21. <span style="white-space:pre">    </span>// 调用画图  
  22.         [view fireDrawing];  
  23.         _index += _drawingCountOnce;  
  24.     if (_index > 420) {  
  25.         _index = 0;  
  26.     }  
  27.     
  28.   
  29.       
  30.   
  31.   
  32. }  

这时候 模拟器就会出现传递数据汇出的图形




原创粉丝点击