Quartz 2D编程指南 (四) —— Paths路径(一)

版本记录

版本号 时间
V1.0 2018.09.04

前言

Quartz 2D框架相信大家都知道,也都一直在使用。Quartz 2D的API是纯C语言的,它是一个二维绘图引擎,同时支持iOS和Mac系统。Quartz 2D的API来自于Core Graphics框架,数据类型和函数基本都以CG作为前缀,接下来几篇我们就一起来看一下这个框架。感兴趣可以看上面几篇文章。
1. Quartz 2D编程指南 (一) —— 简介(一)
2. Quartz 2D编程指南 (二) —— Quartz 2D概览(二)
3. Quartz 2D编程指南 (三) —— 图形上下文(三)

Paths - 路径

路径定义一个或多个形状或子路径。 子路径可以包含直线,曲线或两者。 它可以是开放的或封闭的。 子路径可以是简单的形状,例如线,圆,矩形或星形,或者更复杂的形状,例如山脉的轮廓或抽象涂鸦。 图3-1显示了您可以创建的一些路径。 直线(图中左上角)是虚线;线条也可以是实心的。 弯曲的路径(在中间的顶部)由几条曲线组成,是一条开放的路径。 同心圆被填充,但没有被描边。 加利福尼亚州是一条封闭的道路,由许多曲线和线条组成,路径既有描边也有填充。 星星说明了填充路径的两个选项,您将在本章后面阅读这些选项。

Figure 3-1 Quartz supports path-based drawing

在本章中,您将了解构成路径的构建块,如何描边和绘制路径以及影响路径外观的参数。


Path Creation and Path Painting - 路径创建与路径绘制

路径创建和路径绘制是单独的任务。 首先,您创建一个路径。 如果要渲染路径,请求Quartz绘制它。 如图3-1所示,您可以选择描边路径,填充路径,或者描边和填充路径。 您还可以使用路径来约束路径边界内其他对象的绘制,实际上是创建剪切区域。

图3-2显示了已绘制的路径,其中包含两个子路径。 左边的子路径是一个矩形,右边的子路径是由直线和曲线组成的抽象形状。 每个子路径都被填充并且其轮廓被描边。

Figure 3-2 A path that contains two shapes, or subpaths

图3-3显示了独立绘制的多条路径。 每条路径都包含一条随机生成的曲线,其中一些曲线已填充,另一些曲线则被描边。绘图通过裁剪区域约束到圆形区域。

Figure 3-3 A clipping area constrains drawing

The Building Blocks - 构建Block

子路径由线,弧和曲线构成。 Quartz还提供了便捷功能,可通过单个函数调用添加矩形和椭圆。 点也是路径的基本构建块,因为点定义了形状的起始和结束位置。

1. Points - 点

点是x和y坐标,用于指定用户空间中的位置。 您可以调用函数CGContextMoveToPoint来指定新子路径的起始位置。 Quartz跟踪当前点,这是用于路径构建的最后位置。 例如,如果调用函数CGContextMoveToPoint将位置设置为(10,10),则会将当前点移动到(10,10)。 如果然后绘制一条长50个单位的水平线,则该线上的最后一个点(60,10)将成为当前点。 始终从当前点开始绘制直线,圆弧和曲线。

大多数情况下,通过向Quartz函数传递两个浮点值来指定一个点来指定x和y坐标。 某些函数要求您传递CGPoint数据结构,该结构包含两个浮点值。

2. Lines - 线

一条线由其端点定义。 它的起始点始终假定为当前点,因此在创建线时,只指定其端点。 使用函数CGContextAddLineToPoint将单行线附加到子路径。

您可以通过调用函数CGContextAddLines将一系列连接的线添加到路径中。 您将此函数传递给一系列点。 第一点必须是第一行的起点,剩下的点是端点。 Quartz在第一个点开始一个新的子路径,并将一个直线段连接到每个端点。

3. Arcs - 弧

弧是圆弧段。 Quartz提供了两个创建弧的函数。 函数CGContextAddArc从圆创建一个弯曲的段。 您可以指定圆的中心,半径和径向角(以弧度表示)。 您可以通过指定2 pi的径向角度来创建整圆。 图3-4显示了独立绘制的多条路径。 每条路径包含一个随机生成的圆;有些被填满,有些被描边。

Figure 3-4 Multiple paths; each path contains a randomly generated circle

当您想要对矩形的角进行圆角时,CGContextAddArcToPoint函数是理想的选择。 Quartz使用您提供的端点来创建两条切线。 您还提供了Quartz切割圆弧的圆的半径。 弧的中心点是两个半径的交点,每个半径垂直于两条切线中的一条。 弧的每个端点都是其中一条切线上的切点,如图3-5所示。 圆圈的红色部分实际上是绘制的。

Figure 3-5 Defining an arc with two tangent lines and a radius

如果当前路径已包含子路径,则Quartz会将当前点的直线段附加到弧的起始点。 如果当前路径为空,Quartz会在弧的起始点创建一个新的子路径,并且不会添加初始直线段。

4. Curves - 曲线

二次和三次Bézier曲线是代数曲线,可以指定任意数量的有趣曲线形状。 通过将多项式公式应用于起点和终点以及一个或多个控制点来计算这些曲线上的点。 以这种方式定义的形状是矢量图形的基础。 公式比位数组更紧凑更容易存储,并且具有可以在任何分辨率下重新创建曲线的优点。

图3-6显示了通过独立绘制多个路径创建的各种曲线。 每条路径包含一条随机生成的曲线;有些被填满,有些被描边。

Figure 3-6 Multiple paths; each path contains a randomly generated curve

在许多数学文本和描述计算机图形的在线资源中讨论了产生二次和三次Bézier曲线的多项式公式,以及如何从公式生成曲线的细节。 这里不讨论这些细节。

使用CGContextAddCurveToPoint函数,使用您指定的控制点和端点,从当前点追加三次贝塞尔曲线。 图3-7显示了由图中所示的当前点,控制点和端点产生的三次Bézier曲线。 两个控制点的放置决定了曲线的几何形状。 如果控制点都在起点和终点之上,则曲线向上拱起。 如果控制点都低于起点和终点,则曲线向下拱起。

Figure 3-7 A cubic Bézier curve uses two control points

您可以通过调用CGContextAddQuadCurveToPoint函数并指定控制点和端点,从当前点追加二次Bézier曲线。 图3-8显示了使用相同端点但控制点不同的两条曲线。 控制点确定曲线拱起的方向。 由于二次曲线仅使用一个控制点,因此不可能使用二次贝塞尔曲线创建尽任意多的有趣形状。 例如,无法使用单个控制点创建交叉。

Figure 3-8 A quadratic Bézier curve uses one control point

5. Closing a Subpath - 关闭子路径

要关闭当前子路径,应用程序应调用CGContextClosePath。 此函数添加从当前点到子路径起点的线段,并关闭子路径。 以子路径起点结束的直线,圆弧和曲线实际上不会关闭子路径。 您必须显式调用CGContextClosePath才能关闭子路径。

一些Quartz函数将路径的子路径视为应用程序关闭它们。 这些命令将每个子路径视为您的应用程序调用CGContextClosePath来关闭它,隐式地将一个线段添加到子路径的起始点。

关闭子路径后,如果应用程序进行额外调用以向路径添加直线,圆弧或曲线,Quartz将从刚刚关闭的子路径的起点开始一个新的子路径。

6. Ellipses - 椭圆

椭圆本质上是一个压扁的圆圈。 您可以通过定义两个焦点来创建一个焦点,然后绘制位于一定距离的所有点,以便将椭圆上任意点到一个焦点的距离加上到从该点到另一个焦点的距离这个和始终是相同的值。 图3-9显示了独立绘制的多条路径。 每条路径包含一个随机生成的椭圆;有些被填满,有些被描边。

Figure 3-9 Multiple paths; each path contains a randomly generated ellipse

您可以通过调用函数CGContextAddEllipseInRect将椭圆添加到当前路径。 您提供了一个定义椭圆边界的矩形。 Quartz使用一系列Bézier曲线近似椭圆。 椭圆的中心是矩形的中心。 如果矩形的宽度和高度相等(即正方形),则椭圆为圆形,半径等于矩形宽度(或高度)的一半。 如果矩形的宽度和高度不相等,则它们定义椭圆的长轴和短轴。

添加到路径的椭圆以移动操作开始,以关闭子路径操作结束,所有移动都以顺时针方向定向。

7. Rectangles - 矩形

您可以通过调用函数CGContextAddRect将矩形添加到当前路径。 您提供了一个CGRect结构体,其中包含矩形的原点及其宽度和高度。

添加到路径的矩形以移动操作开始,以关闭子路径操作结束,所有移动都以逆时针方向定向。

您可以通过调用CGContextAddRects函数并提供CGRect结构数组,将许多矩形添加到当前路径。 图3-10显示了独立绘制的多条路径。 每个路径包含一个随机生成的矩形;有些被填满,有些被描边。

Figure 3-10 Multiple paths; each path contains a randomly generated rectangle

Creating a Path - 创建路径

如果要在图形上下文中构造路径,可以通过调用函数CGContextBeginPath来发出Quartz信号。接下来,通过调用函数CGContextMoveToPoint,在路径中设置第一个形状或子路径的起点。建立第一个点后,可以在路径中添加直线,圆弧和曲线,请记住以下内容:

  • 在开始新路径之前,请调用函数CGContextBeginPath
  • 从当前点开始绘制直线,圆弧和曲线。空路径没有当前点;你必须调用CGContextMoveToPoint来设置第一个子路径的起始点,或者调用一个方便的函数,隐式地为你做这个。
  • 如果要关闭路径中的当前子路径,请调用函数CGContextClosePath以将段连接到子路径的起始点。即使您未明确设置新的起点,后续路径调用也会开始新的子路径。
  • 绘制弧时,Quartz在当前点和弧的起点之间绘制一条线。
  • 添加椭圆和矩形的Quartz例程向路径添加新的闭合子路径。
  • 您必须调用绘制函数来填充或描边路径,因为创建路径不会绘制路径。有关详细信息,请参阅Painting a Path

绘制路径后,将从图形上下文中刷新它。您可能不希望如此轻易地丢失路径,特别是如果它描绘了您想要反复使用的复杂场景。因此,Quartz提供了两种用于创建可重用路径的数据类型-CGPathRefCGMutablePathRef。您可以调用函数CGPathCreateMutable来创建可变的CGPath对象,您可以在其中添加直线,圆弧,曲线和矩形。 Quartz提供了一组CGPath函数,这些函数与The Building Blocks中讨论的函数并行。路径函数在CGPath对象上运行,而不是在图形上下文上运行。这些函数是:

有关路径函数的完整列表,请参阅Quartz 2D Reference Collection

如果要将路径附加到图形上下文,请调用函数CGContextAddPath。路径保留在图形上下文中,直到Quartz绘制它。您可以通过调用CGContextAddPath再次添加路径。

注意:您可以通过调用函数CGContextReplacePathWithStrokedPath将图形上下文中的路径替换为路径的描边版本。

后记

本篇主要讲述了Paths路径,感兴趣的给个赞或者关注~~~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容