about summary refs log tree commit diff
path: root/vendor/modernc.org/mathutil/envelope.go
blob: 71980db50038537357879e6991e3665e3c34ca92 (plain)
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
// Copyright (c) 2014 The mathutil Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package mathutil // import "modernc.org/mathutil"

import (
	"math"
)

// Approximation type determines approximation methods used by e.g. Envelope.
type Approximation int

// Specific approximation method tags
const (
	_          Approximation = iota
	Linear                   // As named
	Sinusoidal               // Smooth for all derivations
)

// Envelope is an utility for defining simple curves using a small (usually)
// set of data points.  Envelope returns a value defined by x, points and
// approximation.  The value of x must be in [0,1) otherwise the result is
// undefined or the function may panic. Points are interpreted as dividing the
// [0,1) interval in len(points)-1 sections, so len(points) must be > 1 or the
// function may panic. According to the left and right points closing/adjacent
// to the section the resulting value is interpolated using the chosen
// approximation method.  Unsupported values of approximation are silently
// interpreted as 'Linear'.
func Envelope(x float64, points []float64, approximation Approximation) float64 {
	step := 1 / float64(len(points)-1)
	fslot := math.Floor(x / step)
	mod := x - fslot*step
	slot := int(fslot)
	l, r := points[slot], points[slot+1]
	rmod := mod / step
	switch approximation {
	case Sinusoidal:
		k := (math.Sin(math.Pi*(rmod-0.5)) + 1) / 2
		return l + (r-l)*k
	case Linear:
		fallthrough
	default:
		return l + (r-l)*rmod
	}
}