CGPath复制lineJoin和miterLimit没有明显影响 [英] CGPath copy lineJoin and miterLimit has no apparent affect

查看:126
本文介绍了CGPath复制lineJoin和miterLimit没有明显影响的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用



使用斜接的代码(请注意,使用 CGLineJoin.round 会产生相同的结果):

  let pathOffset = path.copy(strokingWithWidth:4.0,
lineCap:CGLineCap.butt,
lineJoin:CGLineJoin.miter,
mimitLimit:20.0)

context .saveGState()

context.setStrokeColor(UIColor.red.cgColor)
context.addPath(pathOffset)
context.strokePath()

context .restoreGState()

使用斜角的代码:

  let pathOffset = path.copy(strokingWithWidth:4.0,
lineCap:CGLineCap.butt,
lineJoin:CGLineJoin.bevel,
miterLimit:0.0)

context.saveGState()

context.setStrokeColor(UIColor.red.cgColor)
context.addPath(pathOffset)
context .strokePath()

context.restoreGState()


解决方案

这是一条包含两个线段的路径:





这是我用斜角连接以30的线宽对其进行描画的样子:





如果我使用相同的参数制作路径的描边副本,则描边副本如下所示:



< a href = https://i.stack.imgur.com/OV9De.png rel = noreferrer>



注意到那里有三角形吗?之所以出现这种情况,是因为Core Graphics以一种简单的方式创建描边副本:它沿着原始路径的每个段进行跟踪,从而创建了一个偏移了15点的复制段。它用直线将这些复制的段中的每一个连接起来(因为我指定了斜角连接)。在慢动作中,复制操作如下所示:





因此,在关节的内部,我们得到一个三角形,在关节的外部,我们得到平坦的斜角。



当Core Graphics描画原始路径时,该三角形这是无害的,因为Core Graphics使用



现在,假设我用一条很短的线连接的两个关节替换了原始路径中的单个关节。 (很小)底部的平坦点:





当我绘制此路径的描边副本时,该副本具有两个内部三角形,如果描边描边的副本,则它看起来像这样:





因此,当您绘制路径的描边副本时,那些奇怪的形状就是星形形状的来源:非常短的段创建重叠的三角形。



请注意,我是用倒角连接制作副本的。复制时使用斜角连接也会创建隐藏的三角形,因为连接的选择只会影响关节的外部,而不影响关节的内部。



但是,在描边描边副本时,选择连接很重要很重要,因为使用斜接连接会使星星变大。请参阅



这里的星星几乎是不可见的,因为三角形是用钝角绘制的。



如果内部三角形对您来说是不可接受的,则必须编写自己的函数(或在Internet上找到一个函数)以制作不带三角形的笔触路径副本,或从副本中消除三角形。



如果path完全由平面段组成,最简单的解决方案可能是使用现有的多边形剪切库。应用于描边副本的联合操作应消除内部三角形。 例如,请参见此答案。请注意,这些库往往是用C ++编写的,因此您可能必须编写一些库因为Swift无法直接调用C ++代码,所以使用Objective-C ++代码。



如果您想知道如何为该答案生成图形,请使用这个Swift游乐场


I am offsetting a CGPath using copy(strokingWithWidth:lineCap:lineJoin:miterLimit:transform‌​:). The problem is the offset path introduces all kinds of jagged lines that seem to be the result of a miter join. Changing the miterLimit to 0 has no effect, and using a bevel line join also makes no difference.

In this image there is the original path (before applying strokingWithWidth), an offset path using miter join, and an offset path using bevel join. Why doesn't using bevel join have any affect?

Code using miter (Note that using CGLineJoin.round produces identical results):

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()

Code using bevel:

let pathOffset = path.copy(strokingWithWidth: 4.0, 
                           lineCap: CGLineCap.butt,
                           lineJoin: CGLineJoin.bevel,
                           miterLimit: 0.0)

context.saveGState()

context.setStrokeColor(UIColor.red.cgColor)
context.addPath(pathOffset)
context.strokePath()

context.restoreGState()

解决方案

Here is a path consisting of two line segments:

Here's what it looks like if I stroke it with bevel joins at a line width of 30:

If I make a stroked copy of the path with the same parameters, the stroked copy looks like this:

Notice that triangle in there? That appears because Core Graphics creates the stroked copy in a simple way: it traces along the each segment of the original path, creating a copied segment that is offset by 15 points. It joins each of these copied segments with straight lines (because I specified bevel joins). In slow motion, the copy operation looks like this:

So on the inside of the joint, we get a triangle, and on the outside, we get the flat bevel.

When Core Graphics strokes the original path, that triangle is harmless, because Core Graphics uses the non-zero winding rule to fill the stroke. But when you stroke the stroked copy, the triangle becomes visible.

Now, if I scale down the line width used when I make the stroked copy, the triangle becomes smaller. And if I then increase the line width used to draw the stroked copy, and draw the stroked copy with mitered joins, the triangle can actually end up looking like it's filled in:

Now, suppose I replace that single joint in the original path with two joints connected by a very short line, creating a (very small) flat spot on the bottom:

When I make a stroked copy of this path, the copy has two internal triangles, and if I stroke the stroked copy, it looks like this:

So that's where those weird shapes star shapes come from when you make a stroked copy of your paths: very short segments creating overlapping triangles.

Note that I made my copies with bevel joins. Using miter joins when making the copy also creates the hidden triangles, because the choice of join only affects the outside of the joint, not the inside of the joint.

However, the choice of join does matter when stroking the stroked copy, because the use of miter joins makes the stars larger. See this document for a good illustration of how much the join style can affect the appearance of an acute angle.

So the miter joins make the triangles' points stick out quite far, which makes the overlapping triangles look like a star. Here's the result if I stroke the stroked copy using bevel joins instead:

The star is nigh-invisible here because the triangles are drawn with blunted corners.

If the inner triangles are unacceptable to you, you will have to write your own function (or find one on the Internet) to make a stroked copy of the path without the triangles, or to eliminate the triangles from the copy.

If your path consists entirely of flat segments, the easiest solution is probably to use an existing polygon-clipping library. The "union" operation, applied to the stroked copy, should eliminate the inner triangles. See this answer for example. Note that these libraries tend to be written in C++, so you'll probably have to write some Objective-C++ code since Swift cannot call C++ code directly.

In case you're wondering how I generated the graphics for this answer, I did it using this Swift playground.

这篇关于CGPath复制lineJoin和miterLimit没有明显影响的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆