Supporting Corner Radius in Magic Mirror 3

Sketch Plugin Development Series

James Tang
MagicSketch Blog
5 min readDec 12, 2016

--

Signup for Magic Mirror 3 Private Beta!

One request from Magic Mirror 2 users are the feature to support shapes contains corner radius.

Consider following example:

Trying to get an image transformed to a shape contains corner radius provides unexpected results.

Background:

The basic requirement of making a perspective transform of an image is to have exactly 4 coordinates of the shape determined, so I know what shape it’s for the image to transformed to. Magic Mirror 2 does not figure out the correct way to do it, so that was not supported.

One attempt served me well was a previously MMLayerIterator class to iterate through the MSShapeGroup.bezierPath(). This is what I got when I tried to iterate through a NSBezierPath with corner radius applied.

  • Extracting points from a non corner radius applied shape returns exactly what I needed.
  • Extracting points from a corner radius applied shape returns a lot more points along the path.

Learnings:

The data structure of an NSBezierPath does way much more complicated and ambiguously. Remember when Sketch revolutionize rounded rect shapes and keeps corner radius unchanged when resized? And now I was so out of expected ❤

The issue for this is because I couldn’t determine the 4 coordinates I needed.

Unless in a way that you may manually calculate distance between points, get the 4 straight line of the slopes, then use some crazy mathematical equations. Gosh, no maths homework please! Lets look somewhere else.

https://cl.ly/2C0a1G3c3525/magicmirror3-dev-corner-radius.mp4

Despite how limiting is NSBezierPath, I believed Sketch store the exact information I needed. The two things in the video backs up my instinct.

  1. Number of points remains unchanged after applying or unapplying the corner radius, or else the path should go from 4 points to a various number of points.
  2. The transform handle is located at the original location before corner radius applied.

I digged through the header files, and discovered MSCurvePoint.

MSCurvePoint.h file generated from Sketch 40.3

Paste this code in the custom script panel:

At first it looks like it’s too small to be the right thing, but inspect carefully, it’s the relative point of the path.

Now we just convert our MSCurvePoint into real coordinates.

Learnings:

MSCurvePoint contains the relative point as well as the exact corner radius for each point in the MSShapePathLayer object.

Despite there’s only one shape, it’s represent by the MSShapeGroup class. This object can contain multiple MSShapePathLayer (think about Combined Shapes Sketch supported). That’s why we have to looked into the firstObject() of the layers property to find MSCurvePoint.

Unexpected White Spaces

The correct fill should be like the right top with fitting the nice path, the actual result however looks like the right bottom one, with unexpected padding around the image.

Lets consider the following graph:

Explanation:

1. Target shape we wanted to see
2. Actual image we rendered from the 4 points we determined from MSCurvedPoint
3. The actual bounds that the shape consider itself
4. Image got “filled” into the bounds, which is resized and align to the center of the bounds
5. The actual result is an image with weird offset.

So what we needed to do, is to crop out the exceeding area of the rendered image, and use that before filling our shape.

  1. So first obtain the frame of the original path, as well as the cropping bounds of the shape.
  2. Use CGImageCreateWithImageInRect to apply to the image
  3. Execute the relevant Sketch API to create a fill layer and apply the image fill to the corresponding shape.

There finally we successfully created our output and get rid of the nasty padding around.

Signup for Magic Mirror 3 Private Beta Test.

Thanks for reading! If you like what we’re doing, you can get a copy of Magic Mirror 2 to support our work!

--

--

James Tang
MagicSketch Blog

Sketch Plugins and iOS UX Engineer. Opensource projects contributor, share on Twitter. @jamztang