Angle
是一个 Swift 包,它提供了一种灵活且可扩展的方式来处理不同类型的角度,包括度、弧度、百分度、周/圈、角分和角秒。
角度类型: 支持各种角度类型:Radians
(弧度)、Degrees
(度)、Gradians
(百分度)、Revolutions
(周数)、ArcSeconds
(角秒)和 ArcMinutes
(角分)。
归一化: 内置归一化功能,可将角度保持在特定范围内(例如,Degrees
的 0-360 度)。
算术运算: 支持加法、减法、乘法和除法,并具有一致的归一化行为。
角度转换: 轻松在不同角度类型之间进行转换。
测量支持: 将角度值转换为 Swift 的 Measurement<UnitAngle>
类型,以便与 Foundation framework 的 units(单位)一起使用。
类型安全的单位: 使用 AngleType
枚举来表示单位,确保类型安全并避免基于字符串的错误。
可扩展协议: 采用 Anglable
协议设计,可以轻松添加自定义角度类型。
完整的运算符支持: 支持所有基本算术运算符、比较运算符,包括 ==
、<
、<=
、>
、>=
,以及复合赋值运算符(如 +=
、-=
),确保正确的归一化行为。
三角函数: 一组基本的三角函数:sine
(正弦)、cosine
(余弦)、tangent
(正切)、cotangent
(余切)、secant
(正割)、cosecant
(余割)。三角形计算:oppositeLeg(hypotenuse:)
(已知斜边求对边)、adjacentLeg(hypotenuse:)
(已知斜边求邻边)、hypotenuse(fromOppositeLeg:)
(已知对边求斜边)、hypotenuse(fromAdjacentLeg:)
(已知邻边求斜边)、oppositeLeg(fromAdjacentLeg:)
(已知邻边求对边)、adjacentLeg(fromOppositeLeg:)
(已知对边求邻边)。
您可以使用 Swift Package Manager 安装 AAngle
包。
使用 Xcode
https://github.com/gmcusaro/AAngle.git
。1.0.0
(或您的初始版本)作为起始版本。使用 Packages(包): 将以下依赖项添加到您的 Package.swift
文件中
dependencies: [
.package(url: "https://github.com/gmcusaro/AAngle.git", from: "1.0.0")
]
然后将该产品添加到任何需要访问该库的目标中
.product(name: "AAngle", package: "AAngle"),
import AAngle
// Create angles
let degrees = Degrees(90)
let radians = Radians(Double.pi / 2)
let revolutions = AngleType.revolutions.initAngle(degress)
let grads = Gradians() // Init 0.0 grad
let arcMinutes = ArcMinutes.zero // Init 0.0 arc minutes
let arcSeconds = AngleType.arcSeconds.initAngle(324000.00000000) // Init 324000.00000000 arc seconds
// Angle conversions
let degreesFromRadians = Degrees(radians) // Convert radians to degrees
let degreesFromRevolutions: Degrees = revolutions.convertTo(.degrees) as? Degrees // Convert to any Anglable type
// Using Measurement
let measurement = degrees.toMeasurement()
print(measurement) // Output: 90.0 deg
// Accessing to rawValue, description and debugDescription
print(degrees.rawValue) // 90.0
print(degrees.description) // "90.0"
print(degrees.debugDescription) // "Angle(Degrees): rawValue = 90.0, normalized = 90.0"
AAngle
类型的核心设计原则是:尽可能表示归一化的角度。归一化通过将角度保持在预定义的范围内来确保一致性并防止歧义(例如,Degrees
的 0-360 度,Radians
的 0-2π 弧度)。但是,某些运算(如与标量相乘和相除)可能会产生超出此标准范围的数学上有效的结果,并且保留这些值可能很重要。因此,Angle
包中的运算符具有特定的归一化行为
+, -
加法和减法: 这些运算符始终产生归一化的结果。结果角度被归一化为左侧操作数类型的标准范围。这确保了加减角度总是得到预期范围内的值。结果的类型与左侧操作数的类型相同。
let degrees = Degrees(350)
let radians = Radians(Double.pi / 2) // Equivalent to 90 degrees
let sum = degrees + radians // Result: Degrees(80) (350 + 90 = 440, normalized to 80)
let difference = radians - degrees // Result: Radians(-4.537856055185257)
+=, -=
加法和减法赋值: 这些运算符原地修改角度,并且始终归一化结果。它们等效于执行相应的算术运算,然后将归一化值分配回原始变量。
var myAngle = Degrees(350)
myAngle += 90 // myAngle is now 80 (normalized)
myAngle -= Revolutions(0.25) // myAngle is now 340 (normalized)
*
乘法: 与标量(Double、Int 等)的乘法不进行归一化。这是因为将角度乘以一个值可能会合法地产生超出标准范围的角度(例如,2 * 180 度 = 360 度,3 * 180 度 = 540 度)。保留这些值通常在数学上是必要的。
let degrees = Degrees(180)
let doubled = degrees * 2 // Result: Degrees(360) (not normalized)
let tripled = degrees * 3 // Result: Degrees(540) (not normalized)
*=
乘法赋值: 乘法赋值运算符是归一化的。重复乘法(通常这样做)将导致值保持在标准范围内。
var degrees = Degrees(180)
degrees *= 2 // Result: Degrees(0) (normalized)
/
除法: 与标量相除不进行归一化,原因与乘法相同。除一个角度可以产生一个更小或更大的角度,该角度可能落入也可能不落入标准范围内,并且通常需要保留未归一化的值。
let radians = Radians(Double.pi)
let halved = radians / 2 // Result: Radians(1.570796326794966) (not normalized, equal to pi/2)
/=
除法赋值: 除法赋值运算符是归一化的。重复除法(通常这样做)将导致值保持在标准范围内。
var degrees = Degrees(10)
degrees /= 2 // Result: Degrees(90) (normalized)
==, <, <=, >, >=
比较运算符: 比较运算符在不同类型的 Anglable
实例之间正确工作。在比较之前,右侧操作数被转换为左侧操作数的类型。这确保了无论原始单位如何,都能进行一致且准确的比较。比较使用容差值来考虑潜在的浮点精度误差。
let degrees = Degrees(90)
let radians = Radians(Double.pi / 2)
print(degrees == 180) // true
print(degrees == radians) // true (comparison after converting radians to degrees)
print(degrees < Int(89)) // false
print(degrees < radians) // false
Anglable
协议提供了用于归一化角度值的方法,确保它们落在定义的范围内。归一化对于一致性以及防止角度表示中的歧义至关重要。每个符合的类型(例如,Degrees
、Radians
)都定义了自己的 normalizationValue
,它是 Anglable
协议的 static
属性。
normalize()
:原地将角度归一化为符合类型 normalizationValue
定义的标准范围。 例如,对于 Degrees
,这将是范围 0 到 360(不包括 360)。 normalize()
方法会修改现有角度。
var myAngle = Degrees(450)
myAngle.normalize() // myAngle is now 90
normalized() -> Self
:返回一个包含归一化值的新 Anglable
实例。 原始实例不被修改。 normalized()
方法会创建一个新的、归一化的角度实例。
let myAngle = Degrees(450)
let normalizedAngle = myAngle.normalized() // normalizedAngle is 90, myAngle is still 450
normalize(by value: Double)
*: 使用自定义归一化值原地归一化角度。 如果您需要默认值以外的范围,这将非常有用。 normalize()
方法会修改现有角度。
var myAngle = Radians(3 * Double.pi) // 3π
myAngle.normalize(by: Double.pi) // myAngle is now π (normalized to the range 0 to π)
normalized(by value: Double) -> Self
:返回一个新的 Anglable
实例,该实例使用提供的自定义归一化值进行归一化。 原始实例不会被修改。 normalized()
方法会创建一个新的、归一化的角度实例。
let myAngle = Radians(3 * Double.pi) // 3π
let normalizedAngle = myAngle.normalized(by: Double.pi) // normalizedAngle is π, myAngle is still 3π
默认归一化(在适当的情况下): 加法、减法和赋值运算默认进行归一化,以保持在标准范围内表示角度的核心原则。 这避免了常见错误并确保了一致性。
保留量级(必要时): 乘法和除法(不带赋值)保留结果的量级,即使它落在归一化范围之外也是如此。 这对于许多数学运算至关重要,在这些运算中,“未包装”的角度很重要。
类型一致性: 二元运算 (+
, -
) 返回与左侧操作数相同类型的值。 这使得行为可预测并有助于防止意外的类型更改。
跨类型比较: 比较运算符通过执行内部转换来正确处理不同的 Anglable
类型。
容差: 使用容差执行比较运算,以防止因浮点精度限制而导致的错误。
AAngle
为 Radians 类型提供了一组三角函数。
import AAngle
let radians = Radians(Degrees(45))
// Basic trigonometric functions
print(radians.sine) // 0.7071067811865475
print(radians.cosine) // 0.7071067811865476
print(radians.tangent) // 0.9999999999999999
print(radians.cotangent) // Optional(1.0000000000000002)
print(radians.secant) // Optional(1.414213562373095)
print(radians.cosecant) // Optional(1.414213562373095)
oppositeLeg(hypotenuse:)
:计算给定斜边的直角三角形的对边长度。adjacentLeg(hypotenuse:)
:计算给定斜边的直角三角形的邻边长度。hypotenuse(fromOppositeLeg:)
:计算给定对边的直角三角形的斜边长度。hypotenuse(fromAdjacentLeg:)
:计算给定邻边的直角三角形的斜边长度。oppositeLeg(fromAdjacentLeg:)
:计算给定邻边的直角三角形的对边长度。adjacentLeg(fromOppositeLeg:)
:计算给定对边的直角三角形的邻边长度。import AAngle
let radians = Radians(Double.pi / 4) // 45 degrees
// Triangle calculations
let hypotenuse = 10.0
print(radians.oppositeLeg(hypotenuse: hypotenuse)) // 7.0710678118654755
print(radians.adjacentLeg(hypotenuse: hypotenuse)) // 7.071067811865476
print(radians.hypotenuse(fromOppositeLeg: 5.0)) // 7.0710678118654755
print(radians.hypotenuse(fromAdjacentLeg: 5.0)) // 7.071067811865476
print(radians.oppositeLeg(fromAdjacentLeg: 5.0)) // 5.0
print(radians.adjacentLeg(fromOppositeLeg: 5.0)) // 5.0
此软件包根据 Apache License 获得许可。 有关更多信息,请参阅 LICENSE。