The goal is to fill a polygon using Core Graphics in Swift.
The following code does just that if all of the endpoints are known.
func drawPolySegment() {
let renderer = UIGraphicsImageRenderer(size: CGSize(width: 512, height: 512))
let img = renderer.image { ctx in
let endpoints = [
CGPoint(x: 200, y: 175),
CGPoint(x: 270, y: 170),
CGPoint(x: 300, y: 100)
]
ctx.cgContext.addLines(between: endpoints)
UIColor.yellow.setFill()
ctx.cgContext.drawPath(using: .fillStroke)
}
imageView.image = img
}
However, the endpoints for the desired shape are not easily obtainable and so a more generic approach was opted for using rotate(by:), move(to:), addline(to:), translate(by:) methods as follows:
func drawPolygon() {
let renderer = UIGraphicsImageRenderer(size: CGSize(width: 512, height: 512))
let img = renderer.image { ctx in
let apexes: CGFloat = 3 //5 //6
let length: CGFloat = 500 //190 //140
let angle: CGFloat = 2 * π / apexes
let zero: CGFloat = 0
UIColor.brown.setStroke()
UIColor.yellow.setFill()
ctx.cgContext.setLineWidth(10)
ctx.cgContext.setLineCap(.round)
ctx.cgContext.translateBy(x: 256, y: 5)
for segment in 0..<Int(apexes * 2) {
if segment == 0 {
ctx.cgContext.rotate(by: angle)
} else if segment % 2 == 0 {
ctx.cgContext.rotate(by: 2 * angle)
} else {
ctx.cgContext.rotate(by: -angle)
}
ctx.cgContext.move(to: CGPoint(x: zero, y: zero))
ctx.cgContext.addLine(to: CGPoint(x: length, y: zero))
ctx.cgContext.translateBy(x: length, y: zero)
}
ctx.cgContext.drawPath(using: .fillStroke)
}
imageView.image = img
}
The code above generates a beautifully outlined shape, but will not fill with colour. The values commented out for "apexes" and "length" are valid for the 512 x 512 rendering space created. Why does the shape fill for the first code sample and not the second? What is missing from the second code sample to make the shape fill?
You aren't drawing a polygon, you're drawing 3 separate unconnected lines. Each move(to:)
starts a new polygon.
You can fix this by only doing the move(to:)
for the first segment:
for segment in 0..<Int(apexes * 2) {
if segment == 0 {
ctx.cgContext.rotate(by: angle)
ctx.cgContext.move(to: CGPoint(x: zero, y: zero))
} else if segment % 2 == 0 {
ctx.cgContext.rotate(by: 2 * angle)
} else {
ctx.cgContext.rotate(by: -angle)
}
ctx.cgContext.addLine(to: CGPoint(x: length, y: zero))
ctx.cgContext.translateBy(x: length, y: zero)
}
Results:
apexes: 3, length: 500
apexes: 5, length: 190
apexes: 6, length: 140