在此图像中,有原始路径(在应用strokingWithWidth之前),使用斜接连接的偏移路径,以及使用斜角连接的偏移路径.为什么不使用斜角连接有什么影响?
使用斜接的代码(注意使用CGLineJoin.round会产生相同的结果):
let pathOffset = path.copy(strokingWithWidth: 4.0,lineCap: CGLineCap.butt,lineJoin: CGLineJoin.miter,miterLimit: 20.0) context.saveGState() context.setStrokeColor(UIColor.red.cgColor) context.addPath(pathOffset) context.strokePath() context.restoreGState()
使用斜角的代码:
let pathOffset = path.copy(strokingWithWidth: 4.0,lineJoin: CGLineJoin.bevel,miterLimit: 0.0) context.saveGState() context.setStrokeColor(UIColor.red.cgColor) context.addPath(pathOffset) context.strokePath() context.restoreGState()
解决方法
如果我用线宽为30的斜面连接来划线它,它就是这样的:
如果我使用相同的参数创建路径的描边副本,则描边副本如下所示:
请注意那里的三角形?之所以出现这种情况,是因为Core Graphics以一种简单的方式创建了描边拷贝:它沿着原始路径的每个部分进行跟踪,创建一个偏移了15个点的复制段.它用直线连接每个复制的段(因为我指定了斜角连接).在慢动作中,复制操作如下所示:
因此,在关节内侧,我们得到一个三角形,在外面,我们得到平面斜面.
当Core Graphics描绘原始路径时,该三角形是无害的,因为Core Graphics使用non-zero winding rule填充笔划.但是当你抚摸描边的副本时,三角形变得可见.
现在,如果缩小我制作描边副本时使用的线宽,则三角形会变小.如果我然后增加用于绘制描边副本的线宽,并使用mitered连接绘制描边副本,那么三角形实际上最终可能看起来像是填充的:
现在,假设我用原来的路径替换了那个由一条很短的线连接的两个关节的单个关节,在底部创建一个(非常小的)平坦点:
当我制作这条路径的描边副本时,副本有两个内部三角形,如果我描边描边,它看起来像这样:
因此,当您制作路径的描边副本时,那些怪异形状的星形来自于:非常短的段创建重叠的三角形.
请注意,我使用斜角连接制作了我的副本.在制作副本时使用斜接连接也会创建隐藏的三角形,因为连接的选择仅影响关节的外部,而不影响关节的内部.
但是,在抚摸描边的副本时,连接的选择很重要,因为使用斜接连接会使星形变大.有关连接样式可以影响锐角外观的详细说明,请参见this document.
因此斜接连接使三角形的点伸出很远,这使得重叠的三角形看起来像一颗星.如果我使用斜角连接来描边描边的复制,那么结果如下:
这颗恒星在这里几乎看不见,因为三角形是用钝角绘制的.
如果内部三角形对您来说是不可接受的,则必须编写自己的函数(或在Internet上找到一个)来制作没有三角形的路径的描边副本,或者从副本中消除三角形.
如果您的路径完全由扁平段组成,则最简单的解决方案可能是使用现有的多边形裁剪库.应用于描边副本的“联合”操作应该消除内部三角形. See this answer for example.请注意,这些库往往是用C语言编写的,因此您可能不得不编写一些Objective-C代码,因为Swift无法直接调用C代码.
如果你想知道我是如何为这个答案生成图形的,我是用this Swift playground做的.