【问题标题】:How can I convert from degrees to radians?如何将度数转换为弧度?
【发布时间】:2015-05-24 15:20:37
【问题描述】:

我正在尝试将此 Obj-C 代码转换为 Swift 代码,但我不知道此代码的等效项应该是什么?

#define DEGREES_TO_RADIANS(degrees)((M_PI * degrees)/180)

我用谷歌搜索发现this

但我不明白在我的情况下如何在 Swift 中转换它?

【问题讨论】:

  • 我认为您缺少一些代码。你们都可以添加所有相关代码吗?任何其他定义,例如度数?
  • 这是我的快速代码:pastebin.com/bZ4a7EVN
  • 你能给我看看你的.h文件吗?
  • 这是一个宏。你想要一个函数。

标签: ios objective-c macos swift macros


【解决方案1】:

Xcode 11 • Swift 5.1 或更高版本

extension BinaryInteger {
    var degreesToRadians: CGFloat { CGFloat(self) * .pi / 180 }
}

extension FloatingPoint {
    var degreesToRadians: Self { self * .pi / 180 }
    var radiansToDegrees: Self { self * 180 / .pi }
}

游乐场

45.degreesToRadians         // 0.7853981633974483

Int(45).degreesToRadians    // 0.7853981633974483
Int8(45).degreesToRadians   // 0.7853981633974483
Int16(45).degreesToRadians  // 0.7853981633974483
Int32(45).degreesToRadians  // 0.7853981633974483
Int64(45).degreesToRadians  // 0.7853981633974483

UInt(45).degreesToRadians   // 0.7853981633974483
UInt8(45).degreesToRadians  // 0.7853981633974483
UInt16(45).degreesToRadians // 0.7853981633974483
UInt32(45).degreesToRadians // 0.7853981633974483
UInt64(45).degreesToRadians // 0.7853981633974483

Double(45).degreesToRadians    // 0.7853981633974483
CGFloat(45).degreesToRadians   // 0.7853981633974483
Float(45).degreesToRadians     // 0.7853981
Float80(45).degreesToRadians   // 0.78539816339744830963

如果你想让二进制整数返回浮点类型而不是总是返回 CGFloat,你可以创建一个泛型方法而不是计算属性:

extension BinaryInteger {
    func degreesToRadians<F: FloatingPoint>() -> F {  F(self) * .pi / 180 }
}

let radiansDouble: Double = 45.degreesToRadians()   // 0.7853981633974483
let radiansCGFloat: CGFloat = 45.degreesToRadians() // 0.7853981633974483
let radiansFloat: Float = 45.degreesToRadians()     // 0.7853981
let radiansFloat80: Float80 = 45.degreesToRadians() // 0.78539816339744830963

【讨论】:

  • 你不应该扩展CGFloat吗?
  • @Zorayr 更新到 Swift 3 并扩展 FloatingPoint 现在将它们全部扩展
  • 其实在 Swift 3 中你可以使用 Measurement 类型,根本不需要知道转换公式!
  • 请注意这个超级专业提示...stackoverflow.com/a/28600210/294884
  • 无缘无故投反对票没有任何意义。发表评论
【解决方案2】:

Apple 提供这些GLKit functions 进行转换:

func GLKMathDegreesToRadians(_ degrees: Float) -> Float
func GLKMathRadiansToDegrees(_ radians: Float) -> Float

【讨论】:

  • GLKit 即将退出舞台,因为现在它是 Metal 的世界,再见 GL。由于将 iPad 应用移植到 Mac,不再支持 GLKit!。
【解决方案3】:

另外,将 fron 弧度转换为度数(如果有人在 google 上偶然发现这个):

var degrees = radians * (180.0 / M_PI)

【讨论】:

    【解决方案4】:

    创建变量名时不再局限于 ASCII 字符,那么如何使用 π (alt-p):

    typealias RadianAngle = CGFloat
    
    let π = RadianAngle(M_PI)
    let π_x_2 = RadianAngle(M_PI * 2)
    let π_2 = RadianAngle(M_PI_2)
    let π_4 = RadianAngle(M_PI_4)
    
    extension RadianAngle {
        var degrees: CGFloat {
            return self * 180 / π
        }
        init(degrees: Int) {
            self = CGFloat(degrees) * π / 180
        }
    }
    

    示例用法:

    let quarterCircle = RadianAngle(degrees: 90)
    print("quarter circle = \(quarterCircle) radians")
    // quarter circle = 1.5707963267949 radians
    
    let halfCircle = π
    print("half circle = \(halfCircle.degrees) degrees")
    // half circle = 180.0 degrees
    

    【讨论】:

      【解决方案5】:

      这和你问的不一样,但在 Swift 3 / iOS 10 中,你可以使用 Measurement 类型并在不知道公式的情况下进行转换!

      let result = Measurement(value: 45, unit: UnitAngle.degrees)
          .converted(to: .radians).value
      

      【讨论】:

      • 惊人的@matt 再次工作,谢谢!不幸的是,只有 iOS 10。
      • 让 radians = CGFloat(30.3 * .pi / 180.0) 让 radians2 = Measurement(value: 30.3, unit: UnitAngle.degrees) .converted(to: .radians).value 的有趣之处是不同:0.5288347633542818 和 0.5288345742619878
      • 并确定“‘测量’仅适用于 iOS 10.0 或更高版本”
      【解决方案6】:
      let angle = 45° // angle will be in radians, 45 is in degrees
      

      Swift 3 下编译。仍然保留所有值,使用 CGFloats 以弧度进行所有计算...,但使用以度为单位的常量使代码更具可读性。 例如:90° ° 符号会神奇地将度数转换为弧度。

      如何设置:

      ° 符号定义并使用后缀运算符。该运算符将执行从度数到弧度的转换。 此示例适用于 Ints,如果需要,也可以为 Float 类型扩展这些。

      postfix operator °
      
      protocol IntegerInitializable: ExpressibleByIntegerLiteral {
        init (_: Int)
      }
      
      extension Int: IntegerInitializable {
        postfix public static func °(lhs: Int) -> CGFloat {
          return CGFloat(lhs) * .pi / 180
        }
      }
      

      一些使用示例:

      let angle = 45°
      
      contentView.transform = CGAffineTransform(rotationAngle: 45°)
      
      let angle = 45
      contentView.transform = CGAffineTransform(rotationAngle: angle°)
      

      警告!

      两次使用这种转换太容易了(在一个已经错误地以弧度表示的值上),你会得到一个非常小的结果,而且看起来结果的角度总是为零......不要使用°在同一个值上两次(不要转换两次)!!:

      // OBVIOUSLY WRONG!
      let angle = 45°° // ° used twice here
      
      // WRONG! BUT EASY TO MISS
      let angle = 45° // ° used here
      contentView.transform = CGAffineTransform(rotationAngle: angle°) // ° also used here
      

      【讨论】:

      • IntegerInitializable 协议毫无意义。 int 已经符合ExpressibleByIntegerLiteral
      • 顺便说一句,您可以使此运算符通用以支持任何整数并返回任何浮点数。 public extension FixedWidthInteger { postfix static func °&lt;T: FloatingPoint&gt;(lhs: Self) -&gt; T { T(lhs) * .pi / 180 } }
      • 在创建泛型方法时,如果编译器无法推断出结果类型let angle: CGFloat = 45°,则需要显式设置结果类型。但它不需要 CGFloat 或任何 FloatingPoint 类型 CGAffineTransform(rotationAngle: 45°)
      【解决方案7】:

      我会使用上面提到的 @t1ser 相同的原则,但创建一个 CGFloat 的扩展名,以便更容易使用小数表示度数(例如,你可以有 23.4 度):

      extension CGFloat {
          func degrees() -> CGFloat {
              return self * .pi / 180
          }
      
          init(degrees: CGFloat) {
              self = degrees.degrees()
          }
      }
      

      使用它也很容易(主要是因为我个人不知道如何输入°? - 如果你也不知道,那就是option+shift+8 btw):

      let degreesToConvert: CGFloat = 45.7
      .
      .
      .
      let convertedDegrees = degreesToConvert.degrees()
      

      或者使用初始化器:

      let convertedDegrees = CGFloat(degrees: 45.3)
      

      【讨论】:

        【解决方案8】:

        斯威夫特 4.2

        您可以编写全局泛型函数:

        public func radians<T: FloatingPoint>(degrees: T) -> T {
            return .pi * degrees / 180
        }
        
        public func degrees<T: FloatingPoint>(radians: T) -> T {
            return radians * 180 / .pi
        }
        

        例子:

        let cgFloat: CGFloat = 23.0
        let double: Double = 23.0
        let float: Float = 23.0
        let int: Int = 23
        
        let cgf = radians(degrees: cgFloat) // 0.4014 CGFloat
        let d = radians(degrees: double)    // 0.4014 Double
        let f = radians(degrees: float)     // 0.4014 Float
        let i = radians(degrees: int)       // compile error
        

        如果您不想像这样扩展所有浮动类型

        extension FloatingPoint { ... }
        

        【讨论】:

        • 为什么不简单地return .pi * degrees / 180
        • @LeoDabus 因为TFloatingPoint 类型,而180 是Int 类型。在swift中你不能对不同的类型进行计算。
        • 你错了。 Swift 可以推断类型。它的行为与扩展 FloatingPoint 类型完全相同。 180可以是任何东西。不一定是 Int
        • FloatingPoint 符合 ExpressibleByIntegerLiteral 这就是为什么你可以在那里写 180
        • 180.0 需要 T,因为 T 不一定是 Double。它可以是任何浮点类型。你从你的双 180.0 初始化一个新的
        【解决方案9】:

        在度数和弧度之间转换 Double 的最有效和最准确的方法:

        import Foundation
        
        extension Double {
            var radians: Double { return Measurement(value: self, unit: UnitAngle.degrees).converted(to: UnitAngle.radians).value }
            var degrees: Double { return Measurement(value: self, unit: UnitAngle.radians).converted(to: UnitAngle.degrees).value }
        }
        

        Apple 的 Foundation 团队很久以前就通过开发出超越所有其他解决方案的解决方案解决了这个问题:

        Measurements and Units - WWDC 2016, Session 238

        【讨论】:

          猜你喜欢
          • 2015-11-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-04-09
          • 1970-01-01
          • 2013-10-15
          相关资源
          最近更新 更多