根据离散点画直线,iOS离散点画曲线
在iOS开发过程中,我们会经常遇到画线的功能,比如线性图。
目前iOS画线有两大类方法 (我所知道的)。
1、基于CoreGraphics.framework的CGContext;
2、基于UIKit.framework、QuartzCore.framework的UIBezierPath、CAShapeLayer。
方法一、CGContext
CGContext是一个结构体。
下面列举与画线相关的方法:
//绘制直线
CGContextAddLineToPoint(CGContextRef cg_nullable c, CGFloat x, CGFloat y)
//绘制三次贝塞尔曲线
CGContextAddCurveToPoint(CGContextRef cg_nullable c, CGFloat cp1x, CGFloat cp1y, CGFloat cp2x, CGFloat cp2y, CGFloat x, CGFloat y)
//绘制二次贝塞尔曲线
CGContextAddQuadCurveToPoint(CGContextRef cg_nullable c, CGFloat cpx, CGFloat cpy, CGFloat x, CGFloat y)
//绘制矩形
CGContextAddRect(CGContextRef cg_nullable c, CGRect rect)
//绘制多个矩形
CGContextAddRects(CGContextRef cg_nullable c, const CGRect * __nullable rects, size_t count)
//绘制多个点连接的直线
CGContextAddLines(CGContextRef cg_nullable c, const CGPoint * __nullable points, size_t count)
//绘制椭圆
CGContextAddEllipseInRect(CGContextRef cg_nullable c, CGRect rect)
//绘制弧或圆
CGContextAddArc(CGContextRef cg_nullable c, CGFloat x, CGFloat y, CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise)
//绘制两点之间指定半径的弧(如果指定的位置、大小不合适,会绘制不出来)
CGContextAddArcToPoint(CGContextRef cg_nullable c, CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2, CGFloat radius)
//根据指定路径绘制
CGContextAddPath(CGContextRef cg_nullable c, CGPathRef cg_nullable path)
代码示例:
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
//当前绘制区域(上下文)
CGContextRef context = UIGraphicsGetCurrentContext();
//开启一个新路径,放弃旧路径
CGContextBeginPath(context);
//设置线条粗细
CGContextSetLineWidth(context, 1.0);
//设置描边颜色
UIColor *strokeColor = [UIColor redColor];
CGContextSetStrokeColorWithColor(context, strokeColor.CGColor);
//设置起始点
CGContextMoveToPoint(context, 0.0, 100.0);
CGContextAddLineToPoint(context, 100.0, 60.0);
CGContextAddLineToPoint(context, 200.0, 60.0);
CGContextAddLineToPoint(context, 300.0, 100.0);
//路径描边
CGContextStrokePath(context);
}
效果图:
CGContext画线.png
注意CGContextClosePath方法!
有很多人在使用这个方法时,会遇到: CGContextClosePath: no current point.
这是因为再执行CGContextClosePath方法时,当前已经没有可用点了。比如执行CGContextStrokePath、CGContextFillPath 、CGContextEOFillPath后,都会置空当前点,所以CGContextClosePath方法一般在这些方法之前执行。
方法二、UIBezierPath和CAShapeLayer
UIBezierPath继承NSObject;CAShapeLayer继承CALayer,CALayer继承NSObject。
下面列举与画线相关的方法:
//绘制直线(从上一个点到point)
- (void)addLineToPoint:(CGPoint)point;
//绘制三次贝塞尔曲线(从上一个点到endPoint)
- (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2;
//绘制二次贝塞尔曲线(从上一个点到endPoint)
- (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint;
//绘制弧或圆
- (void)addArcWithCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise
代码示例:
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
//设置颜色
[[UIColor orangeColor] set];
UIBezierPath *path = [UIBezierPath bezierPath];
path.lineWidth = 1.0;
path.lineCapStyle = kCGLineCapRound;
path.lineJoinStyle = kCGLineCapRound;
CGPoint p0 = CGPointMake(0.0, 100.0);
CGPoint p1 = CGPointMake(100.0, 120.0);
CGPoint p2 = CGPointMake(200.0, 120.0);
CGPoint p3 = CGPointMake(300.0, 100.0);
[path moveToPoint:p0];
[path addLineToPoint:p1];
[path addLineToPoint:p2];
[path addLineToPoint:p3];
[path stroke];
}
效果图:
UIBezierPath画线.png
当然你也可以借助使用CAShapeLayer,示例如下:
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
//设置颜色
UIBezierPath *path = [UIBezierPath bezierPath];
CGPoint p0 = CGPointMake(0.0, 100.0);
CGPoint p1 = CGPointMake(100.0, 120.0);
CGPoint p2 = CGPointMake(200.0, 120.0);
CGPoint p3 = CGPointMake(300.0, 100.0);
//
[path moveToPoint:p0];
[path addLineToPoint:p1];
[path addLineToPoint:p2];
[path addLineToPoint:p3];
//
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.frame = CGRectMake(0.0, 0.0, rect.size.width, rect.size.height);
shapeLayer.lineWidth = 1.0;
shapeLayer.lineCap = @"round";
shapeLayer.strokeColor = [[UIColor redColor] CGColor];
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
shapeLayer.path = [path CGPath];
shapeLayer.strokeStart = 0.0;
shapeLayer.strokeEnd = 1.0;
[self.layer addSublayer:shapeLayer];
}
效果图:
CAShapeLayer.png
看上去效果是不是和UIBezierPath一样?
注意CAShapeLayer的strokeStart和strokeEnd!这两个参数配合动画,会有不错的效果。
上面说了那么多,都还没介绍绘制曲线方法。
其实上面有说明,比如二次贝塞尔曲线、三次贝塞尔曲线、圆弧都是曲线的绘制方法。
可是这些都不是我这次要介绍的,首先贝塞尔曲线需要添加控制点,说实话,这些控制点在实际项目中很不好找,其次圆弧不能满足所有曲线类型。
那怎么办呢?
答案是使用Catmull-Rom算法。
这个算法思想,大家可以在网上搜索。
这里我直接给出iOS下,我的处理方式。
直接上代码:
/**
Catmull-Rom算法
根据四个点计算中间点
*/
- (CGPoint)getPoint:(CGFloat)t p0:(CGPoint)p0 p1:(CGPoint)p1 p2:(CGPoint)p2 p3:(CGPoint)p3 {
CGFloat t2 = t*t;
CGFloat t3 = t2*t;
CGFloat f0 = -0.5*t3 + t2 - 0.5*t;
CGFloat f1 = 1.5*t3 - 2.5*t2 + 1.0;
CGFloat f2 = -1.5*t3 + 2.0*t2 + 0.5*t;
CGFloat f3 = 0.5*t3 - 0.5*t2;
CGFloat x = p0.x*f0 + p1.x*f1 + p2.x*f2 +p3.x*f3;
CGFloat y = p0.y*f0 + p1.y*f1 + p2.y*f2 +p3.y*f3;
return CGPointMake(x, y);
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
//
UIBezierPath *path = [UIBezierPath bezierPath];
//
CGPoint p0 = CGPointMake(0.0, 100.0);
CGPoint p1 = CGPointMake(100.0, 120.0);
CGPoint p2 = CGPointMake(200.0, 120.0);
CGPoint p3 = CGPointMake(300.0, 100.0);
//
NSValue *v0 = [NSValue valueWithCGPoint:p0];
NSValue *v1 = [NSValue valueWithCGPoint:p1];
NSValue *v2 = [NSValue valueWithCGPoint:p2];
NSValue *v3 = [NSValue valueWithCGPoint:p3];
//
NSArray *array = [NSArray arrayWithObjects:v0, v0, v1, v2, v3, v3, nil];
//
[path moveToPoint:p0];
//
for (NSInteger i=0; i
CGPoint t0 = [array[i+0] CGPointValue];
CGPoint t1 = [array[i+1] CGPointValue];
CGPoint t2 = [array[i+2] CGPointValue];
CGPoint t3 = [array[i+3] CGPointValue];
//
for (int i=0; i<100; i++) {
CGFloat t = i/100.0;
CGPoint point = [self getPoint:t p0:t0 p1:t1 p2:t2 p3:t3];
[path addLineToPoint:point];
}
}
//
[path addLineToPoint:p3];
//
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.frame = CGRectMake(0.0, 0.0, rect.size.width, rect.size.height);
shapeLayer.lineWidth = 1.0;
shapeLayer.lineCap = @"round";
shapeLayer.strokeColor = [[UIColor redColor] CGColor];
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
shapeLayer.path = [path CGPath];
shapeLayer.strokeStart = 0.0;
shapeLayer.strokeEnd = 1.0;
[self.layer addSublayer:shapeLayer];
}
效果图:
Catmull-Rom曲线.png
注意
1、NSArray *array = [NSArray arrayWithObjects:v0, v0, v1, v2, v3, v3, nil];这里为什么我多加了一个v0和v3,因为Catmull-Rom需要四个点!为了能画出v0到v1之间的线和v2直接的线v3,所以我加了这两个点。
2、在第二层for循环中for (int i=0; i<100; i++),这里i我为什么取100为最大值?因为两个点之间的距离是100。当然这个值,可以根据实际需要,由自己来设定。
好了,到这里基本就要结束了。
离散点画曲线,我采用的是Catmull-Rom算法,在离散点之间插入中间点。
基础是两点之间画直线,关于Catmull-Rom算法可以进行封装,这点我在接下来的文章中会有介绍。
根据离散点画直线,iOS离散点画曲线相关推荐
- 根据离散点画直线_离散数据的最佳直线求解方法
离散数据的最佳直线求解方法 高少蔚 ; 丁红胜 [期刊名称] <计量技术> [年 ( 卷 ), 期] 1997(000)012 [摘要] 本文提出了一种在最大偏差最小准则下寻找离散点最佳直 ...
- 过直线上一点画垂线图_苏教版四年级数学上册8.5认识垂直、点到直线的距离微课视频 | 练习...
微课视频第一课时 微课视频第二课时 同步练习 参考答案 教学设计 垂直 教材第89~91页的内容. 1.结合实际情境和操作活动,认识垂直. 2.能借助直尺.三角尺.量角器等工具画出已知直线的垂线,并理 ...
- 【数字信号处理】离散时间信号 ( 模拟信号、离散时间信号、数字信号 | 采样导致时间离散 | 量化导致幅度离散 )
文章目录 一.模拟信号.离散时间信号.数字信号 二.采样导致时间离散 三.量化导致幅度离散 一.模拟信号.离散时间信号.数字信号 时间是 连续 的 , 幅度也是 连续 的 , 该信号是 模拟信号 或 ...
- 离散傅里叶变换DFT、离散余弦变换DCT、离散正弦变换DST,原理与公式推导
更新:本网页为纯图片版,是由 Word 文档转图片后直接上传的.目前我已更新一个 Markdown 文字版的,网页浏览体验会好一些.因为一篇博客的字符数量有限制,所以分开了三篇. DFT:https: ...
- 使用ZRender类库画直线、圆弧、曲线以及点在线上的运动
最近在学习Zrender类库,并利用Zrender 让点在直线.圆弧.曲线上运动.大概的写了一些. Zrender是二维绘图引擎,它提供 Canvas.SVG.VML 等多种渲染方式.ZRender ...
- 解决Photoshop中直线转曲线时一条直线边无法转曲线的问题
目录 解决Photoshop中直线转曲线时一条直线边无法转曲线的问题 问题概述 问题原因 解决方法 其他情况 解决Photoshop中直线转曲线时一条直线边无法转曲线的问题 Mac OS 10.15 ...
- 根据离散点画直线_excel表格怎么画散点图画直线
Excel中散点图画直线具体该如何操作执行呢?其实表格中有插入选项,可以帮助我们完成一系列的画图方案,接下来是学习啦小编为大家带来的excel中的散点图画直线的教程,欢迎大家来到学习啦学习. exce ...
- iOS开发 贝塞尔曲线UIBezierPath(后记)
使用CAShapeLayer与UIBezierPath可以实现不在view的drawRect方法中就画出一些想要的图形 . 1:UIBezierPath: UIBezierPath是在 UIKit 中 ...
- iOS开发 UIBezierPath曲线动画
基础知识 使用UIBezierPath可以创建基于矢量的路径 此类是Core Graphics的封装.使用这个类可以定义简单的形状 如椭圆.矩形或者有多个直线和曲线段组成的形状等. UIBezierP ...
最新文章
- Mol Plant | 中科院遗传与发育生物学研究所周俭民课题组报道了细菌效应蛋白在植物细胞内诱导免疫受体ZAR1寡聚的新发现...
- 写入位置 0x00000004 时发生访问冲突_HDFS读取和写入数据简介
- WPF获取某控件的位置,也就是偏移量
- Java并发编程—ScheduledThreadPoolExecutor原理分析
- oracle导入表 忽略报错,oracle数据泵导入分区表统计信息报错(一)
- android 自定义域名,Android基于Retrofit2改造的可设置多域名的网络加载框架
- 表字段identity
- maven项目jsp无法识别jstl的解决办法
- python 鸭子类型
- 使用容联云通讯实现短信验证登入
- linux获取pc指针地址,为什么pc可以看成使程序存储器的地址指针
- Ford-Fulkerson方法
- windows环境下编译ACE+TAO问题及解决办法
- 查询跟踪快递物流,筛选因拒收退回的单号
- 有小数点的补码怎么算_-49d补码的是多少?怎样计算的?
- 西电、成电的风雨往事
- 手把手教你选开源商城系统!
- 快手直播弹幕数据采集
- zabbix template pg_monz for PostgreSQL
- 破解的iphone上, 如何编写具有root权限的程序
热门文章
- 莫尔斯代码的c语言编码,c语言编写莫尔斯码,帮帮忙啊,速回
- 数据开发面试问题记录
- 12套很酷的Google Plus图标下载
- mysql 显示表_显示MYSQL表信息的方法
- 10个简单的hacker加速你在Python中的数据分析
- Django2.0服务器的零基础完全部署
- 【新书推荐】【2018】有源集成天线的设计与应用
- win10计算机服务打不开,windows10设置打不开怎么办_win10设置功能打不开解决方法...
- matlab用sym出错,使用sym.int时出错输入参数太多
- 零基础编程——块语言编程游戏攻略之动画篇