The copy line of CGPathJoin and miterLimit has no obvious effect

I offset the CGPath using copy (strokingWithWidth: lineCap: lineJoin: miterLimit: transform :) . The problem is that the offset path introduces all kinds of jagged lines that appear to be the result of combining the miter. Changing the value miterLimit

to 0 has no effect, and the use of a tapered connection is also irrelevant.

This image shows the original path (before application strokingWithWidth

), the displacement path using the mitral junction, and the displacement path using the tapered junction. Why is using a tapered connection not affected?

examples of ways

Code using miter (note that using CGLineJoin.round

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

      

+3


source to share


1 answer


Here is a path made up of two line segments:

main path

This is what it looks like if I stroke it with tapered connections at a line width of 30:

simple stroke

If I create an ironed copy of the path with the same parameters, the ironed copy looks like this:

ironed copy

Notice that the triangle is there? This appears because Core Graphics creates an ironed copy in a simple way: it tracks each segment of the original path, creating a copied segment that is offset by 15 points. It connects each of these copied segments with straight lines (because I defined the bevel of the join). In slow motion, the copy operation looks like this:

slow motion copy

Thus, inside the joint we get a triangle, and outside we get a flat bevel.

When Core Graphics removes the original path, this triangle is harmless because Core Graphics uses the non-zero wrap rule to fill the stroke, but when you stroke the ironed copy, the triangle becomes visible.

Now if I decrease the width of the line used to create the ironed copy, the triangle gets smaller. And if I then increase the width of the line used to draw the ironed copy and draw the ironed copy with the mitred joins, the triangle may actually look like it is filled:

thinner ironed copy

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



main path with two joints

When I make an ironed copy of this path, the copy has two inner triangles, and if I stroke the ironed copy, it looks like this:

stroked copy of two-piece path

So, when these strange star-shaped shapes come up when you make an ironed copy of your paths: very short segments creating overlapping triangles.

Note that I made my copies with bevels . Using mit merge when creating the copy also creates hidden triangles because the choice of joint only affects the outside of the joint, not inside the joint.

However, the choice of connection does matter when ironing an ironed copy, as using mitral bands makes the stars appear larger. See this document for a good illustration of how join style can affect the appearance of a sharp corner.

Thus, the miter connects the points of the triangles quite far away, which makes the overlapping triangles look like a star. Here's the result if I stroke the ironed copy using bevels instead:

ironed copy, bevel ironed

The star is almost invisible here because the triangles are drawn with blunt corners.

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

If your path consists entirely of flat segments, the simplest solution is probably to use the existing trim polygon library. The "union" operation applied to the ironed copy should eliminate inner triangles. See this answer for example. Note that these libraries are generally written in C ++, so you probably have to write Objective-C ++ code since Swift cannot call C ++.

If you're wondering how I created the graphics for this answer, I did it with this Swift playground .

+4


source







All Articles