Skip to content

Commit 11109e0

Browse files
committed
Re: #207, add blerp() and trilerp() functions for bilinear and trilinear interpolation
1 parent daca5f3 commit 11109e0

File tree

6 files changed

+90
-4
lines changed

6 files changed

+90
-4
lines changed

docs/api.md

+14
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ codebase: 'https://github.com/evercoder/culori/blob/main'
1313
<li><a href='#averageAngle'>averageAngle</a></li>
1414
<li><a href='#averageNumber'>averageNumber</a></li>
1515
<li><a href='#blend'>blend</a></li>
16+
<li><a href='#blerp'>blerp</a></li>
1617
<li><a href='#clampChroma'>clampChroma</a></li>
1718
<li><a href='#clampRgb'>clampRgb</a></li>
1819
<li><a href='#colorsNamed'>colorsNamed</a></li>
@@ -102,6 +103,7 @@ codebase: 'https://github.com/evercoder/culori/blob/main'
102103
<li><a href='#round'>round</a></li>
103104
<li><a href='#samples'>samples</a></li>
104105
<li><a href='#toGamut'>toGamut</a></li>
106+
<li><a href='#trilerp'>trilerp</a></li>
105107
<li><a href='#unlerp'>unlerp</a></li>
106108
<li><a href='#useMode'>useMode</a></li>
107109
<li><a href='#wcagContrast'>wcagContrast</a></li>
@@ -912,6 +914,18 @@ lerp(5, 10, 0.5);
912914

913915
Returns the point `t` at which the value `v` is located between the values `a` and `b`. The inverse of `lerp`.
914916

917+
<a id="blerp" href="#blerp">#</a> **blerp**(_a00_, _a01_, _a10_, _a11_, _tx_, _ty_) → _value_
918+
919+
<span aria-label='Source:'>☞</span> [src/interpolate/lerp.js]({{codebase}}/src/interpolate/lerp.js)
920+
921+
Perform the [bilinear interpolation](https://en.wikipedia.org/wiki/Bilinear_interpolation) of the four values `a00`, `a01`, `a10`, and `a11` at the point `(tx, ty)`, with `tx, ty ∈ [0, 1]`. This is the extension of `lerp` to two dimensions.
922+
923+
<a id="trilerp" href="#trilerp">#</a> **trilerp**(_a000_, _a010_, _a100_, _a110_, _a001_, _a011_, _a101_, _a111_, _tx_, _ty_, _tz_) → _value_
924+
925+
<span aria-label='Source:'>☞</span> [src/interpolate/lerp.js]({{codebase}}/src/interpolate/lerp.js)
926+
927+
Perform the [trilinear interpolation](https://en.wikipedia.org/wiki/Trilinear_interpolation) of the eight values `a000`, `a010`, `a100`, `a110`, `a001`, `a011`, `a101`, and `a111` at the point `(tx, ty, tz)`, with `tx, ty, tz ∈ [0, 1]`. This is the extension of `lerp` to three dimensions.
928+
915929
### Mappings
916930

917931
<a id="mapper" href="#mapper">#</a> **mapper**(_fn_, _mode = "rgb"_) → _function (color | string)_

src/index-fn.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ export {
9393
interpolatorSplineMonotoneClosed
9494
} from './interpolate/splineMonotone.js';
9595

96-
export { lerp, unlerp } from './interpolate/lerp.js';
96+
export { lerp, unlerp, blerp, trilerp } from './interpolate/lerp.js';
9797
export { default as samples } from './samples.js';
9898
export {
9999
displayable,

src/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ export {
9494
interpolatorSplineMonotoneClosed
9595
} from './interpolate/splineMonotone.js';
9696

97-
export { lerp, unlerp } from './interpolate/lerp.js';
97+
export { lerp, unlerp, blerp, trilerp } from './interpolate/lerp.js';
9898
export { default as samples } from './samples.js';
9999
export {
100100
displayable,

src/interpolate/lerp.js

+25-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,28 @@
11
const lerp = (a, b, t) => a + t * (b - a);
22
const unlerp = (a, b, v) => (v - a) / (b - a);
33

4-
export { lerp, unlerp };
4+
const blerp = (a00, a01, a10, a11, tx, ty) => {
5+
return lerp(lerp(a00, a01, tx), lerp(a10, a11, tx), ty);
6+
};
7+
8+
const trilerp = (
9+
a000,
10+
a010,
11+
a100,
12+
a110,
13+
a001,
14+
a011,
15+
a101,
16+
a111,
17+
tx,
18+
ty,
19+
tz
20+
) => {
21+
return lerp(
22+
blerp(a000, a010, a100, a110, tx, ty),
23+
blerp(a001, a011, a101, a111, tx, ty),
24+
tz
25+
);
26+
};
27+
28+
export { lerp, blerp, trilerp, unlerp };

test/api.test.js

+4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const API_FULL = [
1414
'averageAngle',
1515
'averageNumber',
1616
'blend',
17+
'blerp',
1718
'clampChroma',
1819
'clampGamut',
1920
'clampRgb',
@@ -211,6 +212,7 @@ const API_FULL = [
211212
'serializeHsl',
212213
'serializeRgb',
213214
'toGamut',
215+
'trilerp',
214216
'unlerp',
215217
'useMode',
216218
'useParser',
@@ -278,6 +280,7 @@ const API_FN = [
278280
'averageAngle',
279281
'averageNumber',
280282
'blend',
283+
'blerp',
281284
'clampChroma',
282285
'clampGamut',
283286
'clampRgb',
@@ -451,6 +454,7 @@ const API_FN = [
451454
'serializeHsl',
452455
'serializeRgb',
453456
'toGamut',
457+
'trilerp',
454458
'unlerp',
455459
'useMode',
456460
'useParser',

test/lerp.test.js

+45-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import tape from 'tape';
2-
import { lerp, unlerp } from '../src/index.js';
2+
import { lerp, unlerp, blerp, trilerp } from '../src/index.js';
33

44
tape('lerp()', t => {
55
t.equal(lerp(10, 2, 0.5), 6);
@@ -10,3 +10,47 @@ tape('unlerp()', t => {
1010
t.equal(unlerp(5, 10, 2.5), -0.5);
1111
t.end();
1212
});
13+
14+
const RYB_CUBE = [
15+
{ mode: 'rgb', r: 1, g: 1, b: 1 }, // white
16+
{ mode: 'rgb', r: 1, g: 0, b: 0 }, // red
17+
{ mode: 'rgb', r: 1, g: 1, b: 0 }, // yellow
18+
{ mode: 'rgb', r: 1, g: 0.5, b: 0 }, // orange
19+
{ mode: 'rgb', r: 0.163, g: 0.373, b: 0.6 }, // blue
20+
{ mode: 'rgb', r: 0.5, g: 0, b: 0.5 }, // violet
21+
{ mode: 'rgb', r: 0, g: 0.66, b: 0.2 }, // green
22+
{ mode: 'rgb', r: 0.2, g: 0.094, b: 0 } // black
23+
];
24+
25+
tape('trilerp()', t => {
26+
const RYB_COLOR = [1, 0.5, 0.25];
27+
const EXPECTED_LINEAR = {
28+
mode: 'rgb',
29+
r: 0.8375,
30+
g: 0.19924999999999998,
31+
b: 0.0625
32+
};
33+
const EXPECTED_BIASED = {
34+
mode: 'rgb',
35+
r: 0.8984375,
36+
g: 0.21828124999999998,
37+
b: 0.0390625
38+
};
39+
40+
function ryb2rgb(coords, bias = true) {
41+
const biased_coords = bias
42+
? coords.map(t => t * t * (3 - 2 * t))
43+
: coords;
44+
return {
45+
mode: 'rgb',
46+
r: trilerp(...RYB_CUBE.map(it => it.r), ...biased_coords),
47+
g: trilerp(...RYB_CUBE.map(it => it.g), ...biased_coords),
48+
b: trilerp(...RYB_CUBE.map(it => it.b), ...biased_coords)
49+
};
50+
}
51+
52+
t.deepEqual(ryb2rgb(RYB_COLOR, false), EXPECTED_LINEAR, 'ryb: linear');
53+
t.deepEqual(ryb2rgb(RYB_COLOR), EXPECTED_BIASED, 'ryb: biased');
54+
55+
t.end();
56+
});

0 commit comments

Comments
 (0)