open-wether / Sources /App /Helper /NumberExtensions.swift
soiz1's picture
Migrated from GitHub
6ee917b verified
import Foundation
public extension Double {
func round(digits: Int) -> Double {
let mut = Foundation.pow(10, Double(digits))
return (self * mut).rounded() / mut
}
}
public extension Float {
var degreesToRadians: Float {
return self * .pi / 180
}
var radiansToDegrees: Float {
return self * 180 / .pi
}
}
extension Int {
/// Integer division, but round up instead of floor
func divideRoundedUp(divisor: Int) -> Int {
return (self + divisor - 1) / divisor
}
func zeroPadded(len: Int) -> String {
return String(format: "%0\(len)d", self)
}
/// Performs mathematical module keeping the result positive
@inlinable func moduloPositive(_ devisor: Int) -> Int {
return((self % devisor) + devisor) % devisor
}
/// Devide the current number using integer devision, and report the reaming part as a fraction
@inlinable func moduloFraction(_ devisor: Int) -> (quotient: Int, fraction: Float) {
let fraction = Float(self.moduloPositive(devisor)) / Float(devisor)
return (self / devisor, fraction)
}
@inlinable func ceil(to toNearest: Int) -> Int {
return ((self + toNearest - 1) / toNearest) * toNearest
}
@inlinable func floor(to toNearest: Int) -> Int {
return (self / toNearest) * toNearest
}
}
extension Range where Element == Int {
/// The lower bound uses a regular division, the upper bound uses divideRoundedUp
func divideRoundedUp(divisor: Int) -> Range<Int> {
return lowerBound / divisor ..< upperBound.divideRoundedUp(divisor: divisor)
}
/// Return the intersect position between 2 ranges
public func intersect(fileTime: Range<Int>) -> (file: CountableRange<Int>, array: CountableRange<Int>)? {
let fileLower = fileTime.lowerBound
let fileUpper = fileTime.upperBound
let arrayLower = self.lowerBound
let arrayUpper = self.upperBound
let arrayStart = Swift.max(0, fileLower - arrayLower)
let arrayEnd = Swift.min(fileUpper - arrayLower, arrayUpper - arrayLower)
if arrayStart >= arrayEnd {
return nil
}
let array = arrayStart ..< arrayEnd
if array.count == 0 {
return nil
}
let fileEnd = Swift.min(arrayUpper - fileLower, fileUpper - fileLower)
let fileStart = fileEnd - array.count
let file = fileStart ..< fileEnd
assert(file.count == array.count, "Offsets missmatch file=\(file.count), array=\(array.count)")
return (file, array)
}
@inlinable public func add(_ offset: Int) -> Range<Int> {
return lowerBound + offset ..< upperBound + offset
}
@inlinable public func multiply(_ by: Int) -> Range<Int> {
return lowerBound * by ..< upperBound * by
}
}
extension Range where Bound == Float {
/// Interpolate between lower and upper bound
func interpolated(atFraction at: Float) -> Float {
let value = lowerBound + (upperBound - lowerBound) * at
return Swift.min(Swift.max(value, lowerBound), upperBound)
}
/// Return the fraction of wheever the value is. limited to to 0...1
func fraction(of value: Float) -> Float {
let limited = Swift.min(Swift.max(value, lowerBound), upperBound)
return (limited - lowerBound) / (upperBound - lowerBound)
}
}
public extension RandomAccessCollection where Element == Float, Index == Int {
/// Calculate linear interpolation. Index and fraction are kept apart, because of floating point inprecisions
@inlinable func interpolateLinear(_ i: Int, _ fraction: Float) -> Float {
assert(self.count != 0)
assert(0 <= fraction && fraction <= 1)
if i < startIndex {
return self.first!
}
if i >= endIndex - 1 {
return self.last!
}
let leftVal = self[i]
if fraction < 0.001 {
return leftVal
}
let rightVal = self[i + 1]
if fraction > 0.999 {
return rightVal
}
return leftVal * (1-fraction) + rightVal * fraction
}
/// Assume data is organised in a ring. E,g, the right hand side border will interpolate with the left side.
@inlinable func interpolateLinearRing(_ i: Int, _ fraction: Float) -> Float {
assert(self.count != 0)
assert(0 <= fraction && fraction <= 1)
let leftVal = self[i % count]
if fraction < 0.001 {
return leftVal
}
let rightVal = self[(i + 1) % count]
if fraction > 0.999 {
return rightVal
}
return leftVal * (1-fraction) + rightVal * fraction
}
/// Assume data is organised in a ring. E,g, the right hand side border will interpolate with the left side.
@inlinable func interpolateHermiteRing(_ i: Int, _ fraction: Float) -> Float {
assert(self.count != 0)
assert(0 <= fraction && fraction <= 1)
let A = self[(i - 1 + count) % count]
let B = self[i % count]
let C = self[(i+1) % count]
let D = self[(i+2) % count]
let a = -A/2.0 + (3.0*B)/2.0 - (3.0*C)/2.0 + D/2.0
let b = A - (5.0*B)/2.0 + 2.0*C - D / 2.0
let c = -A/2.0 + C/2.0
let d = B
return (a*fraction*fraction*fraction + b*fraction*fraction + c*fraction + d)
}
}