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)
    }
}