I am trying to convert this Obj-C code to Swift code but I don't know what the equivalent of this code should be ?
#define DEGREES_TO_RADIANS(degrees)((M_PI * degrees)/180)
I googled and found this
But I don't understand how to convert that in Swift in my case?
Xcode 11 • Swift 5.1 or later
extension BinaryInteger {
var degreesToRadians: CGFloat { CGFloat(self) * .pi / 180 }
}
extension FloatingPoint {
var degreesToRadians: Self { self * .pi / 180 }
var radiansToDegrees: Self { self * 180 / .pi }
}
Playground
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
If you would like to make the binary integer return a floating point type instead of always returning a CGFloat you can make a generic method instead of a computed property:
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
This is not identically what you asked, but in Swift 3 / iOS 10, you can use the Measurement type and do the conversion without knowing the formula!
let result = Measurement(value: 45, unit: UnitAngle.degrees)
.converted(to: .radians).value
Apple provides these GLKit functions for conversion:
func GLKMathDegreesToRadians(_ degrees: Float) -> Float
func GLKMathRadiansToDegrees(_ radians: Float) -> Float
let angle = 45° // angle will be in radians, 45 is in degrees
Compiles under Swift 3. Still keep all values, do all calculations in radians with CGFloats..., but make the code more readable with the constants in degrees. For example: 90°
The ° sign will magically do the degrees to radians conversion.
How to set this up:
Define and use a postfix operator for the ° sign. This operator will do the conversion from degrees to radians.
This example is for Ints, extend these also for the Float types if you have the need.
postfix operator °
protocol IntegerInitializable: ExpressibleByIntegerLiteral {
init (_: Int)
}
extension Int: IntegerInitializable {
postfix public static func °(lhs: Int) -> CGFloat {
return CGFloat(lhs) * .pi / 180
}
}
Some examples of usage:
let angle = 45°
contentView.transform = CGAffineTransform(rotationAngle: 45°)
let angle = 45
contentView.transform = CGAffineTransform(rotationAngle: angle°)
Warning!
It is too easy to use this conversion twice (on a value already in radians by mistake), you will get a very small number as the result, and seemingly the resulting angle will be always zero... DO NOT use ° on the same value twice (do not convert twice)!!:
// 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
Also, to convert fron radians to degrees (if anyone stumbles upon this on google):
var degrees = radians * (180.0 / M_PI)
The most efficient and accurate way to convert a Double between degrees and radians:
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 }
}
The Foundation team at Apple addressed this problem long ago by developing a solution that surpasses all others:
Measurements and Units - WWDC 2016, Session 238
You're no longer limited to ASCII characters when creating variable names, so how about this using π (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
}
}
Example usage:
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
Swift 4.2
You can write global generic functions:
public func radians<T: FloatingPoint>(degrees: T) -> T {
return .pi * degrees / 180
}
public func degrees<T: FloatingPoint>(radians: T) -> T {
return radians * 180 / .pi
}
Example:
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
In case when you don't want to extension all your floating types like this
extension FloatingPoint { ... }
I'd use the same principle #t1ser mentioned above, but create an extension of CGFloat to make it easier to use decimals for the degree as well (so you could have a 23.4 degrees, for example):
extension CGFloat {
func degrees() -> CGFloat {
return self * .pi / 180
}
init(degrees: CGFloat) {
self = degrees.degrees()
}
}
Using it would be pretty easy as well (mainly because I personally didn't know how to type ° 😜 - in case you didn't either, it's option+shift+8 btw):
let degreesToConvert: CGFloat = 45.7
.
.
.
let convertedDegrees = degreesToConvert.degrees()
Or to use the initialiser:
let convertedDegrees = CGFloat(degrees: 45.3)
If it is ok to import SwiftUI or if you are already using it you could use the Angle type to convert between angle units, eg.:
import SwiftUI
let radians = Angle(degrees: 45).radians
This will convert from Double to Double.
Related
I have a need where i have to multiply SCNVector3 with 0.1 to get a new position. When i try to do this, i am getting below error. This was working before in earlier Xcode Versions. I am using Xcode 10.1 with compiler of Swift 4 version. I have seen other answers for same kind of question but the data type differs here.
Binary operator '*' cannot be applied to operands of type 'SCNVector3' and 'Double'
And the code i am using is below,
guard let pointOfView = sceneView.pointOfView else { return }
let mat = pointOfView.transform
let dir = SCNVector3(-1 * mat.m31, -1 * mat.m32, -1 * mat.m33)
let currentPosition = pointOfView.position + (dir * 0.1) ------>
Getting error here
let projectedPlaneCenter = self.sceneView.projectPoint(currentPosition)
zVal = Double(projectedPlaneCenter.z)
The operator * is not defined for the operands SCNVector3 and Double.
I am guessing that by someVector * 0.1, you mean multiplying each component of the vector by 0.1?
In that case, you could define your own * operator:
// put this in the global scope
func *(lhs: SCNVector3, rhs: Double) -> SCNVector3 {
return SCNVector3(lhs.x * CGFloat(rhs), lhs.y * CGFloat(rhs), lhs.z * CGFloat(rhs))
}
// usage
SCNVector3(1, 2, 3) * 0.1 // (0.1, 0.2, 0.3)
Drop this into your project, and it should work.
public static func * (lhs: SCNVector3, rhs: Double) -> SCNVector3 {
return SCNVector3(lhs.x * .init(rhs), lhs.y * .init(rhs), lhs.z * .init(rhs))
}
public static func * (lhs: Double, rhs: SCNVector3) -> SCNVector3 {
return rhs * lhs
}
}
I am creating an Uber like iOS app(swift).I have integrated google map and added marker.Also i am receiving current latitude and longitude of the vehicle from backend API. Now i want to show the movement of vehicle in my app. I have written some code and it is working. But there is some issue with movement of the vehicle. There is some difference between position of marker in my app and the actual location of vehicle. Accuracy is not good. Here i am sharing my code.I calls the backend API in each 5 seconds.
func moveCab()
{
let oldCoordinate: CLLocationCoordinate2D? = CLLocationCoordinate2DMake(Double(oldLatitude)!,Double(oldLongitude)!)
let newCoordinate: CLLocationCoordinate2D? = CLLocationCoordinate2DMake(Double(currentLatitude)!,Double(currentLongitude)!)
mMarker.groundAnchor = CGPoint(x: CGFloat(0.5), y: CGFloat(0.5))
mMarker.rotation = CLLocationDegrees(getHeadingForDirection(fromCoordinate: oldCoordinate!, toCoordinate: newCoordinate!))
//found bearing value by calculation when marker add
mMarker.position = oldCoordinate!
//this can be old position to make car movement to new position
mMarker.map = mapView
//marker movement animation
CATransaction.begin()
CATransaction.setValue(Int(2.0), forKey: kCATransactionAnimationDuration)
CATransaction.setCompletionBlock({() -> Void in
self.mMarker.groundAnchor = CGPoint(x: CGFloat(0.5), y: CGFloat(0.5))
// mMarker.rotation = CDouble(data.value(forKey: "bearing"))
//New bearing value from backend after car movement is done
})
mMarker.position = newCoordinate!
mMarker.map = mapView
mMarker.groundAnchor = CGPoint(x: CGFloat(0.5), y: CGFloat(0.5))
mMarker.rotation = CLLocationDegrees(getHeadingForDirection(fromCoordinate: oldCoordinate!, toCoordinate: newCoordinate!))
//found bearing value by calculation
CATransaction.commit()
oldLatitude = currentLatitude
oldLongitude = currentLongitude
}
func getHeadingForDirection(fromCoordinate fromLoc: CLLocationCoordinate2D, toCoordinate toLoc: CLLocationCoordinate2D) -> Float {
let fLat: Float = Float((fromLoc.latitude).degreesToRadians)
let fLng: Float = Float((fromLoc.longitude).degreesToRadians)
let tLat: Float = Float((toLoc.latitude).degreesToRadians)
let tLng: Float = Float((toLoc.longitude).degreesToRadians)
let degree: Float = (atan2(sin(tLng - fLng) * cos(tLat), cos(fLat) * sin(tLat) - sin(fLat) * cos(tLat) * cos(tLng - fLng))).radiansToDegrees
if degree >= 0 {
return degree
}
else {
return 360 + degree
}
extension Int {
var degreesToRadians: Double { return Double(self) * .pi / 180 }
}
extension FloatingPoint {
var degreesToRadians: Self { return self * .pi / 180 }
var radiansToDegrees: Self { return self * 180 / .pi }
}
This question is related to an earlier question however I am receiving an infinite number not related to a divided by 0 problem. For example, the code below prints 4.5300000000000002 in the console but is flagged as .isInfinate and therefore I cannot store using Codable. How can I derive 4.53 (as a double) from this example?
//Calculation
func calculateMaximumAndAverageSkatingEfficiency() {
let heartRateUnit:HKUnit = HKUnit(from: "count/min")
let heartRatesAsDouble = heartRateValues.map { $0.quantity.doubleValue(for: heartRateUnit)}
let maxHeartRate = heartRatesAsDouble.max()
guard let maxHeartRateUnwrapped = maxHeartRate else { return }
maximumEfficiencyFactor = ((1760.0 * (maxSpeed / 60)) / maxHeartRateUnwrapped).round(to: 2)
guard let averageIceTimeHeartRateUnwrapped = averageIceTimeHeartRate else { return }
averageEfficiencyFactor = ((1760.0 * (averageSpeed / 60)) / averageIceTimeHeartRateUnwrapped).round(to: 2)
}
//Round extension I am using
extension Double {
func round(to places: Int) -> Double {
let divisor = pow(10.0, Double(places))
return Darwin.round(self * divisor) / divisor
}
}
//Usage
if let averageEfficiencyFactorUnwrapped = averageEfficiencyFactor {
if averageEfficiencyFactorUnwrapped.isFinite {
hockeyTrackerMetadata.averageEfficiencyFactor = averageEfficiencyFactorUnwrapped.round(to: 2)
} else {
print("AEF is infinite")
}
}
Double cannot precisely store 4.53 for the same reason that you cannot precisely write down the value 1/3 in decimal. (See What Every Programming Should Know About Floating-Point Arithmetic if this is unclear to you.)
If you want your rounding to be in decimal rather than binary, then you need to use a decimal type. See Decimal.
Your round(to:) method is incorrect because it assumes "places" are decimal digits. But Double works in binary digits. I believe what you want is this:
extension Double {
func round(toDecimalPlaces places: Int) -> Decimal {
var decimalValue = Decimal(self)
var result = decimalValue
NSDecimalRound(&result, &decimalValue, places, .plain)
return result
}
}
Note that 4.53 is in no way "infinite." It is somewhat less than 5. I don't see anywhere in your code that it should generate an infinite value. I would double-check how you're determining that.
I'm trying to follow some sample code https://medium.com/#yatchoi/getting-started-with-arkit-real-life-waypoints-1707e3cb1da2 below and I'm getting unresolved identifier 'MatrixHelper'
let translationMatrix = MatrixHelper.translate(
x: 0,
y: 0,
z: distance * -1
)
// Rotation matrix theta degrees
let rotationMatrix = MatrixHelper.rotateAboutY(
degrees: bearing * -1
)
What library or package do I need to import to get MatrixHelper - some Math package? I googled the docs but couldn't find anything.
I think he just wrote a custom class to wrap the functions provided by GLKit.
He named that class MatrixHelper.
With MatrixHelper.rotateAboutY() he is calling something like:
GLKMatrix4 GLKMatrix4Rotate(GLKMatrix4 matrix, float radians, float x, float y, float z);
So the package used in MatrixHelper is GLKit and to be more precise GLKMatrix4
https://developer.apple.com/documentation/glkit/glkmatrix4-pce
You can avoid using MatrixHelper (also GLKit), use simd, it is simple. The methods would look the following way:
func getTranslationMatrix(tx: Float, ty: Float, tz: Float) -> simd_float4x4 {
var translationMatrix = matrix_identity_float4x4
translationMatrix.columns.3 = simd_float4(tx, ty, tz, 1)
return translationMatrix
}
func getRotationYMatrix(angle: Float) -> simd_float3x3 {
let rows = [
simd_float3(cos(angle), 0, -sin(angle)),
simd_float3(0, 1, 0),
simd_float3(-sin(angle), 0, cos(angle))
]
return float3x3(rows: rows)
}
Or more specific the translation matrix:
func getTranslationZMatrix(tz: Float) -> simd_float4x4 {
var translationMatrix = matrix_identity_float4x4
translationMatrix.columns.3.z = tz
return translationMatrix
}
Then the code would look like:
func getTransformGiven(currentLocation: CLLocation) -> matrix_float4x4 {
let bearing = bearingBetween(
startLocation: currentLocation,
endLocation: location
)
let distance: Float = 5
let originTransform = matrix_identity_float4x4
// Create a transform with a translation of 5meter away
// let translationMatrix = MatrixHelper.translate(
// x: 0,
// y: 0,
// z: distance * -1
// )
let translationMatrix = getTranslationZMatrix(tz: distance * -1)
// Rotation matrix theta degrees
// let rotationMatrix = MatrixHelper.rotateAboutY(
// degrees: bearing * -1
// )
let rotationMatrix = getRotationYMatrix(angle: Float(bearing * 180 / Double.pi))
var transformMatrix = simd_mul(rotationMatrix, translationMatrix)
return simd_mul(originTransform, transformMatrix)
}
This question already has answers here:
CLLocation Category for Calculating Bearing w/ Haversine function
(8 answers)
Closed 8 years ago.
I'm trying to calculate a bearing between two CLLocation points in swift-only code. I've run into some difficulty and was assuming this is a pretty simple function. Stack overflow didn't seem to have anything listed.
func d2r(degrees : Double) -> Double {
return degrees * M_PI / 180.0
}
func RadiansToDegrees(radians : Double) -> Double {
return radians * 180.0 / M_PI
}
func getBearing(fromLoc : CLLocation, toLoc : CLLocation) {
let fLat = d2r(fromLoc.coordinate.latitude)
let fLng = d2r(fromLoc.coordinate.longitude)
let tLat = d2r(toLoc.coordinate.latitude)
let tLng = d2r(toLoc.coordinate.longitude)
var a = CGFloat(sin(fLng-tLng)*cos(tLat));
var b = CGFloat(cos(fLat)*sin(tLat)-sin(fLat)*cos(tLat)*cos(fLng-tLng))
return atan2(a,b)
}
I'm getting an error with my atan2 call about lvalue cgfloat or something...
Here is an Objective-C solution
CLLocation Category for Calculating Bearing w/ Haversine function
which can easily be translated to Swift:
func degreesToRadians(degrees: Double) -> Double { return degrees * .pi / 180.0 }
func radiansToDegrees(radians: Double) -> Double { return radians * 180.0 / .pi }
func getBearingBetweenTwoPoints1(point1 : CLLocation, point2 : CLLocation) -> Double {
let lat1 = degreesToRadians(degrees: point1.coordinate.latitude)
let lon1 = degreesToRadians(degrees: point1.coordinate.longitude)
let lat2 = degreesToRadians(degrees: point2.coordinate.latitude)
let lon2 = degreesToRadians(degrees: point2.coordinate.longitude)
let dLon = lon2 - lon1
let y = sin(dLon) * cos(lat2)
let x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon)
let radiansBearing = atan2(y, x)
return radiansToDegrees(radians: radiansBearing)
}
The result type is Double because that is how all location coordinates are
stored (CLLocationDegrees is a type alias for Double).
This isn't exactly accurate, but you're probably looking for something along the lines of:
func XXRadiansToDegrees(radians: Double) -> Double {
return radians * 180.0 / M_PI
}
func getBearingBetweenTwoPoints(point1 : CLLocation, point2 : CLLocation) -> Double {
// Returns a float with the angle between the two points
let x = point1.coordinate.longitude - point2.coordinate.longitude
let y = point1.coordinate.latitude - point2.coordinate.latitude
return fmod(XXRadiansToDegrees(atan2(y, x)), 360.0) + 90.0
}
I appropriated the code from this NSHipster article that goes into more detail about what's wrong with it. The basic issue is that it's using the coordinates as though the world is flat (which it isn't, right?). Mattt's article can show you how to get the real directions using MKMapPoints instead of CLLocations.