Skip to content

Commit

Permalink
math: add math.easing module, ported from the functions, described in
Browse files Browse the repository at this point in the history
  • Loading branch information
spytheman authored Dec 23, 2024
1 parent 47c0ca8 commit e6c1637
Show file tree
Hide file tree
Showing 4 changed files with 431 additions and 0 deletions.
272 changes: 272 additions & 0 deletions vlib/math/easing/easing.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
module easing

// Easing functions specify the value of a property, given a level of completeness from 0.0 to 1.0 .
// The names of the easing functions here, are based on the ones from https://easings.net/ and
// https://nicmulvaney.com/easing .
import math { cos, pow, sin, sqrt }

const pi = math.pi
const pi_half = pi / 2.0
const pi_double = pi * 2.0
const c1 = 1.70158
const c2 = c1 * 1.525
const c3 = c1 + 1.0
const c4 = pi_double / 3.0
const c5 = pi_double / 4.5
const n1 = 7.5625
const d1 = 2.75

// EasingFN defines the common shape of an easing function, so that you can define your own, and pass them everywhere,
// that expects easing.EasingFN . It is just a function that accepts a floating point number and returns one too.
pub type EasingFN = fn (x f64) f64

// linear just returns the parameter x, without changes .
@[inline]
pub fn linear(x f64) f64 {
return x
}

// in_sine returns the equivalent of https://easings.net/#easeInSine .
@[inline]
pub fn in_sine(x f64) f64 {
return 1.0 - cos(x * pi_half)
}

// out_sine returns the equivalent of https://easings.net/#easeOutSine .
@[inline]
pub fn out_sine(x f64) f64 {
return sin(x * pi_half)
}

// in_out_sine returns the equivalent of https://easings.net/#easeInOutSine .
@[inline]
pub fn in_out_sine(x f64) f64 {
return -(cos(pi * x) - 1.0) / 2.0
}

// in_quad returns the equivalent of https://easings.net/#easeInQuad .
@[inline]
pub fn in_quad(x f64) f64 {
return x * x
}

// out_quad returns the equivalent of https://easings.net/#easeOutQuad .
@[inline]
pub fn out_quad(x f64) f64 {
return 1.0 - (1.0 - x) * (1.0 - x)
}

// in_out_quad returns the equivalent of https://easings.net/#easeInOutQuad .
@[inline]
pub fn in_out_quad(x f64) f64 {
return if x < 0.5 { 2.0 * x * x } else { 1.0 - (2.0 - 2.0 * x) * (2.0 - 2.0 * x) / 2.0 }
}

// in_cubic returns the equivalent of https://easings.net/#easeInCubic .
@[inline]
pub fn in_cubic(x f64) f64 {
return x * x * x
}

// out_cubic returns the equivalent of https://easings.net/#easeOutCubic .
@[inline]
pub fn out_cubic(x f64) f64 {
return 1.0 - (1.0 - x) * (1.0 - x) * (1.0 - x)
}

// in_out_cubic returns the equivalent of https://easings.net/#easeInOutCubic .
@[inline]
pub fn in_out_cubic(x f64) f64 {
return if x < .5 {
4.0 * x * x * x
} else {
1.0 - (2.0 - 2.0 * x) * (2.0 - 2.0 * x) * (2.0 - 2.0 * x) / 2.0
}
}

// in_quart returns the equivalent of https://easings.net/#easeInQuart .
@[inline]
pub fn in_quart(x f64) f64 {
return x * x * x * x
}

// out_quart returns the equivalent of https://easings.net/#easeOutQuart .
@[inline]
pub fn out_quart(x f64) f64 {
return 1.0 - (1.0 - x) * (1.0 - x) * (1.0 - x) * (1.0 - x)
}

// in_out_quart returns the equivalent of https://easings.net/#easeInOutQuart .
@[inline]
pub fn in_out_quart(x f64) f64 {
return if x < 0.5 {
8.0 * x * x * x * x
} else {
1.0 - (2.0 - 2.0 * x) * (2.0 - 2.0 * x) * (2.0 - 2.0 * x) * (2.0 - 2.0 * x) / 2.0
}
}

// in_quint returns the equivalent of https://easings.net/#easeInQuint .
@[inline]
pub fn in_quint(x f64) f64 {
return x * x * x * x * x
}

// out_quint returns the equivalent of https://easings.net/#easeOutQuint .
@[inline]
pub fn out_quint(x f64) f64 {
return 1.0 - (1.0 - x) * (1.0 - x) * (1.0 - x) * (1.0 - x) * (1.0 - x)
}

// in_out_quint returns the equivalent of https://easings.net/#easeInOutQuint .
@[inline]
pub fn in_out_quint(x f64) f64 {
return if x < 0.5 {
16.0 * x * x * x * x * x
} else {
1.0 - (2.0 - 2.0 * x) * (2.0 - 2.0 * x) * (2.0 - 2.0 * x) * (2.0 - 2.0 * x) * (2.0 - 2.0 * x) / 2.0
}
}

// in_expo returns the equivalent of https://easings.net/#easeInExpo .
@[inline]
pub fn in_expo(x f64) f64 {
return if math.close(x, 0.0) { 0.0 } else { pow(2.0, 10.0 * x - 10.0) }
}

// out_expo returns the equivalent of https://easings.net/#easeOutExpo .
@[inline]
pub fn out_expo(x f64) f64 {
return if math.close(x, 1.0) { 1.0 } else { 1.0 - pow(2, -10.0 * x) }
}

// in_out_expo returns the equivalent of https://easings.net/#easeInOutExpo .
@[inline]
pub fn in_out_expo(x f64) f64 {
return if math.close(x, 0.0) {
0.0
} else if math.close(x, 1.0) {
1.0
} else if x < 0.5 {
pow(2.0, 20.0 * x - 10.0) / 2.0
} else {
2.0 - pow(2.0, 10.0 - 20.0 * x) / 2.0
}
}

// in_circ returns the equivalent of https://easings.net/#easeInCirc .
@[inline]
pub fn in_circ(x f64) f64 {
return 1.0 - sqrt(1.0 - x * x)
}

// out_circ returns the equivalent of https://easings.net/#easeOutCirc .
@[inline]
pub fn out_circ(x f64) f64 {
return sqrt(1.0 - pow(x - 1.0, 2.0))
}

// in_out_circ returns the equivalent of https://easings.net/#easeInOutCirc .
@[inline]
pub fn in_out_circ(x f64) f64 {
return if x < 0.5 {
(1.0 - sqrt(1.0 - pow(2.0 * x, 2.0))) / 2.0
} else {
(sqrt(1.0 - pow(-2.0 * x + 2.0, 2.0)) + 1.0) / 2.0
}
}

// in_back returns the equivalent of https://easings.net/#easeInBack .
@[inline]
pub fn in_back(x f64) f64 {
return c3 * x * x * x - c1 * x * x
}

// out_back returns the equivalent of https://easings.net/#easeOutBack .
@[inline]
pub fn out_back(x f64) f64 {
return 1.0 + c3 * pow(x - 1.0, 3.0) + c1 * pow(x - 1.0, 2.0)
}

// in_out_back returns the equivalent of https://easings.net/#easeInOutBack .
@[inline]
pub fn in_out_back(x f64) f64 {
return if x < 0.5 {
(pow(2.0 * x, x) * ((c2 + 1) * 2.0 * x - c2)) / 2.0
} else {
(pow(2.0 * x - 2.0, 2.0) * ((c2 + 1.0) * (x * 2.0 - 2.0) + c2) + 2.0) / 2.0
}
}

// in_elastic returns the equivalent of https://easings.net/#easeInElastic .
@[inline]
pub fn in_elastic(x f64) f64 {
return if math.close(x, 0.0) {
0.0
} else if math.close(x, 1.0) {
1.0
} else {
-pow(2.0, 10.0 * x - 10.0) * sin((x * 10.0 - 10.75) * c4)
}
}

// out_elastic returns the equivalent of https://easings.net/#easeOutElastic .
@[inline]
pub fn out_elastic(x f64) f64 {
return if math.close(x, 0.0) {
0.0
} else if math.close(x, 1.0) {
1.0
} else {
pow(2.0, -10.0 * x) * sin((x * 10.0 - 0.75) * c4) + 1.0
}
}

// in_out_elastic returns the equivalent of https://easings.net/#easeInOutElastic .
@[inline]
pub fn in_out_elastic(x f64) f64 {
return if math.close(x, 0.0) {
0.0
} else if math.close(x, 1.0) {
1.0
} else if x < 0.5 {
-(pow(2.0, 20.0 * x - 10.0) * sin((20.0 * x - 11.125) * c5)) / 2.0
} else {
(pow(2.0, -20.0 * x + 10.0) * sin((20.0 * x - 11.125) * c5)) / 2.0 + 1.0
}
}

// in_bounce returns the equivalent of https://easings.net/#easeInBounce .
@[inline]
pub fn in_bounce(x f64) f64 {
return 1.0 - out_bounce(1.0 - x)
}

// out_bounce returns the equivalent of https://easings.net/#easeOutBounce .
pub fn out_bounce(x f64) f64 {
if math.close(x, 1.0) {
return 1.0
}
xd1 := x * d1
return n1 * (if xd1 < 1.0 {
x * x
} else if xd1 < 2.0 {
pow((x - 1.5 / d1), 2.0) + 0.75
} else if xd1 < 2.5 {
pow((x - 2.25 / d1), 2.0) + 0.9375
} else {
pow((x - 2.625 / d1), 2.0) + 0.984375
})
}

// in_out_bounce returns the equivalent of https://easings.net/#easeInOutBounce .
pub fn in_out_bounce(x f64) f64 {
if math.close(x, 1.0) {
return 1.0
}
return if x < 0.5 {
(1.0 - out_bounce(1.0 - 2.0 * x)) / 2.0
} else {
(1.0 + out_bounce(2.0 * x - 1.0)) / 2.0
}
}
11 changes: 11 additions & 0 deletions vlib/math/easing/easing_test.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import math.easing

// Note: most of the checks are done not here, but by comparing the produced table,
// in the .vv/.out pair, checked by:
// `v run vlib/v/slow_tests/inout/math_easing_tables.vv > vlib/v/slow_tests/inout/math_easing_tables.out`

fn test_linear() {
for x := -10.0; x <= 10.0; x += 0.1 {
assert easing.linear(x) == x
}
}
78 changes: 78 additions & 0 deletions vlib/v/slow_tests/inout/math_easing_tables.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
in_ functions, compared to the linear one
+------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| x | linear | sine | quad | cubic | quart | quint | expo | circ | back | elastic | bounce |
+------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| -0.5 | -0.500 | 0.293 | 0.250 | -0.125 | 0.063 | -0.031 | 0.000 | 0.134 | -0.763 | 0.000 | -8.694 |
| -0.4 | -0.400 | 0.191 | 0.160 | -0.064 | 0.026 | -0.010 | 0.000 | 0.083 | -0.445 | -0.000 | -7.945 |
| -0.3 | -0.300 | 0.109 | 0.090 | -0.027 | 0.008 | -0.002 | 0.000 | 0.046 | -0.226 | -0.000 | -7.347 |
| -0.2 | -0.200 | 0.049 | 0.040 | -0.008 | 0.002 | -0.000 | 0.000 | 0.020 | -0.090 | 0.000 | -6.900 |
| -0.1 | -0.100 | 0.012 | 0.010 | -0.001 | 0.000 | -0.000 | 0.000 | 0.005 | -0.020 | -0.000 | -6.604 |
| -0.0 | -0.000 | 0.000 | 0.000 | -0.000 | 0.000 | -0.000 | 0.000 | 0.000 | -0.000 | 0.000 | 0.000 |
| 0.1 | 0.100 | 0.012 | 0.010 | 0.001 | 0.000 | 0.000 | 0.002 | 0.005 | -0.014 | 0.002 | -6.140 |
| 0.2 | 0.200 | 0.049 | 0.040 | 0.008 | 0.002 | 0.000 | 0.004 | 0.020 | -0.046 | -0.002 | -6.092 |
| 0.3 | 0.300 | 0.109 | 0.090 | 0.027 | 0.008 | 0.002 | 0.008 | 0.046 | -0.080 | -0.004 | -4.853 |
| 0.4 | 0.400 | 0.191 | 0.160 | 0.064 | 0.026 | 0.010 | 0.016 | 0.083 | -0.099 | 0.016 | -4.694 |
| 0.5 | 0.500 | 0.293 | 0.250 | 0.125 | 0.063 | 0.031 | 0.031 | 0.134 | -0.088 | -0.016 | -4.688 |
| 0.6 | 0.600 | 0.412 | 0.360 | 0.216 | 0.130 | 0.078 | 0.063 | 0.200 | -0.029 | -0.031 | -4.832 |
| 0.7 | 0.700 | 0.546 | 0.490 | 0.343 | 0.240 | 0.168 | 0.125 | 0.286 | 0.093 | 0.125 | 0.319 |
| 0.8 | 0.800 | 0.691 | 0.640 | 0.512 | 0.410 | 0.328 | 0.250 | 0.400 | 0.294 | -0.125 | 0.697 |
| 0.9 | 0.900 | 0.844 | 0.810 | 0.729 | 0.656 | 0.590 | 0.500 | 0.564 | 0.591 | -0.250 | 0.924 |
| 1.0 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 |
| 1.1 | 1.100 | 1.156 | 1.210 | 1.331 | 1.464 | 1.611 | 2.000 | nan | 1.537 | -1.000 | 0.924 |
| 1.2 | 1.200 | 1.309 | 1.440 | 1.728 | 2.074 | 2.488 | 4.000 | nan | 2.218 | -2.000 | 0.698 |
| 1.3 | 1.300 | 1.454 | 1.690 | 2.197 | 2.856 | 3.713 | 8.000 | nan | 3.060 | 8.000 | 0.319 |
| 1.4 | 1.400 | 1.588 | 1.960 | 2.744 | 3.842 | 5.378 | 16.000 | nan | 4.078 | -8.000 | -0.210 |
| 1.5 | 1.500 | 1.707 | 2.250 | 3.375 | 5.063 | 7.594 | 32.000 | nan | 5.289 | -16.000 | -0.891 |
+------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
out_ functions, compared to the linear one
+------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| x | linear | sine | quad | cubic | quart | quint | expo | circ | back | elastic | bounce |
+------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| -0.5 | -0.500 | -0.707 | -1.250 | -2.375 | -4.063 | -6.594 | -31.000 | nan | -4.289 | 17.000 | 1.891 |
| -0.4 | -0.400 | -0.588 | -0.960 | -1.744 | -2.842 | -4.378 | -15.000 | nan | -3.078 | 9.000 | 1.210 |
| -0.3 | -0.300 | -0.454 | -0.690 | -1.197 | -1.856 | -2.713 | -7.000 | nan | -2.060 | -7.000 | 0.681 |
| -0.2 | -0.200 | -0.309 | -0.440 | -0.728 | -1.074 | -1.488 | -3.000 | nan | -1.218 | 3.000 | 0.303 |
| -0.1 | -0.100 | -0.156 | -0.210 | -0.331 | -0.464 | -0.611 | -1.000 | nan | -0.537 | 2.000 | 0.076 |
| -0.0 | -0.000 | -0.000 | 0.000 | 0.000 | 0.000 | 0.000 | -0.000 | 0.000 | 0.000 | 0.000 | 0.000 |
| 0.1 | 0.100 | 0.156 | 0.190 | 0.271 | 0.344 | 0.410 | 0.500 | 0.436 | 0.409 | 1.250 | 0.076 |
| 0.2 | 0.200 | 0.309 | 0.360 | 0.488 | 0.590 | 0.672 | 0.750 | 0.600 | 0.706 | 1.125 | 0.302 |
| 0.3 | 0.300 | 0.454 | 0.510 | 0.657 | 0.760 | 0.832 | 0.875 | 0.714 | 0.907 | 0.875 | 0.681 |
| 0.4 | 0.400 | 0.588 | 0.640 | 0.784 | 0.870 | 0.922 | 0.938 | 0.800 | 1.029 | 1.031 | 5.832 |
| 0.5 | 0.500 | 0.707 | 0.750 | 0.875 | 0.938 | 0.969 | 0.969 | 0.866 | 1.088 | 1.016 | 5.688 |
| 0.6 | 0.600 | 0.809 | 0.840 | 0.936 | 0.974 | 0.990 | 0.984 | 0.917 | 1.099 | 0.984 | 5.694 |
| 0.7 | 0.700 | 0.891 | 0.910 | 0.973 | 0.992 | 0.998 | 0.992 | 0.954 | 1.080 | 1.004 | 5.853 |
| 0.8 | 0.800 | 0.951 | 0.960 | 0.992 | 0.998 | 1.000 | 0.996 | 0.980 | 1.046 | 1.002 | 7.092 |
| 0.9 | 0.900 | 0.988 | 0.990 | 0.999 | 1.000 | 1.000 | 0.998 | 0.995 | 1.014 | 0.998 | 7.140 |
| 1.0 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 |
| 1.1 | 1.100 | 0.988 | 0.990 | 1.001 | 1.000 | 1.000 | 1.000 | 0.995 | 1.020 | 1.000 | 7.604 |
| 1.2 | 1.200 | 0.951 | 0.960 | 1.008 | 0.998 | 1.000 | 1.000 | 0.980 | 1.090 | 1.000 | 7.900 |
| 1.3 | 1.300 | 0.891 | 0.910 | 1.027 | 0.992 | 1.002 | 1.000 | 0.954 | 1.226 | 1.000 | 8.347 |
| 1.4 | 1.400 | 0.809 | 0.840 | 1.064 | 0.974 | 1.010 | 1.000 | 0.917 | 1.445 | 1.000 | 8.945 |
| 1.5 | 1.500 | 0.707 | 0.750 | 1.125 | 0.937 | 1.031 | 1.000 | 0.866 | 1.763 | 1.000 | 9.694 |
+------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
in_out_ functions, compared to the linear one
+------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| x | linear | sine | quad | cubic | quart | quint | expo | circ | back | elastic | bounce |
+------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| -0.5 | -0.500 | 0.500 | 0.500 | -0.500 | 0.500 | -0.500 | 0.000 | 0.500 | nan | -0.000 | -7.355 |
| -0.4 | -0.400 | 0.345 | 0.320 | -0.256 | 0.205 | -0.164 | 0.000 | 0.200 | nan | 0.000 | -5.925 |
| -0.3 | -0.300 | 0.206 | 0.180 | -0.108 | 0.065 | -0.039 | 0.000 | 0.100 | nan | -0.000 | -4.797 |
| -0.2 | -0.200 | 0.095 | 0.080 | -0.032 | 0.013 | -0.005 | 0.000 | 0.042 | nan | 0.000 | -3.972 |
| -0.1 | -0.100 | 0.024 | 0.020 | -0.004 | 0.001 | -0.000 | 0.000 | 0.010 | nan | -0.000 | -3.450 |
| -0.0 | -0.000 | -0.000 | 0.000 | -0.000 | 0.000 | -0.000 | 0.000 | 0.000 | nan | 0.000 | 0.000 |
| 0.1 | 0.100 | 0.024 | 0.020 | 0.004 | 0.001 | 0.000 | 0.002 | 0.010 | -0.799 | 0.000 | -3.046 |
| 0.2 | 0.200 | 0.095 | 0.080 | 0.032 | 0.013 | 0.005 | 0.008 | 0.042 | -0.482 | -0.004 | -2.347 |
| 0.3 | 0.300 | 0.206 | 0.180 | 0.108 | 0.065 | 0.039 | 0.031 | 0.100 | -0.188 | 0.024 | -2.416 |
| 0.4 | 0.400 | 0.345 | 0.320 | 0.256 | 0.205 | 0.164 | 0.125 | 0.200 | 0.129 | -0.117 | 0.349 |
| 0.5 | 0.500 | 0.500 | 0.500 | 0.500 | 0.500 | 0.500 | 1.500 | 0.500 | 0.500 | 0.500 | 0.500 |
| 0.6 | 0.600 | 0.655 | 0.680 | 0.744 | 0.795 | 0.836 | 1.875 | 0.800 | 0.910 | 1.117 | 0.651 |
| 0.7 | 0.700 | 0.794 | 0.820 | 0.892 | 0.935 | 0.961 | 1.969 | 0.900 | 1.079 | 0.976 | 3.416 |
| 0.8 | 0.800 | 0.905 | 0.920 | 0.968 | 0.987 | 0.995 | 1.992 | 0.958 | 1.093 | 1.004 | 3.347 |
| 0.9 | 0.900 | 0.976 | 0.980 | 0.996 | 0.999 | 1.000 | 1.998 | 0.990 | 1.038 | 1.000 | 4.046 |
| 1.0 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 |
| 1.1 | 1.100 | 0.976 | 0.980 | 1.004 | 0.999 | 1.000 | 2.000 | 0.990 | 1.066 | 1.000 | 4.450 |
| 1.2 | 1.200 | 0.905 | 0.920 | 1.032 | 0.987 | 1.005 | 2.000 | 0.958 | 1.323 | 1.000 | 4.972 |
| 1.3 | 1.300 | 0.794 | 0.820 | 1.108 | 0.935 | 1.039 | 2.000 | 0.900 | 1.855 | 1.000 | 5.797 |
| 1.4 | 1.400 | 0.655 | 0.680 | 1.256 | 0.795 | 1.164 | 2.000 | 0.800 | 2.751 | 1.000 | 6.925 |
| 1.5 | 1.500 | 0.500 | 0.500 | 1.500 | 0.500 | 1.500 | 2.000 | nan | 4.095 | 1.000 | 8.355 |
+------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
Loading

0 comments on commit e6c1637

Please sign in to comment.