BezierCurve -> 贝塞尔曲线

一、贝塞尔曲线简介:

贝塞尔曲线是应用于二维图形应用程序的数学曲线。贝兹曲线由线段节点组成,节点是可拖动的支点,线段像可伸缩的皮筋。它通过控制曲线上的四个点(起始点、终止点以及两个相互分离的中间点)来创造、编辑图形。其中起重要作用的是位于曲线中央的控制线。这条线是虚拟的,中间与贝塞尔曲线交叉,两端是控制端点。移动两端的端点时贝塞尔曲线改变曲线的曲率(弯曲的程度);移动中间点(也就是移动虚拟的控制线)时,贝塞尔曲线在起始点和终止点锁定的情况下做均匀移动。

bezier.jpg

在iOS中,使用UIBezierPath类完成贝塞尔曲线的绘制,UIBezierPath可以创建基于矢量的路径。这个类继承于NSObject,在UIKit中它是基于Core Graphics对CGPathRef数据类型和path绘图属性的一个封装,需要图形上下文(CGContextRef),所以一般UIBezierPath在drawRect中使用(当然也有例外~)。

二、属性方法:

1、以下方法均为类方法创建UIBezierPath的方法

+ (instancetype)bezierPath;

// 根据CGRect绘制矩形;
+ (instancetype)bezierPathWithRect:(CGRect)rect;

// 根据CGRect绘制内切椭圆(若rect是正方形,那就是内切圆~)
+ (instancetype)bezierPathWithOvalInRect:(CGRect)rect;

// 设置可自定义圆角大小的圆角矩形
+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect cornerRadius:(CGFloat)cornerRadius;

 // 设置指定角是圆弧的矩形
/*
typedef NS_OPTIONS(NSUInteger, UIRectCorner) {
    UIRectCornerTopLeft     = 1 << 0, // 左上角
    UIRectCornerTopRight    = 1 << 1, // 右上角
    UIRectCornerBottomLeft  = 1 << 2, // 左下角
    UIRectCornerBottomRight = 1 << 3, // 右下角 
    UIRectCornerAllCorners  = ~0UL // 全部四个角
};
*/
+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect byRoundingCorners:(UIRectCorner)corners cornerRadii:(CGSize)cornerRadii;

// 根据中心圆点、半径、开始角度、终止角度、是否是顺时针方向创建圆弧(yes 顺时针,no逆时针)
+ (instancetype)bezierPathWithArcCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise;

// 通过已有路径创建路径
+ (instancetype)bezierPathWithCGPath:(CGPathRef)CGPath;

PS:弧线参考系

弧线参考系

2、对曲线的路径设置及其他属性的设置

//将UIBezierPath转换成一个不可变的CGPathRef类型数据类似于UIColor的CGColor
@property(nonatomic) CGPathRef CGPath;
- (CGPathRef)CGPath;

#prama --------  具体设计路径的相关方法
// 路径移动到某一点(设置起点point即起点位置)
- (void)moveToPoint:(CGPoint)point;
// 在前往某一点(point)路径上划直线
- (void)addLineToPoint:(CGPoint)point;
//构建三次贝塞尔曲线,参数终点,两个控制点
- (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2;
// 构建二次贝塞尔曲线,终点,一个控制点
- (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint;
// 实例方法创建圆弧
- (void)addArcWithCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise ;
// 闭合路径,即在终点和起点连一根线
- (void)closePath;
// 移除路径
- (void)removeAllPoints;
// 添加路径
- (void)appendPath:(UIBezierPath *)bezierPath;
// 颠倒路径,起点变终点,终点变起点
- (UIBezierPath *)bezierPathByReversingPath;
// 对路径进行仿射变换
- (void)applyTransform:(CGAffineTransform)transform;

#prama  ------- 路径信息
@property(readonly,getter=isEmpty) BOOL empty; // 路径是否为空
@property(nonatomic,readonly) CGRect bounds;// 它获取曲线的外接矩形的frame
@property(nonatomic,readonly) CGPoint currentPoint;// path的当前点位置。对于圆或者椭圆来说是圆心,对于其他则是终点位置
- (BOOL)containsPoint:(CGPoint)point; // 路径上是否包含某一点

#prama ------------- 绘图属性
@property(nonatomic) CGFloat lineWidth; // 线宽
/*
线帽风格。线帽(line cap)是指线条两端的外观
typedef CF_ENUM(int32_t, CGLineCap) {
    kCGLineCapButt, // 无端点
    kCGLineCapRound, // 圆的
    kCGLineCapSquare // 平直的(看起来和kCGLineCapButt没啥差别···)
};
具体见图“线帽风格”
*/
@property(nonatomic) CGLineCap lineCapStyle;
/*
线段连接风格
typedef CF_ENUM(int32_t, CGLineJoin) {
    kCGLineJoinMiter, // 斜接
    kCGLineJoinRound, // 圆润衔接
    kCGLineJoinBevel // 有过渡斜面衔接
};
具体见图“线段连接风格”
*/
@property(nonatomic) CGLineJoin lineJoinStyle; 
// 最大斜接长度,只有在kCGLineJoinMiter下才有效果。因为当角度很小时斜接的长度会非常的长。所以可以设置一个最大斜接长度。
// 当斜接长度超过了该设置则以kCGLineJoinBevel的样式展示
@property(nonatomic) CGFloat miterLimit;
// 弯曲路径的渲染精度,默认为0.6,越小精度越高,相应的更加消耗性能
@property(nonatomic) CGFloat flatness;
// 是否使用奇偶规则用于绘制路径,默认是NO(详情见PS-1),如果使用-fill方法,则多边形内部填充颜色,外部不会填充
@property(nonatomic) BOOL usesEvenOddFillRule; 

// 设置线型,pattern--C类型的线型数据。如:CGFloat dashStyle[] = { 1.0f, 2.0f };count--pattern 包含元素的数量;phase--相位(一般是指,角度所在的象限)(一些举例:PS-dash)
- (void)setLineDash:(nullable const CGFloat *)pattern count:(NSInteger)count phase:(CGFloat)phase;
- (void)getLineDash:(nullable CGFloat *)pattern count:(nullable NSInteger *)count phase:(nullable CGFloat *)phase;

#prama 一下设置路径颜色分布两种模式均需在设置颜色情况下:
#prama  [[UIColor blueColor] set]、[[UIColor redColor] setFill]、[[UIColor yellowColor] setStroke];
// 填充模式
- (void)fill;
// 描边模式
- (void)stroke;

// 设置填充/描边的混合模式和透明度(CGBlendMode一般在设置图片中用途较大,详细见PS-2)
- (void)fillWithBlendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha;
- (void)strokeWithBlendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha;
// 添加剪裁
- (void)addClip;
线帽风格
线段连接风格

**PS-1: 奇偶判断规则(even-odd)--- 平面内的任何一点P,引出一条 射线这里强调一下,是射线而不是直线,一定要注意两者的区别),注意不要经过多边形的顶点,如果射线与多边形的交点的个数为奇数,则点P在多边形的内部,如果交点的个数为偶数,则点P在多边形的外部。

PS-1-扩展: 非零缠绕规则(non-zero)---- 平面内的任何一点P,引出一条 射线,注意不要经过多边形的顶点。然后将多边形的边矢量化,规定环绕数初始结果为0,多边形的边如果从射线的左边穿过则加1,如果从射线的右边穿过则减1,最终结果累加,如果为0,则点P在多边的外面;如果非0则点P在多边形的内部。

**举例: **

在P点引出的射线与图形边界交点为2,偶数,所以使用奇偶判断规则P点在多边形外部,同理则P1在多边形内部
可以看到P点环绕数为2,不为0,所以P点在多边形内部,同理P1点环绕数为-1,也在多边形内部

从上边可以看到奇偶判断规则与非零缠绕规则判断的结果可能是矛盾的,所以遵循了什么什么规则,对于绘图来说很重要。

PS-dash:

一些虚线缓冲🌰

PS-2: 混合模式:这一混合模式常用于图片(image)设置,要特别注意kCGBlendModeOverlay(保持背景灰度)、kCGBlendModeColor(保持图片灰度)、kCGBlendModeDestinationIn(保持图片透明度信息)、kCGBlendModeDestinationOut(与图片透明度相反信息)这四种混合模式

typedef CF_ENUM (int32_t, CGBlendMode) {
    /* Available in Mac OS X 10.4 & later. */
    kCGBlendModeNormal, // 保持原色
    kCGBlendModeMultiply, // 混合了前景和背景的颜色样本,最终颜色比原先的都暗
    kCGBlendModeScreen, // 复合反转的原图和背景图样本,与Multiply相反
    kCGBlendModeOverlay, // 可以保持背景色的明暗,也就是灰度信息.
    kCGBlendModeDarken, // 从源图像或北京选较暗的样品,背景样品被暗化样品取代,也就是暗化。
    kCGBlendModeLighten, // 与Darken相反(亮化)
    kCGBlendModeColorDodge, //加亮背景反射源图像(颜色变浅)
    kCGBlendModeColorBurn,// 与Dodge相反(颜色变深)
    kCGBlendModeSoftLight, // 根据源图像样本的颜色,变暗或减轻颜色,。如果源图像样本颜色比50%灰色轻,背景是减轻颜色比重,否则相反(柔光)
    kCGBlendModeHardLight, // 与SoftLight相反(强光)
    kCGBlendModeDifference, // 要么背景图像样本减去源图像样本颜色,或相反(差值),黑色则不变,白色则颠倒
    kCGBlendModeExclusion, // 低对比度的Difference
    kCGBlendModeHue, // 使用背景的亮度和饱和度值与源图像的色调进行混合(色调)
    kCGBlendModeSaturation, //使用背景的亮度值和色调与源图像的饱和度值进行混合(饱和度)
    kCGBlendModeColor, //使用背景的亮度值与源图像的饱和度值和色调进行混合,这种模式保留图像中灰色的水平。
    kCGBlendModeLuminosity, //使用背景的饱和度值和色调与源图像的亮度值进行混合。这种模式创建的效果与Color创建的效果相反!
/*
       R = D*Sa :结果色 = 目标色*原色的透明度
       R--结果色
       S--原色
       D--目标色
       Ra、Sa、Da分别为三种颜色的透明度
*/
    kCGBlendModeClear,                  /* R = 0 */
    kCGBlendModeCopy,                   /* R = S */
    kCGBlendModeSourceIn,               /* R = S*Da */
    kCGBlendModeSourceOut,              /* R = S*(1 - Da) */
    kCGBlendModeSourceAtop,             /* R = S*Da + D*(1 - Sa) */
    kCGBlendModeDestinationOver,        /* R = S*(1 - Da) + D */
    kCGBlendModeDestinationIn,          /* R = D*Sa */
    kCGBlendModeDestinationOut,         /* R = D*(1 - Sa) */
    kCGBlendModeDestinationAtop,        /* R = S*(1 - Da) + D*Sa */
    kCGBlendModeXOR,                    /* R = S*(1 - Da) + D*(1 - Sa) */
    kCGBlendModePlusDarker,             /* R = MAX(0, (1 - D) + (1 - S)) */
    kCGBlendModePlusLighter             /* R = MIN(1, S + D) */
};

举例代码:

- (void)drawRect:(CGRect)rect {
    
    [[UIColor blueColor] set];
    UIBezierPath * bezierPath = [UIBezierPath bezierPath];
    [bezierPath moveToPoint:CGPointMake(120, 100)];
    [bezierPath addLineToPoint:CGPointMake(220, 100)];
    [bezierPath addLineToPoint:CGPointMake(270, 187)];
    [bezierPath addLineToPoint:CGPointMake(220, 274)];
    [bezierPath addLineToPoint:CGPointMake(120, 274)];
    [bezierPath addLineToPoint:CGPointMake(70, 187)];
    [bezierPath closePath];
    bezierPath.lineWidth = 5.f;
    bezierPath.lineJoinStyle = kCGLineJoinMiter;
    bezierPath.usesEvenOddFillRule = NO;
    [bezierPath fillWithBlendMode:kCGBlendModeNormal alpha:0.5];
    
    [[UIColor redColor] setFill];
    UIBezierPath * bezier_0 = [UIBezierPath bezierPath];
    [bezier_0 moveToPoint:CGPointMake(170, 150)];
    [bezier_0 addQuadCurveToPoint:CGPointMake(170, 274) controlPoint:CGPointMake(50, 50)];
    bezier_0.lineWidth = 5.f;
    [bezier_0 fillWithBlendMode:kCGBlendModeOverlay alpha:1.0];
    [bezierPath appendPath:bezier_0];
    
    [[UIColor purpleColor] setFill];
    UIBezierPath * bezier_1 = [UIBezierPath bezierPath];
    [bezier_1 moveToPoint:CGPointMake(170, 150)];
    [bezier_1 addQuadCurveToPoint:CGPointMake(170, 274) controlPoint:CGPointMake(290, 50)];
    bezier_1.lineWidth = 5.f;
    [bezier_1 fillWithBlendMode:kCGBlendModeDarken alpha:1.0];
    [bezierPath appendPath:bezier_1];
    
    [[UIColor grayColor] setStroke];
    UIBezierPath * bezier_3 = [UIBezierPath bezierPath];
    [bezier_3 moveToPoint:CGPointMake(170, 150)];
    [bezier_3 addCurveToPoint:CGPointMake(170, 274) controlPoint1:CGPointMake(50, 212) controlPoint2:CGPointMake(220, 180)];
    bezier_3.lineWidth = 5.f;
    [bezier_3 stroke];
    [bezierPath appendPath:bezier_3];
    
    [[UIColor greenColor] setStroke];
    UIBezierPath * bezier_4 = [UIBezierPath bezierPath];
    [bezier_4 moveToPoint:CGPointMake(170, 150)];
    [bezier_4 addCurveToPoint:CGPointMake(170, 274) controlPoint1:CGPointMake(290, 212) controlPoint2:CGPointMake(120, 180)];
    bezier_4.lineWidth = 5.f;
    [bezier_4 stroke];
    [bezierPath appendPath:bezier_4];
}
效果图
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,383评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,522评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,852评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,621评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,741评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,929评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,076评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,803评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,265评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,582评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,716评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,395评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,039评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,027评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,488评论 2 361
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,612评论 2 350

推荐阅读更多精彩内容