将角度归一化到0到360度的范围?



我们在SwiftUI中有数据类型Angle。这可以存储从-∞到+∞的度数或弧度值。

我想将角度转换为0到360之间的值。例如,通过使用诸如wrap around mod:

的方法
func normalize(_ angle: Angle) -> Angle {
wrapAroundMod(angle.degrees, 360.0)
}

但是,wrapAroundMod不是内置函数,不支持浮点数。我正在努力想出一个优雅的解决方案,没有一堆分支逻辑。

是否有一种优雅的方法来规范化角度?

优雅在旁观者的眼中…

您可以通过使用truncatingRemainder(dividingBy:)的两个应用程序而不使用分支来完成此操作:

extension Angle {
/// Returns an Angle in the range `0° ..< 360°`
func normalized() -> Angle {
let degrees = (self.degrees.truncatingRemainder(dividingBy: 360) + 360)
.truncatingRemainder(dividingBy: 360)
return Angle(degrees: degrees)
}
}

%等价的浮点数是truncatingRemainder,它可以很好地处理负数!

你可以使用这个函数来规范化一个角度:

extension Angle {
/// Returns an Angle in the range `0° ..< 360°`
func normalized() -> Angle {
var degrees = self.degrees.truncatingRemainder(dividingBy: 360)
if degrees < 0 {
degrees = degrees + 360
}
return Angle(degrees: degrees)
}
}

如果你想在-180° ..< 180°范围内规范化它,考虑添加这个扩展:

extension Angle {
/// Returns an Angle in the range `-180° ..< 180°` by mapping `180° ..< 360°` to `-180° ..< 0°`
func normalizedDelta() -> Angle {
var normalized = normalized()
if normalized >= Angle(degrees: 180) {
normalized = normalized - Angle(degrees: 360)
}
return normalized
}
}

这些函数有以下属性:

Angle(degrees: -1081).normalized().degrees == 359
Angle(degrees: -721).normalized().degrees == 359
Angle(degrees: -361).normalized().degrees == 359
Angle(degrees: -1).normalized().degrees == 359
Angle(degrees: 0).normalized().degrees == 0
Angle(degrees: 359.9).normalized().degrees == 359.9
Angle(degrees: 360).normalized().degrees == 0
Angle(degrees: 361).normalized().degrees == 1
Angle(degrees: 720).normalized().degrees == 0
Angle(degrees: 721).normalized().degrees == 1
Angle(degrees: 1081).normalized().degrees == 1
Angle(degrees: -1081).normalizedDelta().degrees // == -1
Angle(degrees: -721).normalizedDelta().degrees // == -1
Angle(degrees: -361).normalizedDelta().degrees // == -1
Angle(degrees: -1).normalizedDelta().degrees // == -1
Angle(degrees: 0).normalizedDelta().degrees == 0
Angle(degrees: 359.9).normalizedDelta().degrees // == -0.1
Angle(degrees: 360).normalizedDelta().degrees == 0
Angle(degrees: 361).normalizedDelta().degrees == 1
Angle(degrees: 720).normalizedDelta().degrees == 0
Angle(degrees: 721).normalizedDelta().degrees == 1
Angle(degrees: 1081).normalizedDelta().degrees == 1

最新更新