mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-01 02:41:48 +00:00
[wpilib] Fix precision issue in Color round-and-clamp (#6100)
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
#include <string_view>
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <gcem.hpp>
|
||||
#include <wpi/StringExtras.h>
|
||||
#include <wpi/ct_string.h>
|
||||
|
||||
@@ -868,12 +869,8 @@ class Color {
|
||||
double blue = 0.0;
|
||||
|
||||
private:
|
||||
static constexpr double kPrecision = 1.0 / (1 << 12);
|
||||
|
||||
static constexpr double roundAndClamp(double value) {
|
||||
const auto rounded =
|
||||
(static_cast<int>(value / kPrecision) + 0.5) * kPrecision;
|
||||
return std::clamp(rounded, 0.0, 1.0);
|
||||
return std::clamp(gcem::ceil(value * (1 << 12)) / (1 << 12), 0.0, 1.0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -17,11 +17,22 @@ TEST(ColorTest, ConstructDefault) {
|
||||
}
|
||||
|
||||
TEST(ColorTest, ConstructFromDoubles) {
|
||||
constexpr frc::Color color{1.0, 0.5, 0.25};
|
||||
{
|
||||
constexpr frc::Color color{1.0, 0.5, 0.25};
|
||||
|
||||
EXPECT_NEAR(1.0, color.red, 1e-2);
|
||||
EXPECT_NEAR(0.5, color.green, 1e-2);
|
||||
EXPECT_NEAR(0.25, color.blue, 1e-2);
|
||||
EXPECT_NEAR(1.0, color.red, 1e-2);
|
||||
EXPECT_NEAR(0.5, color.green, 1e-2);
|
||||
EXPECT_NEAR(0.25, color.blue, 1e-2);
|
||||
}
|
||||
|
||||
{
|
||||
constexpr frc::Color color{1.0, 0.0, 0.0};
|
||||
|
||||
// Check for exact match to ensure round-and-clamp is correct
|
||||
EXPECT_EQ(1.0, color.red);
|
||||
EXPECT_EQ(0.0, color.green);
|
||||
EXPECT_EQ(0.0, color.blue);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ColorTest, ConstructFromInts) {
|
||||
@@ -52,9 +63,9 @@ TEST(ColorTest, ConstructFromHexString) {
|
||||
TEST(ColorTest, FromHSV) {
|
||||
constexpr frc::Color color = frc::Color::FromHSV(90, 128, 64);
|
||||
|
||||
EXPECT_DOUBLE_EQ(0.1256103515625, color.red);
|
||||
EXPECT_DOUBLE_EQ(0.2510986328125, color.green);
|
||||
EXPECT_DOUBLE_EQ(0.2510986328125, color.blue);
|
||||
EXPECT_DOUBLE_EQ(0.125732421875, color.red);
|
||||
EXPECT_DOUBLE_EQ(0.251220703125, color.green);
|
||||
EXPECT_DOUBLE_EQ(0.251220703125, color.blue);
|
||||
}
|
||||
|
||||
TEST(ColorTest, ToHexString) {
|
||||
|
||||
@@ -14,8 +14,6 @@ import java.util.Objects;
|
||||
*/
|
||||
@SuppressWarnings("MemberName")
|
||||
public class Color {
|
||||
private static final double kPrecision = Math.pow(2, -12);
|
||||
|
||||
public final double red;
|
||||
public final double green;
|
||||
public final double blue;
|
||||
@@ -178,8 +176,7 @@ public class Color {
|
||||
}
|
||||
|
||||
private static double roundAndClamp(double value) {
|
||||
final var rounded = Math.round((value + kPrecision / 2) / kPrecision) * kPrecision;
|
||||
return MathUtil.clamp(rounded, 0.0, 1.0);
|
||||
return MathUtil.clamp(Math.ceil(value * (1 << 12)) / (1 << 12), 0.0, 1.0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -21,11 +21,22 @@ class ColorTest {
|
||||
|
||||
@Test
|
||||
void testConstructFromDoubles() {
|
||||
var color = new Color(1.0, 0.5, 0.25);
|
||||
{
|
||||
var color = new Color(1.0, 0.5, 0.25);
|
||||
|
||||
assertEquals(1.0, color.red, 1e-2);
|
||||
assertEquals(0.5, color.green, 1e-2);
|
||||
assertEquals(0.25, color.blue, 1e-2);
|
||||
assertEquals(1.0, color.red, 1e-2);
|
||||
assertEquals(0.5, color.green, 1e-2);
|
||||
assertEquals(0.25, color.blue, 1e-2);
|
||||
}
|
||||
|
||||
{
|
||||
var color = new Color(1.0, 0.0, 0.0);
|
||||
|
||||
// Check for exact match to ensure round-and-clamp is correct
|
||||
assertEquals(1.0, color.red);
|
||||
assertEquals(0.0, color.green);
|
||||
assertEquals(0.0, color.blue);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user