Skip to content

Instantly share code, notes, and snippets.

@fruitcoder
Last active November 25, 2021 10:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fruitcoder/45042cd25d8711f17c911d1a0269e0d5 to your computer and use it in GitHub Desktop.
Save fruitcoder/45042cd25d8711f17c911d1a0269e0d5 to your computer and use it in GitHub Desktop.
Function to create a rounded polygon from the corner points and a corner radius
public extension CGPath {
static func createRoundedShapeWithinCornerPoints(points: [CGPoint],
cornerRadius radius: CGFloat,
shouldAddTwoArcsForIntermediatePoints: Bool = false) -> CGPath {
assert(points.count > 2, "We need at least 3 points.")
let path = CGMutablePath()
for i in 0 ..< points.count {
let firstIndex = i
let secondIndex = mod(i + 1, points.count)
let thirdIndex = mod(i + 2, points.count)
let from = points[firstIndex]
let via = points[secondIndex]
let to = points[thirdIndex]
let fromAngle = atan2f(Float(via.y - from.y), Float(via.x - from.x))
let toAngle = atan2f(Float(to.y - via.y), Float(to.x - via.x))
let fromOffset = CGVector(dx: CGFloat(-sinf(fromAngle)) * radius, dy: CGFloat(cosf(fromAngle)) * radius)
let toOffset = CGVector(dx: CGFloat(-sinf(toAngle)) * radius, dy: CGFloat(cosf(toAngle)) * radius)
let x1 = from.x + fromOffset.dx
let y1 = from.y + fromOffset.dy
let x2 = via.x + fromOffset.dx
let y2 = via.y + fromOffset.dy
let x3 = via.x + toOffset.dx
let y3 = via.y + toOffset.dy
let x4 = to.x + toOffset.dx
let y4 = to.y + toOffset.dy
let intersectionX = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4))
let intersectionY = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4))
let cornerCenter = CGPoint(x: floor(intersectionX), y: floor(intersectionY))
let startAngle = fromAngle - (.pi / 2.0)
let endAngle = toAngle - (.pi / 2.0)
if shouldAddTwoArcsForIntermediatePoints && i != 0 && i != points.count - 1 {
let intermediateStep = (startAngle + endAngle) / 2.0
path.addArc(center: cornerCenter, radius: radius, startAngle: CGFloat(startAngle), endAngle: CGFloat(intermediateStep), clockwise: false)
path.addArc(center: cornerCenter, radius: radius, startAngle: CGFloat(intermediateStep), endAngle: CGFloat(endAngle), clockwise: false)
} else {
path.addArc(center: cornerCenter, radius: radius, startAngle: CGFloat(startAngle), endAngle: CGFloat(endAngle), clockwise: false)
}
}
path.closeSubpath()
return path
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment