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.