BezierCurve -> 贝塞尔曲线

一、贝塞尔曲线简介:

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

BezierCurve -> 贝塞尔曲线_第1张图片
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:弧线参考系

BezierCurve -> 贝塞尔曲线_第2张图片
弧线参考系

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;
BezierCurve -> 贝塞尔曲线_第3张图片
线帽风格
BezierCurve -> 贝塞尔曲线_第4张图片
线段连接风格

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

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

**举例: **

BezierCurve -> 贝塞尔曲线_第5张图片
在P点引出的射线与图形边界交点为2,偶数,所以使用奇偶判断规则P点在多边形外部,同理则P1在多边形内部
BezierCurve -> 贝塞尔曲线_第6张图片
可以看到P点环绕数为2,不为0,所以P点在多边形内部,同理P1点环绕数为-1,也在多边形内部

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

PS-dash:

BezierCurve -> 贝塞尔曲线_第7张图片
一些虚线缓冲

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];
}
BezierCurve -> 贝塞尔曲线_第8张图片
效果图

你可能感兴趣的:(BezierCurve -> 贝塞尔曲线)