Jak mogę zamienić stopnie na radiany?


107

Próbuję przekonwertować ten Obj-Ckod na Swiftkod, ale nie wiem, jaki powinien być odpowiednik tego kodu?

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

Poszukałem w Google i znalazłem to

Ale nie rozumiem, jak przekonwertować to w Swift w moim przypadku?


Myślę, że brakuje ci jakiegoś kodu. Czy możecie wszyscy dodać cały odpowiedni kod? Jakieś inne definicje, takie jak stopnie?
— BlackHatSamurai

to jest mój szybki kod: pastebin.com/bZ4a7EVN
— Dharmesh Kheni

Czy możesz mi pokazać swój plik .h?
— BlackHatSamurai

To jest makro. Chcesz funkcji.
— gnasher729

Odpowiedzi:


267

Xcode 11 • Swift 5.1 lub nowszy

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

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

Plac zabaw

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

Jeśli chcesz, aby binarna liczba całkowita zwracała typ zmiennoprzecinkowy zamiast zawsze zwracać CGFloat, możesz utworzyć metodę ogólną zamiast obliczonej właściwości:

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
Nie powinieneś przedłużyć CGFloat?
— Zorayr

1
@Zorayr zaktualizowany do Swift 3, a rozszerzenie FloatingPoint teraz rozszerza je wszystkie
— Leo Dabus

3
Właściwie w Swift 3 możesz używać typów pomiarów i nie musisz w ogóle znać wzoru konwersji!
— mat.

3
UWAGA JEDNAK ta super
— pro

1
Głosowanie bez powodu nie ma sensu. Napisz komentarz
— Leo Dabus

63

To nie jest dokładnie to, o co prosiłeś, ale w Swift 3 / iOS 10 możesz użyć typu pomiaru i wykonać konwersję bez znajomości wzoru!

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

4
Niesamowity @matt znowu w pracy, dzięki! Niestety tylko iOS 10.
— znaczenie-ma znaczenie

interesująca rzecz, która pozwoliła radianom = CGFloat (30,3 * .pi / 180,0) niech radians2 = Measurement (wartość: 30,3, jednostka: UnitAngle.degrees). przeliczone (na: .radians). wartość będzie inna: 0.5288347633542818 i 0.5288345742619878
— Zaporożczenko Oleksandr

i upewnij się, że „Pomiar” jest dostępny tylko na iOS 10.0 lub nowszym ”
— Zaporożczenko Oleksandr

42

Apple udostępnia następujące funkcje GLKit do konwersji:

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

GLKit wkrótce zejdzie ze sceny, ponieważ teraz to świat Metalu, pa GL. GLKit nie jest już obsługiwany jako przenoszenie aplikacji na iPada na Maca !.
— Juguang

17
let angle = 45° // angle will be in radians, 45 is in degrees

Kompiluje pod Swift 3 . Nadal zachowuj wszystkie wartości, wykonuj wszystkie obliczenia w radianach za pomocą CGFloats ..., ale spraw, aby kod był bardziej czytelny dzięki stałym w stopniach. Na przykład: 90 ° Znak ° w magiczny sposób zamienia stopnie na radiany.

Jak to ustawić:

Zdefiniuj i użyj operatora przyrostka dla znaku ° . Ten operator dokona konwersji ze stopni na radiany. Ten przykład jest dla Ints, rozszerz je również dla typów Float, jeśli masz taką potrzebę.

postfix operator °

protocol IntegerInitializable: ExpressibleByIntegerLiteral {
  init (_: Int)
}

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

Kilka przykładów użycia:

let angle = 45°

contentView.transform = CGAffineTransform(rotationAngle: 45°)

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

Ostrzeżenie!

Zbyt łatwo jest użyć tej konwersji dwa razy (na wartości już w radianach przez pomyłkę), otrzymasz bardzo małą liczbę i pozornie wynikowy kąt będzie zawsze równy zero ... NIE używaj ° na tym samym wartość dwukrotnie (nie konwertuj dwukrotnie) !!:

// 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

IntegerInitializableprotokół jest bezcelowy. Int już się ExpressibleByIntegerLiteral
— zgadza

Btw Możesz uczynić ten operator generycznym, aby obsługiwał dowolną liczbę całkowitą i zwracał również dowolny zmiennoprzecinkowy. public extension FixedWidthInteger { postfix static func °<T: FloatingPoint>(lhs: Self) -> T { T(lhs) * .pi / 180 } }
— Leo Dabus

I zanim skomentujesz to podczas tworzenia metody ogólnej, musisz jawnie ustawić typ wynikowy, jeśli kompilator nie może wywnioskować typu wynikowego let angle: CGFloat = 45°. Ale to nie jest konieczne, jeżeli oczekuje się CGFloatlub dowolny FloatingPointtypCGAffineTransform(rotationAngle: 45°)
— Leo Dabus

11

Ponadto, aby przekonwertować fron radianów na stopnie (jeśli ktoś natknie się na to w Google):

var degrees = radians * (180.0 / M_PI)

3

Nie jesteś już ograniczony do znaków ASCII podczas tworzenia nazw zmiennych, więc co powiesz na to, używając π (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
    }
}

Przykładowe użycie:

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

Możesz pisać globalne funkcje ogólne:

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

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

Przykład:

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

W przypadku, gdy nie chcesz rozszerzać wszystkich typów pływających w ten sposób

extension FloatingPoint { ... }

Dlaczego nie po prostu return .pi * degrees / 180?
— Leo Dabus

@LeoDabus, ponieważ Tto FloatingPointtyp, a 180 to Inttyp. Szybko nie możesz wykonywać obliczeń na różnych typach.
— Tichonow Aleksander

Mylisz się. Swift może wywnioskować typ. Zachowuje się dokładnie tak samo, jak gdybyś rozszerzał typ FloatingPoint. 180 może oznaczać dowolną rzecz. niekoniecznie Int
— Leo Dabus

1
FloatingPoint jest zgodny z ExpressibleByIntegerLiteral, dlatego możesz tam wpisać 180
— Leo Dabus

1
180.0 potrzebuje T, ponieważ T niekoniecznie jest Double. Może to być dowolny typ zmiennoprzecinkowy. Inicjalizujesz nowy ze swojego podwójnego 180.0
— Leo Dabus

1

Użyłbym tej samej zasady @ t1ser, o której wspomniano powyżej, ale utworzyłbym rozszerzenie, CGFloataby ułatwić użycie ułamków dziesiętnych również dla stopnia (więc możesz mieć na przykład 23,4 stopnia):

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

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

Używanie go również byłoby całkiem proste (głównie dlatego, że osobiście nie wiedziałem, jak wpisać ° 😜 - na wypadek, gdybyś ty też nie, to przy option+shift+8okazji):

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

Lub użyj inicjatora:

let convertedDegrees = CGFloat(degrees: 45.3)
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.