77
88#include < fmt/format.h>
99
10-
11- #include < iostream>
12-
1310[[nodiscard]] Color HSVColor::to_rgb_color () const {
1411 return Color{ *this };
1512}
1613
1714[[nodiscard]] std::string HSVColor::to_string () const {
18- return to_rgb_color ().to_string (Color::SerializeMode::HSV);
15+ return fmt::format (" hsva({:.2f}, {:.5f}, {:.5f}, {:#2x})" , h, s, v, a);
16+ }
17+
18+
19+ std::ostream& HSVColor::operator <<(std::ostream& os) const {
20+ os << to_string ();
21+ return os;
1922}
2023
24+
2125helper::expected<Color, std::string> Color::from_string (const std::string& value) {
2226
2327 const auto result = detail::get_color_from_string (value);
@@ -35,7 +39,8 @@ namespace {
3539 if (value < static_cast <T>(0.0 )) {
3640 // see https://math.stackexchange.com/questions/2179579/how-can-i-find-a-mod-with-negative-number
3741 T result = value;
38- while (result < 0 ) {
42+ // TODO: maybe this is possible faster?
43+ while (result < static_cast <T>(0.0 )) {
3944 result += divisor;
4045 }
4146 return result;
@@ -47,34 +52,37 @@ namespace {
4752// taken carefully from https://math.stackexchange.com/questions/556341/rgb-to-hsv-color-conversion-algorithm
4853// and modified and sped up, by optimizing it manually
4954[[nodiscard]] HSVColor Color::to_hsv_color () const {
50- constexpr auto max_d = static_cast <double >(0xFF );
51- const double r_d = static_cast <double >(r) / max_d;
52- const double g_d = static_cast <double >(g) / max_d;
53- const double b_d = static_cast <double >(b) / max_d;
55+ using FloatType = double ; // for more precision use "long double" here
56+ constexpr auto max_d = static_cast <FloatType>(0xFF );
57+ const auto r_d = static_cast <FloatType>(r) / max_d;
58+ const auto g_d = static_cast <FloatType>(g) / max_d;
59+ const auto b_d = static_cast <FloatType>(b) / max_d;
5460
55- const double min = std::min ({ r_d, g_d, b_d });
56- const double max = std::max ({ r_d, g_d, b_d });
57- const double delta = max - min;
61+ const auto min = std::min<FloatType> ({ r_d, g_d, b_d });
62+ const auto max = std::max<FloatType> ({ r_d, g_d, b_d });
63+ const auto delta = max - min;
5864
59- double h_temp = 0.0 ;
65+ FloatType h_temp = 0.0 ;
6066 if (min == max) {
6167 h_temp = 0.0 ;
62- } else if (r >= max) { // > is bogus, just keeps compiler happy
63- h_temp = (g - b) / delta; // between yellow & magenta
64- } else if (g >= max) {
65- h_temp = 2.0 + ((b - r) / delta); // between cyan & yellow
68+ } else if (r_d >= max) { // > is bogus, just keeps compiler happy
69+ h_temp = fmod_always_positive<FloatType>(
70+ (g_d - b_d) / delta, static_cast <FloatType>(6.0 )
71+ ); // between yellow & magenta
72+ } else if (g_d >= max) {
73+ h_temp = 2.0 + ((b_d - r_d) / delta); // between cyan & yellow
6674 } else {
67- h_temp = 4.0 + ((r - g ) / delta); // between magenta & cyan
75+ h_temp = 4.0 + ((r_d - g_d ) / delta); // between magenta & cyan
6876 }
6977
7078 // use custom fmod, that always result in a positive value
71- const double h = fmod_always_positive ( h_temp, 6.0 ) * 60.0 ; // degrees
79+ const FloatType h = h_temp * static_cast <FloatType>( 60.0 ) ; // degrees
7280
73- const double s = max == 0.0 ? 0.0 : delta / max;
81+ const FloatType s = max == static_cast <FloatType>( 0.0 ) ? static_cast <FloatType>( 0.0 ) : delta / max;
7482
7583 // v = max
7684
77- return HSVColor{ h, s, max, a };
85+ return HSVColor{ static_cast < double >(h), static_cast < double >(s), static_cast < double >( max) , a };
7886}
7987
8088// Note: this output formats are all deserializable by the from_string method!
@@ -89,7 +97,7 @@ namespace {
8997 }
9098 case SerializeMode::HSV: {
9199 const auto color = to_hsv_color ();
92- return fmt::format ( " hsva({:.2f}, {:.5f}, {:.5f}, {:#2x}) " , color.h , color. s , color. v , color. a );
100+ return color.to_string ( );
93101 }
94102 default :
95103 utils::unreachable ();
0 commit comments