Created
February 22, 2023 11:59
-
-
Save UnderscoreDavidSmith/fd77499b3ca791093abeb58407683f8b to your computer and use it in GitHub Desktop.
SwiftUI UnitPoint for Angle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// ContentView.swift | |
// GradientComponenet | |
// | |
// Created by David Smith on 2/21/23. | |
// | |
import SwiftUI | |
struct ContentView: View { | |
@State var rotationAngle:CGFloat = 0.0 | |
func unitSquareIntersectionPoint(_ angle:Angle) -> UnitPoint { | |
var normalizedDegree = angle.degrees | |
while normalizedDegree > 360.0 { | |
normalizedDegree -= 360.0 | |
} | |
while normalizedDegree < 0.0 { | |
normalizedDegree += 360.0 | |
} | |
if normalizedDegree < 45.0 || normalizedDegree >= 315 { | |
//Right Edge, x = 1.0 | |
var degreeToConsider = normalizedDegree | |
if degreeToConsider < 45.0 { | |
degreeToConsider = normalizedDegree + 360.0 | |
//angle now between 315 & 405 | |
} | |
let degreeProportion = (degreeToConsider - 315.0) / 90.0 | |
return UnitPoint(x: 1.0, y: 1.0 - degreeProportion) | |
} else if normalizedDegree < 135.0 { | |
//Top Edge, y = 0.0 | |
let degreeProportion = (normalizedDegree - 45.0) / 90.0 | |
return UnitPoint(x: 1.0 - degreeProportion, y: 0.0) | |
} else if normalizedDegree < 225.0 { | |
//left Edge, x = 0.0 | |
let degreeProportion = (normalizedDegree - 135) / 90.0 | |
return UnitPoint(x: 0.0, y: degreeProportion) | |
} else if normalizedDegree < 315.0 { | |
//Bottom Edge, y = 1.0 | |
let degreeProportion = (normalizedDegree - 225) / 90.0 | |
return UnitPoint(x: degreeProportion, y: 1.0) | |
} | |
return .zero | |
} | |
var startPoint:UnitPoint { | |
return unitSquareIntersectionPoint(Angle(degrees: 360.0 * rotationAngle)) | |
} | |
var endPoint:UnitPoint { | |
return unitSquareIntersectionPoint(Angle(degrees: 360.0 * rotationAngle + 180.0)) | |
} | |
var body: some View { | |
VStack { | |
let start = startPoint | |
let end = endPoint | |
ZStack { | |
LinearGradient(colors: [Color.red, Color.blue], startPoint: startPoint, endPoint: endPoint) | |
.border(.black) | |
Circle() | |
.fill(.red) | |
.frame(width:15, height:15) | |
.overlay(Circle().stroke(.black)) | |
.position(x:start.x * 200, y:start.y * 200) | |
Rectangle() | |
.fill(.blue) | |
.frame(width:15, height:15) | |
.border(.black) | |
.position(x:end.x * 200, y:end.y * 200) | |
} | |
.frame(width:200, height:200) | |
Text("\(Int(rotationAngle * 360.0))°") | |
HStack { | |
Circle().fill(.red).frame(width:10, height:10) | |
Text("Start: \(String(format:"%0.1f", start.x)),\(String(format:"%0.1f", start.y))") | |
} | |
HStack { | |
Rectangle().fill(.blue).frame(width:10, height:10) | |
Text("End: \(String(format:"%0.1f", end.x)),\(String(format:"%0.1f", end.y))") | |
} | |
GeometryReader { proxy in | |
ZStack { | |
Color(white:0.9) | |
RoundedRectangle(cornerRadius: 8) | |
.fill(Color.green) | |
.frame(width:32, height:32) | |
.overlay( | |
HStack(spacing:3) { | |
RoundedRectangle(cornerRadius: 4) | |
.fill(.white) | |
.frame(width: 2, height:24) | |
RoundedRectangle(cornerRadius: 4) | |
.fill(.white) | |
.frame(width: 2, height:24) | |
RoundedRectangle(cornerRadius: 4) | |
.fill(.white) | |
.frame(width: 2, height:24) | |
} | |
) | |
.position(x:22 + ((proxy.size.width - 44) * rotationAngle), y:proxy.size.height * 0.5) | |
.highPriorityGesture(DragGesture().onChanged { dragValue in | |
var dragLocation = dragValue.location.x | |
dragLocation = max(22, dragLocation) | |
dragLocation = min(proxy.size.width - 22, dragLocation) | |
rotationAngle = (dragLocation - 22) / (proxy.size.width - 44) | |
}) | |
} | |
} | |
.frame(height:44) | |
Text("Rotation") | |
.frame(minWidth:0, maxWidth:.infinity) | |
} | |
.padding() | |
} | |
} | |
struct ContentView_Previews: PreviewProvider { | |
static var previews: some View { | |
ContentView() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This:
can be simplified to this:
That first
while
loop is the definition of the%
operator. Using%
with a negative value on the left results in a negative number greater than -360 so adding 360 brings in into the range 0-359.