Skip to content

Commit d43e9f2

Browse files
authored
Merge pull request #17 from spacenation/rounded-star-radius-fixes
Rounded star radius fixes
2 parents ea671db + c8ee6ed commit d43e9f2

File tree

4 files changed

+40
-21
lines changed

4 files changed

+40
-21
lines changed

Sources/Shapes/CGPoint+Extensions.swift

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,19 @@ public extension CGPoint {
2929
}
3030

3131
public extension CGPoint {
32-
static func intersection(start1: CGPoint, end1: CGPoint, start2: CGPoint, end2: CGPoint) -> CGPoint {
33-
let x1 = start1.x
34-
let y1 = start1.y
35-
let x2 = end1.x
36-
let y2 = end1.y
37-
let x3 = start2.x
38-
let y3 = start2.y
39-
let x4 = end2.x
40-
let y4 = end2.y
41-
42-
let intersectionX: CGFloat = ((x1*y2-y1*x2)*(x3-x4) - (x1-x2)*(x3*y4-y3*x4)) / ((x1-x2)*(y3-y4) - (y1-y2)*(x3-x4))
43-
let intersectionY: CGFloat = ((x1*y2-y1*x2)*(y3-y4) - (y1-y2)*(x3*y4-y3*x4)) / ((x1-x2)*(y3-y4) - (y1-y2)*(x3-x4))
44-
45-
return CGPoint(x: intersectionX, y: intersectionY)
32+
static func intersection(start1: CGPoint, end1: CGPoint, start2: CGPoint, end2: CGPoint) -> CGPoint? {
33+
let denominator = (end1.x - start1.x) * (end2.y - start2.y) - (end1.y - start1.y) * (end2.x - start2.x)
34+
if denominator == 0 {
35+
// Lines are parallel or coincident
36+
return nil
37+
}
38+
39+
let ua = ((end2.x - start2.x) * (start1.y - start2.y) - (end2.y - start2.y) * (start1.x - start2.x)) / denominator
40+
41+
let x = start1.x + ua * (end1.x - start1.x)
42+
let y = start1.y + ua * (end1.y - start1.y)
43+
44+
return CGPoint(x: x, y: y)
4645
}
4746
}
4847

Sources/Shapes/Path+Extensions.swift

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
11
import SwiftUI
22

33
public extension Path {
4-
mutating func addCircularCornerRadiusArc(from point: CGPoint, via viaPoint: CGPoint, to nextPoint: CGPoint, radius: CGFloat, clockwise: Bool) {
4+
mutating func addCircularCornerRadiusArc(from point: CGPoint, via viaPoint: CGPoint, to nextPoint: CGPoint, radius: CGFloat) {
5+
// Calculate the cross product to determine clockwise direction
6+
let v1 = CGVector(dx: viaPoint.x - point.x, dy: viaPoint.y - point.y)
7+
let v2 = CGVector(dx: nextPoint.x - viaPoint.x, dy: nextPoint.y - viaPoint.y)
8+
9+
let crossProduct = v1.dx * v2.dy - v1.dy * v2.dx
10+
11+
// Determine if the arc should be clockwise based on the cross product
12+
let isClockwise = crossProduct < 0
13+
14+
let radius = isClockwise ? -radius : radius
15+
516
let lineAngle = atan2(viaPoint.y - point.y, viaPoint.x - point.x)
617
let nextLineAngle = atan2(nextPoint.y - viaPoint.y, nextPoint.x - viaPoint.x)
718

@@ -15,7 +26,9 @@ public extension Path {
1526

1627
let offsetEnd2 = CGPoint(x: nextPoint.x + nextLineVector.dx, y: nextPoint.y + nextLineVector.dy)
1728

18-
let intersection = CGPoint.intersection(start1: offsetStart1, end1: offsetEnd1, start2: offsetStart2, end2: offsetEnd2)
29+
guard let intersection = CGPoint.intersection(start1: offsetStart1, end1: offsetEnd1, start2: offsetStart2, end2: offsetEnd2) else {
30+
return
31+
}
1932

2033
let startAngle = lineAngle - (.pi / 2)
2134
let endAngle = nextLineAngle - (.pi / 2)
@@ -24,8 +37,10 @@ public extension Path {
2437
center: intersection,
2538
radius: radius,
2639
startAngle: Angle(radians: startAngle),
27-
endAngle: Angle(radians:endAngle),
28-
clockwise: clockwise
40+
endAngle: Angle(radians: endAngle),
41+
clockwise: isClockwise
2942
)
3043
}
3144
}
45+
46+

Sources/Shapes/RoundedRegularPolygons/RoundedRegularPolygonPath.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ extension Path {
5050
y: centerPoint.y + CGFloat(sin(nextAngle) * hypotenuse)
5151
)
5252

53-
path.addCircularCornerRadiusArc(from: point, via: viaPoint, to: nextPoint, radius: usableRadius, clockwise: false)
53+
path.addCircularCornerRadiusArc(from: point, via: viaPoint, to: nextPoint, radius: usableRadius)
5454
}
5555
path.closeSubpath()
5656
}

Sources/Shapes/RoundedStarPolygons/RoundedStarPolygon.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,9 @@ extension Path {
102102

103103
let lastPoint: CGPoint = getLastPoint(from: centerPoint, angle: lastAngle, hypotenuse: hypotenuse, smoothness: smoothness)
104104

105-
path.addCircularCornerRadiusArc(from: point, via: viaPoint, to: nextPoint, radius: smoothness > 0.5 ? usableConcaveRadius: -usableConcaveRadius, clockwise: smoothness > 0.5 ? false : true)
105+
path.addCircularCornerRadiusArc(from: point, via: viaPoint, to: nextPoint, radius: usableConcaveRadius)
106106

107-
path.addCircularCornerRadiusArc(from: viaPoint, via: nextPoint, to: lastPoint, radius: usableConvexRadius, clockwise: false)
107+
path.addCircularCornerRadiusArc(from: viaPoint, via: nextPoint, to: lastPoint, radius: usableConvexRadius)
108108
}
109109
path.closeSubpath()
110110
}
@@ -120,6 +120,11 @@ struct RoundedStarPolygon_Previews: PreviewProvider {
120120
.background(Circle())
121121
.previewLayout(.fixed(width: 400, height: 400))
122122

123+
RoundedStarPolygon(points: 12, smoothness: 0.87, radius: 20) .strokeBorder(lineWidth: 1)
124+
.foregroundColor(.yellow)
125+
.background(Circle())
126+
.previewLayout(.fixed(width: 400, height: 400))
127+
123128
RoundedStarPolygon(points: 3, smoothness: 0.87, radius: 40)
124129
.fill(Color.orange)
125130
.background(Circle())

0 commit comments

Comments
 (0)