...
1 package utils
2
3 import (
4 "fmt"
5 "sort"
6 "sync"
7 )
8
9
15 type Interpolator struct {
16 sync.Mutex
17 referencepoints []*interpolator_referencepoint
18 }
19
20 type interpolator_referencepoint struct {
21 number float64
22 value float64
23 }
24
25 func (ip *Interpolator) AddReferencePoints(points map[float64]float64) {
26 for k, v := range points {
27 ip.AddReferencePoint(k, v)
28 }
29 }
30 func (ip *Interpolator) AddReferencePoint(number, value float64) {
31 ip.Lock()
32 defer ip.Unlock()
33 if len(ip.referencepoints) == 0 && number != 0 {
34 ip.referencepoints = append(ip.referencepoints, &interpolator_referencepoint{number: 0, value: 0})
35 }
36
37
38 var res []*interpolator_referencepoint
39 for _, rp := range ip.referencepoints {
40 if rp.number == number {
41 continue
42 }
43 res = append(res, rp)
44 }
45 ip.referencepoints = res
46
47
48 ip.referencepoints = append(ip.referencepoints, &interpolator_referencepoint{number: number, value: value})
49
50
51 sort.Slice(ip.referencepoints, func(i, j int) bool {
52 return ip.referencepoints[i].number < ip.referencepoints[j].number
53 })
54 var last *interpolator_referencepoint
55
56
57 for _, ir := range ip.referencepoints {
58 if last == nil {
59 last = ir
60 continue
61 }
62 if ir.value < last.value {
63 fmt.Printf("WARNING: interpolator values out of order: %s\n", ip.String())
64 }
65 last = ir
66 }
67 }
68
69
72 func (ip *Interpolator) LinearInterpolate(number float64) float64 {
73 ir1, ir2 := ip.findReferences(number)
74 if ir2 == nil {
75
76
77 return ir1.value
78 }
79 xa := ir1.number
80 ya := ir1.value
81 xb := ir2.number
82 yb := ir2.value
83 x := number
84 diff := (x - xa) / (xb - xa)
85 y := ya + (yb-ya)*diff
86
87 return y
88 }
89 func (ip *Interpolator) findReferences(number float64) (*interpolator_referencepoint, *interpolator_referencepoint) {
90 var ir1 *interpolator_referencepoint
91 var ir2 *interpolator_referencepoint
92 for i, ir := range ip.referencepoints {
93 if number < ir.number {
94 continue
95 }
96 ir1 = ir
97 if i < len(ip.referencepoints)-1 {
98 ir2 = ip.referencepoints[i+1]
99 } else {
100 ir2 = nil
101 }
102 }
103 return ir1, ir2
104 }
105 func (ip *Interpolator) String() string {
106 deli := ""
107 s := ""
108 for _, ir := range ip.referencepoints {
109 s = s + deli + fmt.Sprintf("%f->%f", ir.number, ir.value)
110 deli = ", "
111 }
112 return s
113 }
114
115 func (ir *interpolator_referencepoint) String() string {
116 return fmt.Sprintf("%f->%f", ir.number, ir.value)
117 }
118
View as plain text