I'm trying to find a way to draw a iOS 7-style icon 'squircle' shape programmatically, using core graphics. I'm not asking how to draw a rounded rectangle. A squircle is a superellipse:
which is slightly different than a regular rounded rectangle:
It's exact formula is readily available. However, I can't figure out how to draw this using, for example, a CGPath, let alone fill it, and be able to resize it rather easily. All this while being entirely exact with the formula.
Quote from Wikipedia: Superellipse
So why not try to approximate Squircle using Bezier curves? Both curves (Bezier and Squircle) are defined by the parametric equations.
UIBezierPath Class have method:
addCurveToPoint:controlPoint1:controlPoint2:
NOTE: Use of the
addQuadCurveToPoint:controlPoint:
method gives worse results - tested.I used this method and that's what happened as a result:
red line
- rounded rectangle,blue line
- rectangle from fours Bezier curvesIf this result is interested - drawing code below.
NOTE: To achieve a more exact match Bezier curve can be required to change the coordinates of the four
corner points
(now they correspond to the angles of the rectangle in which is inscribed the figure).A filled version of the accepted answer, also ported to Swift:
perfect for use in a UIView subclass.
This isn't a great answer since it doesn't get to the heart of what you're asking which is how to draw a superellipse** programmatically, but you can:
Load the SVG, and convert it to a UIBezierPath, from there you can scale and transform however you like:
** It's maybe worth noting that the shape might not be an exact superellipse anyway: http://i.imgur.com/l0ljVRo.png
in iOS 13/ Xcode 11 you can now use CALayerCornerCurve
Example
source: https://developer.apple.com/documentation/quartzcore/calayercornercurve
Building on top of Ruslan's and Sunkas' answers above, I created a path that joins superelliptic "corners" with straight line segments; i.e. a superelliptic analog of the regular, rounded rectangle (like the mask seen around the edges of the iPhone X Simulator):
The points
p0
throughp7
in the code can be visualized in the following diagram:If you pass a rectangle that is actually a square, and the corner radius is equal to or greater than half the side length, the straight line segments collapse (
p0
"merges" withp1
,p2
withp3
, etc.) and you get the standard superellipse.This would be pretty easy to do in OpenGL ES with a shader. Just draw a quad and pass in the x and y as vertex attributes. In the fragment shader, plug x and y into the equation. If the result <= 1, then the fragment is inside the shape. If I can get some free time I might try this and post it here.
If you want to use CGPath, I think the key is to parameterize x and y in terms of t, which goes from 0 to 2π. Then evaluate x and y at regular intervals. I'll try to figure this out in my free time, too, but my math is kind of rusty.
BTW, I'm certain that Apple is not using this formula. See the link that @millimoose posted: http://blog.mikeswanson.com/post/62341902567/unleashing-genetic-algorithms-on-the-ios-7-icon