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


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.