Skip to content

Commit

Permalink
[wpilib] Fix precision issue in Color round-and-clamp (#6100)
Browse files Browse the repository at this point in the history
  • Loading branch information
calcmogul authored Dec 26, 2023
1 parent 7aa9ad4 commit 795d4be
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 22 deletions.
7 changes: 2 additions & 5 deletions wpilibc/src/main/native/include/frc/util/Color.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <string_view>

#include <fmt/core.h>
#include <gcem.hpp>
#include <wpi/StringExtras.h>
#include <wpi/ct_string.h>

Expand Down Expand Up @@ -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);
}
};

Expand Down
27 changes: 19 additions & 8 deletions wpilibc/src/test/native/cpp/util/ColorTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,22 @@ TEST(ColorTest, ConstructDefault) {
}

TEST(ColorTest, ConstructFromDoubles) {
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);
{
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);
}

{
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) {
Expand Down Expand Up @@ -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) {
Expand Down
5 changes: 1 addition & 4 deletions wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
*/
@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;
Expand Down Expand Up @@ -178,8 +176,7 @@ public String toHexString() {
}

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);
}

/*
Expand Down
21 changes: 16 additions & 5 deletions wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ColorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,22 @@ void testConstructDefault() {

@Test
void testConstructFromDoubles() {
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);
{
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);
}

{
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
Expand Down

0 comments on commit 795d4be

Please sign in to comment.