Как перевести градусы в радианы?


107

Я пытаюсь преобразовать этот Obj-Cкод в Swiftкод, но не знаю, каким должен быть эквивалент этого кода?

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

Я погуглил и нашел это

Но я не понимаю, как это преобразовать в Swift в моем случае?


Я думаю, вам не хватает кода. Можете ли вы добавить весь соответствующий код? Какие-нибудь другие определения, например, степени?
BlackHatSamurai

это мой быстрый код: pastebin.com/bZ4a7EVN
Dharmesh Kheni

Вы можете показать мне ваш файл .h?
BlackHatSamurai

Это макрос. Вам нужна функция.
gnasher729

Ответы:


268

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

4
Разве вы не должны продлить CGFloat?
Зорайр

1
@Zorayr обновился до Swift 3, а расширение FloatingPoint теперь расширяет их все
Лео Дабус,

3
Фактически, в Swift 3 вы можете использовать типы измерений, и вам вообще не нужно знать формулу преобразования!
Мэтт

3
ПРИМЕЧАНИЕ, ОДНАКО этот суперпрофессиональный совет ... stackoverflow.com/a/28600210/294884
Fattie

1
Голосовать против без причины бессмысленно. Добавить комментарий
Лео Дабус

63

Это не совсем то, что вы просили, но в Swift 3 / iOS 10 вы можете использовать тип измерения и выполнять преобразование, не зная формулы!

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

4
Удивительный @matt снова на работе, спасибо! К сожалению, только iOS 10.
значение имеет значение

Интересно, что let radians = CGFloat (30.3 * .pi / 180.0) let radians2 = Measurement (value: 30.3, unit: UnitAngle.degrees) .converted (to: .radians) .value будет разные: 0.5288347633542818 и 0.5288345742619878
Запорожченко Александр

и убедитесь, что «Измерение доступно только на iOS 10.0 или новее»
Запорожченко Александр

42

Apple предоставляет следующие функции GLKit для преобразования:

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

GLKit скоро уйдет со сцены, так как теперь это мир металла, пока, GL. При переносе приложения iPad на Mac GLKit больше не поддерживается !.
Цзюгуан

17
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протокол бессмысленен. Инт уже соответствуетExpressibleByIntegerLiteral
Лео Дабус

Кстати, вы можете сделать этот оператор универсальным, чтобы поддерживать любое целое число и возвращать любую плавающую точку. public extension FixedWidthInteger { postfix static func °<T: FloatingPoint>(lhs: Self) -> T { T(lhs) * .pi / 180 } }
Лео Дабус

И прежде чем вы прокомментируете это при создании универсального метода, вам нужно будет явно установить результирующий тип, если компилятор не может вывести результирующий тип let angle: CGFloat = 45°. Но он не нужен там, где его ожидает CGFloatили какой-либо FloatingPointтип,CGAffineTransform(rotationAngle: 45°)
Лео Дабус

11

Кроме того, чтобы преобразовать радианы в градусы (если кто-нибудь наткнется на это в Google):

var degrees = radians * (180.0 / M_PI)

3

Вы больше не ограничены символами 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

2

Swift 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, потому что Tэто FloatingPointтип, а 180 - Intтип. В swift нельзя производить расчеты по разным типам.
Тихонов Александр

Вы неправы. Swift может определить тип. Он ведет себя точно так же, как если бы вы расширяли тип FloatingPoint. 180 может быть любым. не обязательно Int
Лео Дабус

1
FloatingPoint соответствует ExpressibleByIntegerLiteral, поэтому вы можете написать здесь 180
Лео Дабус

1
180.0 требует T, потому что T не обязательно является Double. Это может быть любой тип с плавающей запятой. Вы инициализируете новый из своего двойного 180.0
Лео Дабус

1

Я бы использовал тот же принцип @ t1ser, упомянутый выше, но создал бы расширение, CGFloatчтобы упростить использование десятичных знаков для степени (например, у вас может быть 23,4 градуса):

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

    init(degrees: CGFloat) {
        self = degrees.degrees()
    }
}

Использовать это тоже было бы довольно просто (в основном потому, что я лично не знал, как набирать ° 😜 - если вы тоже этого не сделали, это option+shift+8кстати):

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

Или использовать инициализатор:

let convertedDegrees = CGFloat(degrees: 45.3)
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.