5

Usually, when we draw a bezierpath in CoreGraphics, and set this 'CGContextSetLineWidth' a the desired thickness of the path , it strokes on the outside boundary of the path ( as the line width increases, the boundary seems to grow on the outside of the path), I want my line thickness to grow on the inside of the bezier path, is there a way to do that?

rmaddy
  • 314,917
  • 42
  • 532
  • 579
  • Possible duplicate of [UIView drawRect: is it possible to stroke inside a path?](https://stackoverflow.com/questions/14258924/uiview-drawrect-is-it-possible-to-stroke-inside-a-path) – Kurt Revis Apr 28 '18 at 05:32

1 Answers1

7

I am not aware of a way to stroke the inside of a path. However, you can accomplish something similar, which might work for you. If you scale down the path and move it to the center with the correct amount, it will fit nicely within the bounds you want. The visual difference between drawing inside and scaling is none for simple shapes like rectangles, rounded rects and ellipses, but will differ for more complex shapes. Consider what will happen if you stroke the letter B with "inside strokes", versus scaling it.

Here is what it looks like before and after transforming using a very wide line. As you can see, stroking a line will center it on the path, making half of it appear on each side. So to transform it, we will need to move the path by half a line width down and right, then scale it down by the line width.

Using bezierPathWithRoundedRect
line width 20, box size 200 x 300, corner radius 50

paths

The transform then becomes like this.

viewSize is your bounding box for the path
lineWidth is the width of the line
bezierPath is your UIBezierPath

CGAffineTransform transform = CGAffineTransformMakeTranslation(lineWidth / 2.0,
                                                               lineWidth / 2.0);
transform = CGAffineTransformScale(transform, 
                                   (viewSize.width - lineWidth) / viewSize.width, 
                                   (viewSize.height - lineWidth) / viewSize.height);

CGPathRef reducedPath = CGPathCreateCopyByTransformingPath(bezierPath.CGPath, &transform);


UPDATE

If you want to keep the aspect ratio, the scaling can be modified to be equal on both axis, using the smallest factor on both.

CGFloat scale = viewSize.width < viewSize.height ? (viewSize.width - lineWidth) / viewSize.width :
                                                   (viewSize.height - lineWidth) / viewSize.height;

CGAffineTransform transform = CGAffineTransformMakeTranslation(lineWidth / 2.0, lineWidth / 2.0);
transform = CGAffineTransformScale(transform, scale, scale);

CGPathRef reducedPath = CGPathCreateCopyByTransformingPath(bezierPath.CGPath, &transform);
LGP
  • 4,135
  • 1
  • 22
  • 34
  • what if my path is initially rotated by some angle which is unknown, would this still work? Won't there be shearing of the path in that case if I apply scale? – Sudhanshu Monga Apr 26 '18 at 06:30
  • It should work if you have applied the rotation before doing this. As for the shearing, my solution does not preserve aspect ratio, so yes, it might shear. If you want to keep the aspect ratio, the scale transform can easily be modified to scale equally on both axis. Just do the smaller of the two scale values on both axis instead. – LGP Apr 26 '18 at 06:43
  • viewsize is the bounding box, but what if i have a rotated star like path as my path, and i need to add a border inside it, how would i do that, since this solution works for rectangles. – Sudhanshu Monga May 02 '18 at 07:51
  • I think convex shapes, like rectangles, circles, etc will be fine, but concave shapes like stars will be more or less distorted. The problem is that drawing a border inside the edge of a star will give you relatively sharper angles than drawing on or outside the edge. That said, when drawing a thin line on a fairly large shape, the distortion will probably not even be visible. I do not have a solution to do it properly. – LGP May 02 '18 at 08:49