github.com/cznic/mathutil@v0.0.0-20181122101859-297441e03548/envelope.go (about)

     1  // Copyright (c) 2014 The mathutil Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package mathutil
     6  
     7  import (
     8  	"math"
     9  )
    10  
    11  // Approximation type determines approximation methods used by e.g. Envelope.
    12  type Approximation int
    13  
    14  // Specific approximation method tags
    15  const (
    16  	_          Approximation = iota
    17  	Linear                   // As named
    18  	Sinusoidal               // Smooth for all derivations
    19  )
    20  
    21  // Envelope is an utility for defining simple curves using a small (usually)
    22  // set of data points.  Envelope returns a value defined by x, points and
    23  // approximation.  The value of x must be in [0,1) otherwise the result is
    24  // undefined or the function may panic. Points are interpreted as dividing the
    25  // [0,1) interval in len(points)-1 sections, so len(points) must be > 1 or the
    26  // function may panic. According to the left and right points closing/adjacent
    27  // to the section the resulting value is interpolated using the chosen
    28  // approximation method.  Unsupported values of approximation are silently
    29  // interpreted as 'Linear'.
    30  func Envelope(x float64, points []float64, approximation Approximation) float64 {
    31  	step := 1 / float64(len(points)-1)
    32  	fslot := math.Floor(x / step)
    33  	mod := x - fslot*step
    34  	slot := int(fslot)
    35  	l, r := points[slot], points[slot+1]
    36  	rmod := mod / step
    37  	switch approximation {
    38  	case Sinusoidal:
    39  		k := (math.Sin(math.Pi*(rmod-0.5)) + 1) / 2
    40  		return l + (r-l)*k
    41  	case Linear:
    42  		fallthrough
    43  	default:
    44  		return l + (r-l)*rmod
    45  	}
    46  }