1、贝塞尔曲线

  • 贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。一般的矢量图形软件通过它来精确画出曲线,贝兹曲线由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋,我们在绘图工具上看到的钢笔工具就是来做这种矢量曲线的。贝塞尔曲线是计算机图形学中相当重要的参数曲线,在一些比较成熟的位图软件中也有贝塞尔曲线工具,如 PhotoShop 等。在 Flash4 中还没有完整的曲线工具,而在 Flash5 里面已经提供出贝塞尔曲线工具。

  • 二阶贝塞尔曲线示意图

  • 三阶贝塞尔曲线示意图

  • 贝塞尔路径(UIBezierPath)是 iOS UIKit 框架中对 Quartz 2D 绘图的封装。实际操作起来,使用贝塞尔路径,更为方便。用法与 CGContextRef 类似,但是 OC 对其进行了封装,更加面向对象。

  • 贝塞尔路径常用的方法

    	// 设置起始点
    - (void)moveToPoint:(CGPoint)point; // 添加直线到一点
    - (void)addLineToPoint:(CGPoint)point; // 封闭闭路径
    - (void)closePath; // 返回一个描述椭圆的路径
    + (UIBezierPath *)bezierPathWithOvalInRect:(CGRect)rect; // 贝塞尔曲线
    - (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint; // 三次贝塞尔曲线
    - (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2; // 绘制圆弧
    - (void)addArcWithCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise;

2、基本图形的绘制

3、二三阶贝塞尔曲线示例

3.1 二阶贝塞尔曲线示例

  • QBezierPathView.h

    	@interface QBezierPathView : UIView
    
    	@end
  • QBezierPathView.m

    	@interface QBezierPathView ()
    
    	/// 路径
    @property (nonatomic, strong) UIBezierPath *path; /// 起始点
    @property (nonatomic, assign) CGPoint startP; /// 终止点
    @property (nonatomic, assign) CGPoint endP; /// 控制点
    @property (nonatomic, assign) CGPoint controlP; /// 线的颜色
    @property (nonatomic, strong) UIColor *pathColor; /// 线的宽度
    @property (nonatomic, assign) CGFloat pathWidth; /// 当前触摸的点
    @property (nonatomic, assign) NSUInteger currentTouchP; @end @implementation QBezierPathView /// 初始化
    - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { // 设置初始值 self.startP = CGPointMake(20, 300);
    self.endP = CGPointMake(250, 300);
    self.controlP = CGPointMake(100, 100); self.pathColor = [UIColor redColor];
    self.pathWidth = 2;
    }
    return self;
    } /// 绘制二阶贝塞尔曲线
    - (void)drawRect:(CGRect)rect { // 绘制贝塞尔曲线 self.path = [UIBezierPath bezierPath];
    [self.path moveToPoint:self.startP]; [self.path addQuadCurveToPoint:self.endP controlPoint:self.controlP]; self.path.lineWidth = self.pathWidth;
    [self.pathColor setStroke];
    [self.path stroke]; // 绘制辅助线 self.path = [UIBezierPath bezierPath]; self.path.lineWidth = 1;
    [[UIColor grayColor] setStroke]; CGFloat lengths[] = {5};
    [self.path setLineDash:lengths count:1 phase:1]; [self.path moveToPoint:self.controlP];
    [self.path addLineToPoint:self.startP];
    [self.path stroke]; [self.path moveToPoint:self.controlP];
    [self.path addLineToPoint:self.endP];
    [self.path stroke]; // 绘制辅助点及信息 self.path = [UIBezierPath bezierPathWithArcCenter:self.startP radius:4 startAngle:0 endAngle:M_PI * 2 clockwise:YES];
    [[UIColor blackColor] setStroke];
    [self.path fill]; self.path = [UIBezierPath bezierPathWithArcCenter:self.endP radius:4 startAngle:0 endAngle:M_PI * 2 clockwise:YES];
    [[UIColor blackColor] setStroke];
    [self.path fill]; self.path = [UIBezierPath bezierPathWithArcCenter:self.controlP radius:3 startAngle:0 endAngle:M_PI * 2 clockwise:YES];
    self.path.lineWidth = 2;
    [[UIColor blackColor] setStroke];
    [self.path stroke]; CGRect startMsgRect = CGRectMake(self.startP.x + 8, self.startP.y - 7, 50, 20);
    [@"起始点" drawInRect:startMsgRect withAttributes:nil]; CGRect endMsgRect = CGRectMake(self.endP.x + 8, self.endP.y - 7, 50, 20);
    [@"终止点" drawInRect:endMsgRect withAttributes:nil]; CGRect control1MsgRect = CGRectMake(self.controlP.x + 8, self.controlP.y - 7, 50, 20);
    [@"控制点" drawInRect:control1MsgRect withAttributes:nil];
    } /// 触摸开始
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event { // 获取触摸点位置
    CGPoint startPoint = [touches.anyObject locationInView:self]; CGRect startR = CGRectMake(self.startP.x - 4, self.startP.y - 4, 8, 8);
    CGRect endR = CGRectMake(self.endP.x - 4, self.endP.y - 4, 8, 8);
    CGRect controlR = CGRectMake(self.controlP.x - 4, self.controlP.y - 4, 8, 8); // 判断当前触摸点
    if (CGRectContainsPoint(startR, startPoint)) {
    self.currentTouchP = 1;
    } else if (CGRectContainsPoint(endR, startPoint)) {
    self.currentTouchP = 2;
    } else if (CGRectContainsPoint(controlR, startPoint)) {
    self.currentTouchP = 3;
    }
    } /// 触摸移动
    - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event { // 获取触摸点位置
    CGPoint touchPoint = [touches.anyObject locationInView:self]; // 限制触摸点的边界 if (touchPoint.x < 0) {
    touchPoint.x = 0;
    } if (touchPoint.x > self.bounds.size.width) {
    touchPoint.x = self.bounds.size.width;
    } if (touchPoint.y < 0) {
    touchPoint.y = 0;
    } if (touchPoint.y > self.bounds.size.height) {
    touchPoint.y = self.bounds.size.height;
    } // 设置当前触摸点的值
    switch (self.currentTouchP) {
    case 1:
    self.startP = touchPoint;
    break; case 2:
    self.endP = touchPoint;
    break; case 3:
    self.controlP = touchPoint;
    break; default:
    break;
    } // 刷新
    [self setNeedsDisplay];
    } /// 触摸结束
    - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event { // 释放之前的触摸点
    self.currentTouchP = 0;
    } /// 触摸取消
    - (void)touchesCancelled:(NSSet *)touches withEvent:(nullable UIEvent *)event {
    [self touchesEnded:touches withEvent:event];
    } @end
  • ViewController.m

    	CGRect frame = CGRectMake(20, 50, self.view.bounds.size.width - 40, 400);
    
    	QBezierPathView *pathView = [[QBezierPathView alloc] initWithFrame:frame];
    
    	pathView.backgroundColor = [UIColor whiteColor];
    pathView.layer.borderWidth = 1; [self.view addSubview:pathView];
  • 效果

3.2 三阶贝塞尔曲线示例

  • QBezierPathView.h

    	@interface QBezierPathView : UIView
    
    	@end
  • QBezierPathView.m

    	@interface QBezierPathView : UIView
    @interface QBezierPathView () /// 路径
    @property (nonatomic, strong) UIBezierPath *path; /// 起始点
    @property (nonatomic, assign) CGPoint startP; /// 终止点
    @property (nonatomic, assign) CGPoint endP; /// 控制点
    @property (nonatomic, assign) CGPoint controlP1;
    @property (nonatomic, assign) CGPoint controlP2; /// 线的颜色
    @property (nonatomic, strong) UIColor *pathColor; /// 线的宽度
    @property (nonatomic, assign) CGFloat pathWidth; /// 当前触摸的点
    @property (nonatomic, assign) NSUInteger currentTouchP; @end @implementation QBezierPathView /// 初始化
    - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { // 设置初始值 self.startP = CGPointMake(20, 300);
    self.endP = CGPointMake(250, 300);
    self.controlP1 = CGPointMake(100, 100);
    self.controlP2 = CGPointMake(200, 350); self.pathColor = [UIColor redColor];
    self.pathWidth = 2;
    }
    return self;
    } /// 绘制二阶贝塞尔曲线
    - (void)drawRect:(CGRect)rect { // 绘制贝塞尔曲线 self.path = [UIBezierPath bezierPath];
    [self.path moveToPoint:self.startP]; [self.path addCurveToPoint:self.endP controlPoint1:self.controlP1 controlPoint2:self.controlP2]; self.path.lineWidth = self.pathWidth;
    [self.pathColor setStroke];
    [self.path stroke]; // 绘制辅助线 self.path = [UIBezierPath bezierPath]; self.path.lineWidth = 1;
    [[UIColor grayColor] setStroke]; CGFloat lengths[] = {5};
    [self.path setLineDash:lengths count:1 phase:1]; [self.path moveToPoint:self.controlP1];
    [self.path addLineToPoint:self.startP];
    [self.path stroke]; [self.path moveToPoint:self.controlP1];
    [self.path addLineToPoint:self.controlP2];
    [self.path stroke]; [self.path moveToPoint:self.controlP2];
    [self.path addLineToPoint:self.endP];
    [self.path stroke]; // 绘制辅助点及信息 self.path = [UIBezierPath bezierPathWithArcCenter:self.startP radius:4 startAngle:0 endAngle:M_PI * 2 clockwise:YES];
    [[UIColor blackColor] setStroke];
    [self.path fill]; self.path = [UIBezierPath bezierPathWithArcCenter:self.endP radius:4 startAngle:0 endAngle:M_PI * 2 clockwise:YES];
    [[UIColor blackColor] setStroke];
    [self.path fill]; self.path = [UIBezierPath bezierPathWithArcCenter:self.controlP1 radius:3 startAngle:0 endAngle:M_PI * 2 clockwise:YES];
    self.path.lineWidth = 2;
    [[UIColor blackColor] setStroke];
    [self.path stroke]; self.path = [UIBezierPath bezierPathWithArcCenter:self.controlP2 radius:3 startAngle:0 endAngle:M_PI * 2 clockwise:YES];
    self.path.lineWidth = 2;
    [[UIColor blackColor] setStroke];
    [self.path stroke]; CGRect startMsgRect = CGRectMake(self.startP.x + 8, self.startP.y - 7, 50, 20);
    [@"起始点" drawInRect:startMsgRect withAttributes:nil]; CGRect endMsgRect = CGRectMake(self.endP.x + 8, self.endP.y - 7, 50, 20);
    [@"终止点" drawInRect:endMsgRect withAttributes:nil]; CGRect control1MsgRect = CGRectMake(self.controlP1.x + 8, self.controlP1.y - 7, 50, 20);
    [@"控制点1" drawInRect:control1MsgRect withAttributes:nil]; CGRect control2MsgRect = CGRectMake(self.controlP2.x + 8, self.controlP2.y - 7, 50, 20);
    [@"控制点2" drawInRect:control2MsgRect withAttributes:nil];
    } /// 触摸开始
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event { // 获取触摸点位置
    CGPoint startPoint = [touches.anyObject locationInView:self]; CGRect startR = CGRectMake(self.startP.x - 4, self.startP.y - 4, 8, 8);
    CGRect endR = CGRectMake(self.endP.x - 4, self.endP.y - 4, 8, 8);
    CGRect controlR1 = CGRectMake(self.controlP1.x - 4, self.controlP1.y - 4, 8, 8);
    CGRect controlR2 = CGRectMake(self.controlP2.x - 4, self.controlP2.y - 4, 8, 8); // 判断当前触摸点
    if (CGRectContainsPoint(startR, startPoint)) {
    self.currentTouchP = 1;
    } else if (CGRectContainsPoint(endR, startPoint)) {
    self.currentTouchP = 2;
    } else if (CGRectContainsPoint(controlR1, startPoint)) {
    self.currentTouchP = 3;
    } else if (CGRectContainsPoint(controlR2, startPoint)) {
    self.currentTouchP = 4;
    }
    } /// 触摸移动
    - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event { // 获取触摸点位置
    CGPoint touchPoint = [touches.anyObject locationInView:self]; // 限制触摸点的边界 if (touchPoint.x < 0) {
    touchPoint.x = 0;
    } if (touchPoint.x > self.bounds.size.width) {
    touchPoint.x = self.bounds.size.width;
    } if (touchPoint.y < 0) {
    touchPoint.y = 0;
    } if (touchPoint.y > self.bounds.size.height) {
    touchPoint.y = self.bounds.size.height;
    } // 设置当前触摸点的值
    switch (self.currentTouchP) {
    case 1:
    self.startP = touchPoint;
    break; case 2:
    self.endP = touchPoint;
    break; case 3:
    self.controlP1 = touchPoint;
    break; case 4:
    self.controlP2 = touchPoint;
    break; default:
    break;
    } // 刷新
    [self setNeedsDisplay];
    } /// 触摸结束
    - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event { // 释放之前的触摸点
    self.currentTouchP = 0;
    } /// 触摸取消
    - (void)touchesCancelled:(NSSet *)touches withEvent:(nullable UIEvent *)event {
    [self touchesEnded:touches withEvent:event];
    } @end
  • ViewController.m

    	CGRect frame = CGRectMake(20, 50, self.view.bounds.size.width - 40, 400);
    
    	QBezierPathView *pathView = [[QBezierPathView alloc] initWithFrame:frame];
    
    	pathView.backgroundColor = [UIColor whiteColor];
    pathView.layer.borderWidth = 1; [self.view addSubview:pathView];
  • 效果

iOS - Quartz 2D 贝塞尔曲线的更多相关文章

  1. iOS - Quartz 2D 二维绘图

    1.Quartz 2D 简介 Quartz 2D 属于 Core Graphics(所以大多数相关方法的都是以 CG 开头),是 iOS/Mac OSX 提供的在内核之上的强大的 2D 绘图引擎,并且 ...

  2. iOS之UIBezierPath贝塞尔曲线属性简介

    #import <Foundation/Foundation.h> #import <CoreGraphics/CoreGraphics.h> #import <UIKi ...

  3. iOS - Quartz 2D 第三方框架 Charts 绘制图表

    1.Charts 简介 使用第三方框架 Charts 绘制 iOS 图表.GitHub 源码 Charts Charts 是一款用于绘制图表的框架,可以绘制柱状图.折线图.K线图.饼状图等.Chart ...

  4. IOS Quartz 2D 学习(1)

    IOS提供两种创建图形的途径: 1.OpenGL. 2.Quartz.Core Animation.UIKit图形支持. UIKit的图形系统 1.视图绘画周期: DrawRect方法,在任何时候,当 ...

  5. iOS - Quartz 2D 画板绘制

    1.绘制画板 1.1 绘制简单画板 PaintBoardView.h @interface PaintBoardView : UIView @end PaintBoardView.m @interfa ...

  6. iOS - Quartz 2D 手势截屏绘制

    1.绘制手势截屏 具体实现代码见 GitHub 源码 QExtension QTouchClipView.h @interface QTouchClipView : UIView /** * 创建手势 ...

  7. iOS - Quartz 2D 下载进度按钮绘制

    1.绘制下载进度按钮 具体实现代码见 GitHub 源码 QExtension QProgressButton.h @interface QProgressButton : UIButton /// ...

  8. iOS 2D绘图详解(Quartz 2D)之路径(点,直线,虚线,曲线,圆弧,椭圆,矩形)

    前言:一个路径可以包含由一个或者多个shape以及子路径subpath,quartz提供了很多方便的shape可以直接调用.例如:point,line,Arc(圆弧),Curves(曲线),Ellip ...

  9. IOS用CGContextRef画各种图形(文字、圆、直线、弧线、矩形、扇形、椭圆、三角形、圆角矩形、贝塞尔曲线、图片)

    ... 首先了解一下CGContextRef: An opaque type that represents a Quartz 2D drawing environment. Graphics Con ...

随机推荐

  1. POJ 1222 EXTENDED LIGHTS OUT [高斯消元XOR]

    题意: $5*6$网格里有一些灯告诉你一开始开关状态,按一盏灯会改变它及其上下左右的状态,问最后全熄灭需要按那些灯,保证有解 经典问题 一盏灯最多会被按一次,并且有很明显的异或性质 一个灯作为一个方程 ...

  2. 调试 smallcorgi/Faster-RCNN_TF 的demo过程遇到的问题

    最近在调试faster R-CNN时,遇到了各种各样的问题.使用的算法库为https://github.com/smallcorgi/Faster-RCNN_TF 注:本文使用的是通过virtuale ...

  3. 使用performance进行网页性能监控

    由于项目需要, 需要对网页的一些性能进行监控, 接触到了performance, window.performance 提供了一组精确的数据,经过简单的计算就能得出一些网页性能数据, 将这些数据存储为 ...

  4. 携程Apollo(阿波罗)配置中心用户管理和部门管理

    Apollo是配置管理系统,会提供权限管理(Authorization),理论上是不负责用户登录认证功能的实现(Authentication).所以Apollo定义了一些SPI用来解耦,Apollo接 ...

  5. hiveql函数笔记(二)

    1.数据查询 //提高聚合的性能 SET hive.map.aggr=true; SELECT count(*),avg(salary) FROM employees; //木匾不允许在一个查询语句中 ...

  6. CentOS7上Docker安装与卸载

    安装 1.安装Docker 参见:https://docs.docker.com/engine/installation/linux/centos/ 2.直接使用root安装(更新系统) yum up ...

  7. Linux 编译安装 php 扩展包 curl

    php源码目录:/root/php php编译目录:/usr/local/webserver/php/ curl源码目录:/root/curl 1.curl,主要用于发送http请求,是php的一个扩 ...

  8. C# 托管堆和垃圾回收器GC

    这里我们讨论的两个东西:托管堆和垃圾回收器,前者是负责创建对象并控制这些对象的生存周期,后者负责回收这些对象. 一.托管堆分配资源 CLR要求所有的对象都从托管堆分配.进程初始化时,CLR划出一个地址 ...

  9. mysql存储引擎、事务

    MySQL存储引擎介绍 文件系统 操作系统组织和存取数据的一种机制. 文件系统是一种软件. 文件系统类型 ext2  ext3  ext4  xfs 数据 不管使用什么文件系统,数据内容不会变化 不同 ...

  10. Mysql数据库建立索引的优缺点有哪些?

    索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息. 什么是索引 数据库索引好比是一本书前面的目录,能加快数据库的查询速度. 例如这样一个查询:select * ...