mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-22 01:11:42 +00:00
[wpilib] Tweak Color HSV formula and use in AddressableLED (#4724)
The Color algorithm was tweaked to: a) not produce incorrect values if the user happens to input a hue outside the [0, 180) range, and b) more accurately convert the hue remainder from range 0-30 to 0-255. The current conversion vastly overshoots the multiplier (converts 0-30 to 0-270) and relies on clamping the value when constructing the Color object to produce a slightly incorrect result.
This commit is contained in:
@@ -39,7 +39,7 @@ public class AddressableLEDBuffer {
|
||||
* Sets a specific led in the buffer.
|
||||
*
|
||||
* @param index the index to write
|
||||
* @param h the h value [0-180]
|
||||
* @param h the h value [0-180)
|
||||
* @param s the s value [0-255]
|
||||
* @param v the v value [0-255]
|
||||
*/
|
||||
@@ -49,31 +49,48 @@ public class AddressableLEDBuffer {
|
||||
return;
|
||||
}
|
||||
|
||||
final int region = h / 30;
|
||||
final int remainder = (h - (region * 30)) * 6;
|
||||
// The below algorithm is copied from Color.fromHSV and moved here for
|
||||
// performance reasons.
|
||||
|
||||
final int p = (v * (255 - s)) >> 8;
|
||||
final int q = (v * (255 - ((s * remainder) >> 8))) >> 8;
|
||||
final int t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8;
|
||||
// Loosely based on
|
||||
// https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB
|
||||
// The hue range is split into 60 degree regions where in each region there
|
||||
// is one rgb component at a low value (m), one at a high value (v) and one
|
||||
// that changes (X) from low to high (X+m) or high to low (v-X)
|
||||
|
||||
// Difference between highest and lowest value of any rgb component
|
||||
final int chroma = (s * v) / 255;
|
||||
|
||||
// Beacuse hue is 0-180 rather than 0-360 use 30 not 60
|
||||
final int region = (h / 30) % 6;
|
||||
|
||||
// Remainder converted from 0-30 to 0-255
|
||||
final int remainder = (int) Math.round((h % 30) * (255 / 30.0));
|
||||
|
||||
// Value of the lowest rgb component
|
||||
final int m = v - chroma;
|
||||
|
||||
// Goes from 0 to chroma as hue increases
|
||||
final int X = (chroma * remainder) >> 8;
|
||||
|
||||
switch (region) {
|
||||
case 0:
|
||||
setRGB(index, v, t, p);
|
||||
setRGB(index, v, X + m, m);
|
||||
break;
|
||||
case 1:
|
||||
setRGB(index, q, v, p);
|
||||
setRGB(index, v - X, v, m);
|
||||
break;
|
||||
case 2:
|
||||
setRGB(index, p, v, t);
|
||||
setRGB(index, m, v, X + m);
|
||||
break;
|
||||
case 3:
|
||||
setRGB(index, p, q, v);
|
||||
setRGB(index, m, v - X, v);
|
||||
break;
|
||||
case 4:
|
||||
setRGB(index, t, p, v);
|
||||
setRGB(index, X + m, m, v);
|
||||
break;
|
||||
default:
|
||||
setRGB(index, v, p, q);
|
||||
setRGB(index, v, m, v - X);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,13 +85,13 @@ public class Color {
|
||||
// that changes (X) from low to high (X+m) or high to low (v-X)
|
||||
|
||||
// Difference between highest and lowest value of any rgb component
|
||||
final int chroma = (s * v) >> 8;
|
||||
final int chroma = (s * v) / 255;
|
||||
|
||||
// Beacuse hue is 0-180 rather than 0-360 use 30 not 60
|
||||
final int region = h / 30;
|
||||
final int region = (h / 30) % 6;
|
||||
|
||||
// Remainder converted from 0-30 to roughly 0-255
|
||||
final int remainder = (h - (region * 30)) * 9;
|
||||
// Remainder converted from 0-30 to 0-255
|
||||
final int remainder = (int) Math.round((h % 30) * (255 / 30.0));
|
||||
|
||||
// Value of the lowest rgb component
|
||||
final int m = v - chroma;
|
||||
|
||||
Reference in New Issue
Block a user