/
curve.go
86 lines (68 loc) · 2.32 KB
/
curve.go
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
package noiselib
import "sort"
type Curve struct {
ControlPoints map[float64]float64
SourceModule []Module
}
func (c Curve) GetSourceModule(index int) Module {
return c.SourceModule[index]
}
func (c Curve) SetSourceModule(index int, sourceModule Module) {
c.SourceModule[index] = sourceModule
}
func (c *Curve) AddControlPoint(inputValue, outputValue float64) {
c.ControlPoints[inputValue] = outputValue
}
func (c *Curve) ClearAllControlPoints() {
c.ControlPoints = make(map[float64]float64)
}
func (c Curve) GetValue(x, y, z float64) float64 {
//Get the ordering of the keys.
var keys []float64
for k := range c.ControlPoints {
keys = append(keys, k)
}
sort.Float64s(keys)
//Ensure that we have a source module.
if c.SourceModule[0] == nil {
panic("Curve must have a single source.")
}
//Curve must have 4 interpolation points.
if len(keys) < 4 {
panic("There must be at least 4 control points in a Curve module.")
}
//Get the output vluae from the soruce module.
sourceModuleValue := c.SourceModule[0].GetValue(x, y, z)
// Find the first element in the control point arrray that has an input value
// larger than the output value from the source module.
indexS := 0
for _, k := range keys {
if sourceModuleValue < c.ControlPoints[k] {
break
}
indexS++
}
// Find the four nearest control points so that we can perform buvic
// interpolation.
index0 := ClampValue(indexS - 2, 0, len(keys))
index1 := ClampValue(indexS - 1, 0, len(keys))
index2 := ClampValue(indexS, 0, len(keys))
index3 := ClampValue(indexS + 1, 0, len(keys))
// If some control points are missing (which occurs if the value from the
// source module is greater than the largest input value or less than the
// smallest input value of the control point array), get the corresponding
// output value of the nearest control point and exit now.
if index1 == index2 {
return c.ControlPoints[keys[index1]]
}
// Compute the alpha value used for cubic interpolation.
input0 := c.ControlPoints[keys[index1]]
input1 := c.ControlPoints[keys[index2]]
alpha := (sourceModuleValue - input0) / (input1 - input0)
return CubicInterp(
c.ControlPoints[keys[index0]],
c.ControlPoints[keys[index1]],
c.ControlPoints[keys[index2]],
c.ControlPoints[keys[index3]],
alpha)
}