Spaces:
Sleeping
Sleeping
File size: 5,489 Bytes
6ee917b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | 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)
}
}
|