购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

2.3 Quartz路径

在绘制复杂图形的时候会用到路径,在2.2节的实例中如下代码都是与路径有关系的。

CGContextMoveToPoint(context, 75, 10);
CGContextAddLineToPoint(context, 10, 150);
CGContextAddLineToPoint(context, 160, 150);    
CGContextClosePath(context);
CGContextDrawPath(context, kCGPathFillStroke);

我们用路径来描述矩形、圆及其他想要画的2D几何图形。通过路径可以对这些几何图形进行描边、填充和描边填充处理。Core Graphics(Quartz 2D)中有4个基本图元用于描述路径:点、线段、弧和贝塞尔(Bézier)曲线。

1.点

点是二维空间中的一个位置,不要把它想成像素,一个点完全不占空间,所以画一个点不会在屏幕上显示任何东西,我们可以在路径里加入很多的点,想加多少加多少。

2.线段

线段由两个点定义:起点和终点。线段可以通过描边绘制出来,我们可以通过设置图形上下文,如画笔宽度或者颜色等参数,就可以绘制出两点之间的线段。线段没有面积,所以它们不能被填充。我们可以用一组线段或曲线组成一个具有闭合路径的几何图形,然后填充它。

3.弧

弧可以由一个圆心点、半径、起始角和结束角描述的。圆是弧的特例,只需要设置为起始角0°,结束角为360°就可以了。因为弧是占有一定面积的路径,所以可以被填充、描边和描边填充出来。

4.贝塞尔(Bézier)曲线

贝塞尔(Bézier)曲线是法国数学家贝塞尔在工作中发现,任何一条曲线都可以通过与它相切的控制线两端的点的位置来定义。因此,贝塞尔曲线可以用4个点描述,其中两个点描述两个端点,另外两个描述每一端的切线。贝塞尔曲线可以分为:二次方贝塞尔曲线(图2-9)和高阶贝塞尔曲线(图2-10是三次方贝塞尔曲线)。

图2-9 二次方贝塞尔曲线 图2-10 三次方贝塞尔曲线

下面解释一下2.2节实例中有关路径的代码,其中下面4条语句是绘制路径。

CGContextMoveToPoint(context, 75, 10);    
CGContextAddLineToPoint(context, 10, 150);
CGContextAddLineToPoint(context, 160, 150);    
CGContextClosePath(context);

其中,CGContextMoveToPoint (context,75,10)语句是在(75,10)绘制起始点。CGContextAddLineToPoint (context,10,150)是绘制从(75,10)到(10,150)线段。CGContextAddLineToPoint (context,160,150)是绘制从(10,150)到(160,150)线段。这样通过上面3条语句就定义了一个三角形路径,如图2-11所示,路径是按照(75,10)→(10,150)→(160,150)顺序定义的,因此它不是闭合的。如果需要闭合可以调用CGContextClosePath(context)函数实现,如图2-12所示。

图2-11 非闭合路径 图2-12 闭合路径

定义和绘制路径是两个不同的操作,先定义路径,再绘制它。CGContextDrawPath(context,kCGPathFillStroke)函数实现绘制路径,其中kCGPathFillStroke参数是填充描边处理,此外还有:kCGPathFill和kCGPathStroke,分别代表填充和描边处理。

下面介绍贝塞尔曲线定义路径的实例。如图2-13所示是半个瓶子的轮廓,它的轮廓很复杂,我们分成很多贝塞尔曲线,然后找到贝塞尔曲线的控制点,就可以绘制它了。

图2-13 曲线定义路径实例

请参照2.2节构建工程BezierCurve。自定义视图MyView.m代码如下。

#import "MyView.h"

@implementation MyView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
    }
    return self;
}

- (void)drawRect:(CGRect)rect
{    
    CGContextRef cgContext = UIGraphicsGetCurrentContext();
    
    CGContextMoveToPoint(cgContext, 333, 0);                              ①
    CGContextAddCurveToPoint(cgContext, 333, 0, 332, 26, 330, 26);        ②
    CGContextAddCurveToPoint(cgContext, 330, 26, 299, 20, 299, 17);       ③
    CGContextAddLineToPoint(cgContext, 296, 17);
    CGContextAddCurveToPoint(cgContext, 296, 17, 296, 19, 291, 19);
    CGContextAddLineToPoint(cgContext, 250, 19);
    CGContextAddCurveToPoint(cgContext, 250, 19, 241, 24, 238, 19);
    CGContextAddCurveToPoint(cgContext, 236, 20, 234, 24, 227, 24);
    CGContextAddCurveToPoint(cgContext, 220, 24, 217, 19, 216, 19);
    CGContextAddCurveToPoint(cgContext, 214, 20, 211, 22, 207, 20);
    CGContextAddCurveToPoint(cgContext, 207, 20, 187, 20, 182, 21);
    CGContextAddLineToPoint(cgContext, 100, 45);
    CGContextAddLineToPoint(cgContext, 97, 46);
    CGContextAddCurveToPoint(cgContext, 97, 46, 86, 71, 64, 72);
    CGContextAddCurveToPoint(cgContext, 42, 74, 26, 56, 23, 48);
    CGContextAddLineToPoint(cgContext, 9, 47);
    CGContextAddCurveToPoint(cgContext, 9, 47, 0, 31, 0, 0);              ④
    CGContextStrokePath(cgContext);

}

@end

上面代码第①~④行都是在定义这个瓶子的轮廓,其中CGContextAddCurveToPoint函数是定义贝塞尔曲线,函数定义如下。 lhStJ0Izgh+1j99EAP+Wgy/xjU39sigOkPlsP2n00BePuA9jqBaXXqKFeiFr5zt/

void CGContextAddCurveToPoint (
  CGContextRef c,
  CGFloat cp1x,                     //第一控制点 x坐标
  CGFloat cp1y,                     //第一控制点 y坐标
  CGFloat cp2x,                     //第二控制点 x坐标
  CGFloat cp2y,                     //第二控制点 y坐标
  CGFloat x,                        //结束点 x坐标
  CGFloat y                         //结束点 y坐标
);
点击中间区域
呼出菜单
上一章
目录
下一章
×