在上篇文章中,我们简单的理解了绘图上下文,今天我们来认识一下Quartz-2D中另一个重要的概念,路径(Paths)。 一、理解路径 路径定义了一个或多个形状,或是子路径。一个子路径可由直线,曲线,或者同时由两者构成。它可以是开放的,也可以是闭合的。一个子路径可以是简单的形状,如线、圆、矩形、星形;也可以是复杂的形状,如山脉的轮廓或者是涂鸦。图3-1显示了一些我们可以创建的路径。左上角的直线可以是虚线;直线也可以是实线。上边中间的路径是由多条曲线组成的开放路径。右上角的同心圆填充了颜色,但没有描边。左下角的加利福尼亚州是闭合路径,由许多曲线和直线构成,且对路径进行填充和描边。两个星形阐明了填充路径的两种方式,我们将详细描述。
二、创建及绘制路径 路径创建及路径绘制是两个独立的工作。首先我们创建路径。当我们需要渲染路径时,我们需要使用Quartz来绘制它。正如图3-1中所示,我们可以选择对路径进行描边,填充路径,或同时进行这两种操作。我们同样可以将其它对象绘制到路径所表示的范围内,即对对象进行裁减。
图3-3显示了多条独立绘制的路径。每个路径饮食随机生成的曲线,一些进行填充,另一些进行了描边。这些路径都包含在一个圆形裁减区域内。
三、构建块(Building Block) 函数CGContextAddArcToPoint用于为矩形创建内切弧的场景。Quartz使用我们提供的端点创建两条正切线。同样我们需要提供圆的半径。弧心是两条半径的交叉点,每条半径都与相应的正切线垂直。弧的两个端点是正切线的正切点,如图3-5所示。红色的部分是实际绘制的部分。
下面分别是画直线和圆弧的代码 直线:
1 // 1. 获取一个与视图相关联的上下文 2 CGContextRef context = UIGraphicsGetCurrentContext(); 3 4 // 2. 构建路径 5 // 2.1 设置上下文路径起点 6 CGContextMoveToPoint(context, 85, 85); 7 // 2.2 增加路径内容…… 8 CGContextAddLineToPoint(context, 150, 150); 9 CGContextAddLineToPoint(context, 250, 50); 10 // 3. 保存上下文状态 11 // 4. 设置上下文状态 12 // 4.1 设置边线颜色 13 CGContextSetRGBStrokeColor(context, 1, 0, 0, 1); 14 // 4.2 设置线宽 15 CGContextSetLineWidth(context, 10); 16 // 4.3 设置线段连接样式 17 CGContextSetLineJoin(context, kCGLineJoinRound); 18 // 4.4 设置线段收尾样式 19 CGContextSetLineCap(context, kCGLineCapRound); 20 // 4.5 设置虚线样式 21 // 4. 绘制路径 22 CGContextDrawPath(context, kCGPathStroke);
圆弧: // 1. 获取一个与视图相关联的上下文 CGContextRef context = UIGraphicsGetCurrentContext(); [[UIColor redColor]set]; // 2. 添加弧线 // 2.1 上下文 // 2.2 中心点坐标 // 2.3 半径 // 2.4 开始角度,结束角度,角度的单位是“弧度” CGContextAddArc(context, 160, 230, 100, M_PI, -M_PI_2, 0); // 绘制路径 CGContextStrokePath(context); 曲线
我们使用函数CGContextAddCurveToPoint将Bezier曲线连接到当前点,并传递控制点和端点作为参数,如图3-7所示。两个控制点的位置决定了曲线的形状。如果两个控制点都在两个端点上面,则曲线向上凸起。如果两个控制点都在两个端点下面,则曲线向下凹。如果第二个控制点比第一个控制点离得当前点近,则曲线自交叉,创建了一个回路。 我们也可以调用函数CGContextAddQuadCurveToPoint来创建Bezier,并传递端点及一个控制点,如图3-8所示。控制点决定了曲线弯曲的方向。由于只使用一个控制点,所以无法创建出如三次Bezier曲线一样多的曲线。例如我们无法创建出交叉的曲线 1 /*画贝塞尔曲线*/ 2 //二次曲线 3 CGContextMoveToPoint(context, 120, 300);//设置Path的起点 4 CGContextAddQuadCurveToPoint(context,190, 310, 120, 390);//设置贝塞尔曲线的控制点坐标和终点坐标 5 CGContextStrokePath(context); 6 //三次曲线函数 7 CGContextMoveToPoint(context, 200, 300);//设置Path的起点 8 CGContextAddCurveToPoint(context,250, 280, 250, 400, 280, 300);//设置贝塞尔曲线的控制点坐标和控制点坐标终点坐标 9 CGContextStrokePath(context);
闭合路径 椭圆 我们可以调用CGContextAddEllipseInRect函数来添加一个椭圆到当前路径。我们提供一个矩形来定义一个椭圆。Quartz利用一系列的Bezier曲线来模拟椭圆。椭圆的中心就是矩形的中心。如果矩形的宽与高相等,则椭圆变成了圆,且圆的半径为矩形宽度的一半。如果矩形的宽与高不相等,则定义了椭圆的长轴与短轴。 矩形 四、创建路径 当我们需要在一个图形上下文中构建一个路径时,我们需要调用CGContextBeginPath来标记Quartz。然后,我们调用函数CGContextMovePoint来设置每一个图形或子路径的起始点。在构建起始点后,我们可以添加直线、弧、曲线。记住如下规则:
在绘制路径后,将清空图形上下文。我们也许想保留路径,特别是在绘制复杂场景时,我们需要反复使用。基于此,Quartz提供了两个数据类型来创建可复用路径—CGPathRef和CGMutablePathRef。我们可以调用函数CGPathCreateMutable来创建可变的CGPath对象,并可向该对象添加直线、弧、曲线和矩形。Quartz提供了一个类似于操作图形上下文的CGPath的函数集合。这些路径函数操作CGPath对象,而不是图形上下文。这些函数包括:
如果想要添加一个路径到图形上下文,可以调用CGContextAddPath。路径将保留在图形上下文中,直到Quartz绘制它。我们可以调用CGContextAddPath再次添加路径。 五、绘制路径 我们可以绘制填充或描边的路径。描边(Stroke)是绘制路径的边框。填充是绘制路径包含的区域。Quartz提供了函数来填充或描边路径。描边线的属性(宽度、颜色等),填充色及Quartz用于计算填充区域的方法都是图形状态的一部分。 linewidth是线的总宽度,单位是用户空间单元。
linecap指定如何绘制直线的端点。Quartz支持表3-3所示的线帽类型。默认的是butt cap。
闭合路径将起始点看作是一个联接点;起始点同样也使用选定的直线连接方法进行渲染。如果通过添加一条连接到起始点的直线来闭合路径,则路径的两个端点都使用选定的线帽类型来绘制。 CGContextSetLineDash结构如下:
1 void CGContextSetLineDash ( 2 CGContextRef ctx, 3 float phase, 4 const float lengths[], 5 size_t count, 6 ); 其中lengths属性指定了虚线段的长度,该值是在绘制片断与未绘制片断之间交替。phase属性指定虚线模式的起始点。图3-11显示了虚线模式: 路径描边的函数
函数CGContextStrokeLineSegments等同于如下代码 1 CGContextBeginPath(context); for(k = 0; k < count; k += 2) { CGContextMoveToPoint(context,s[k].x, s[k].y); CGContextAddLineToPoint(context,s[k+1].x, s[k+1].y);}CGContextStrokePath(context); 当我们调用CGContextStrokeLineSegments时,我们通过点数组来指定线段,并组织成点对的形式。每一对是由线段的起始点与终止点组成。例如,数组的第一个点指定了第一条直线的起始点,第二个点是第一条直线的终点,第三个点是第二条直线的起始点,依此类推。
Quartz提供了表3-5中的函数来填充当前路径。其中一些是填充矩形及椭圆的便捷函数。
好,说了这么多下面上代码 1 - (void)drawLine1 2 { 3 // 1. 获取一个与视图相关联的上下文 4 CGContextRef context = UIGraphicsGetCurrentContext(); 5 6 // 2. 创建一个可变路径 7 // 2.1 创建路径 8 CGMutablePathRef path = CGPathCreateMutable(); 9 // 2.2 设置路径起点 10 CGPathMoveToPoint(path, NULL, 50, 50); 11 // 2.3 增加路径内容…… 12 CGPathAddLineToPoint(path, NULL, 150, 150); 13 CGPathAddLineToPoint(path, NULL, 50, 150); 14 // CGPathAddLineToPoint(path, NULL, 50, 50); 15 // 闭合路径,关闭路径,闭合路径是收尾相连的 16 CGPathCloseSubpath(path); 17 18 // 3. 将路径添加到上下文; 19 CGContextAddPath(context, path); 20 21 // 4. 设置上下文状态 22 // 4.1 设置边线颜色 23 // 颜色数值 = RGB数值 / 255 24 CGContextSetRGBStrokeColor(context, 255.0 / 255.0, 0.0, 0.0 , 1.0); 25 // 4.2 设置填充颜色 26 CGContextSetRGBFillColor(context, 0.0, 0.0, 128.0 / 255.0, 1.0); 27 // 4.3 设置线宽 28 CGContextSetLineWidth(context, 5); 29 // 4.4 设置线段连接样式 30 CGContextSetLineJoin(context, kCGLineJoinBevel); 31 // 4.5 设置线段首尾样式 32 CGContextSetLineCap(context, kCGLineCapRound); 33 // 4.6 设置虚线样式 34 // lengths 设置公有几条虚线,每条虚线的长度 35 // count 指的是lengths数组的长度 36 CGFloat lengthes[2] = {10.0, 10.0}; 37 CGContextSetLineDash(context, 0, lengthes, 2); 38 // 5. 绘制路径 39 /** 40 kCGPathStroke 绘制边线 41 kCGPathFill 填充 42 */ 43 CGContextDrawPath(context, kCGPathFillStroke); 44 // 6. 释放路径,不同对象对应着不同的release方法 45 CGPathRelease(path); 46 } 七、裁剪路径 当前裁剪区域是从路径中创建,作为一个遮罩,从而允许遮住我们不想绘制的部分。例如,我们有一个很大的图片,但只需要显示其中一小部分,则可以设置裁减区域来显示我们想显示的部分。 当我们绘制的时候,Quartz只渲染裁剪区域里面的东西。裁剪区域内的闭合路径是可见的;而在区域外的部分是不可见的。 当图形上下文初始创建时,裁减区域包含上下文所有的可绘制区域(例如,PDF上下文的media box)。我们可以通过设置当前路径来改变裁剪区域,然后使用裁减函数来取代绘制函数。裁剪函数与当前已有的裁剪区域求交集以获得路径的填充区域。因此,我们可以求交取得裁减区域,缩小图片的可视区域,但是不能扩展裁减区域。
1 Listing 3-1 Setting up a circular clip area 2 CGContextBeginPath(context); 3 CGContextAddArc(context, w/2, h/2, ((w>h) ? h : w)/2, 0, 2*PI, 0); 4 CGContextClosePath(context); 5 CGContextClip(context);
表3-6 裁减图形上下文的函数
|
|