MathLib
Loading...
Searching...
No Matches
Conversions.hpp
Go to the documentation of this file.
1#pragma once
2
8#include <concepts>
9#include <limits>
10#include <type_traits>
11#include <cmath>
12
21namespace Color
22{
23
32template <std::floating_point T>
34{
35 assert( input.isNormalized() );
36
37#define TOHSV_METHOD 2
38
39#ifdef TOHSV_METHOD
40#if (TOHSV_METHOD == 1)
41 T cmax = max( input );
42 T cmin = min( input );
43 T delta = cmax - cmin;
44
45 T v = cmax;
46
47 T saturation;
48
49 // When delta is zero, avoid dividing by delta (0)
50 if ( Math::approximately_equal_to( cmax, cmin ) )
51 return BasicHSV<T>{ Math::BasicDegree<T>(), T{}, v};
52
53 // Saturation
54 if ( Math::approximately_equal_to( v, T{} ) )
55 saturation = T{};
56 else if ( Math::approximately_equal_to( delta, T{} ) )
57 saturation = T{};
58 else
59 saturation = delta / cmax;
60
61 T rc = ( cmax - input.red() ) / delta;
62 T gc = ( cmax - input.green() ) / delta;
63 T bc = ( cmax - input.blue() ) / delta;
64 T hue;
65
66 // Hue
67 if ( Math::approximately_equal_to( input.red(), cmax ) )
68 hue = T{0.0} + bc - gc;
69 else if ( Math::approximately_equal_to( input.green(), cmax ) )
70 hue = T{2.0} + rc - bc;
71 else
72 hue = T{4.0} + gc - rc;
73
74 // Let hue be possibly negative
75 hue = std::fmod( hue / T{6.0}, T{1.0} );
76
77 // But make hue be 0 - 360 upon return...
78 return BasicHSV<T>{ Math::BasicDegree<T>(hue * Math::BasicDegree<T>::modulus()).modulo(), saturation, v };
79#elif (TOHSV_METHOD == 2)
80 // https://web.archive.org/web/20200207113336/http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl
81 using namespace Math;
82
83 BasicVector4D<T> K{ T{0.0}, T{-1.0} / T{3.0}, T{2.0} / T{3.0}, T{-1.0} };
84 BasicVector4D<T> p = (input.g() < input.b()) ? BasicVector4D<T>{input.b(), input.g(), K.w, K.z} : BasicVector4D<T>{input.g(), input.b(), K.x, K.y};
85 BasicVector4D<T> q = (input.r() < p.x) ? BasicVector4D<T>{p.x, p.y, p.w, input.r()} : BasicVector4D<T>{input.r(), p.y, p.z, p.x};
86
87 T d = q.x - std::min(q.w, q.y);
88 T e = 1.0e-10;
89
90 return BasicHSV<T>(
91 BasicDegree<T>( std::abs(q.z + (q.w - q.y) / (T{6.0} * d + e)) ) * BasicDegree<T>::modulus(),
92 d / (q.x + e),
93 q.x
94 );
95#else
96 static_assert("Invalid value for TOHSV_METHOD");
97#endif
98#endif
99
100#undef TOHSV_METHOD
101}
102
111template <std::floating_point T>
113{
114#define TORGB_METHOD 1
115
116#ifdef TORGB_METHOD
117 // https://stackoverflow.com/questions/3018313/algorithm-to-convert-rgb-to-hsv-and-hsv-to-rgb-in-range-0-255-for-both
118#if (TORGB_METHOD == 1)
121
123
124 hh /= T{60.0};
125
126 long i = hh.value();
127 T ff = hh.value() - i;
128 T p = input_hsv.value() * (T{1.0} - input_hsv.saturation());
129 T q = input_hsv.value() * (T{1.0} - (input_hsv.saturation() * ff));
130 T t = input_hsv.value() * (T{1.0} - (input_hsv.saturation() * (T{1.0} - ff)));
131
133
134 switch ( i )
135 {
136 case 0:
138 break;
139 case 1:
141 break;
142 case 2:
144 break;
145 case 3:
147 break;
148 case 4:
150 break;
151 case 5:
152 default:
154 break;
155 }
156
157 return out;
158#elif (TORGB_METHOD == 2)
159 T h = std::fmod( T{100.0} + input_hsv.hue().value(), T{1.0} );
160 T hue_slice = T{6.0} * h;
161 T hue_slice_integer = std::floor( hue_slice );
163
164 Math::Vector3D<T> temp_rgb{ input_hsv.value() * (T{1.0} - input_hsv.saturation()),
166 input_hsv.value() * (T{1.0} - input_hsv.saturation() * (T{1.0} - hue_slice_interpolant))};
167
168 T is_odd_slice = std::fmod( hue_slice_integer, T{2.0} );
170
172 Math::Vector3D<T> scrolling_rgb_for_odd_slices{ temp_rgb.y, input_hsv.value(), temp_rgb.x };
174
176 T is_not_second_slice = Math::saturate( three_slice_selector - T{1.0}, T{0.0}, T{1.0} );
177
181 );
182#elif (TORGB_METHOD == 3)
183 Math::BasicVector4D<T> K( T{1.0}, T{2.0} / T{3.0}, T{1.0} / T{3.0}, T{3.0} );
184
186
187 Math::BasicVector3D<T> p( abs( fract(input_xxx + K.xyz()) * T{6.0} - K.www() ) );
188
189 Math::BasicVector3D<T> out( mix( K.xxx(),
190 saturate( p - K.xxx(), T{0.0}, T{1.0} ),
191 input_hsv.saturation() ) );
192
193 return { input_hsv.value() * out };
194#else
195 static_assert("Invalid method defined for TORGB_METHOD");
196#endif
197#endif
198
199#undef TORGB_METHOD
200}
201
210template <std::floating_point T>
212{
213 // https://en.wikipedia.org/wiki/HSL_and_HSV (HSV to HSL)
214 //
215 // TODO: Use algorithms from Computer Graphics: Principles and Practice
216 T lightness = input_hsv.value() * (T{1.0} - input_hsv.saturation() / T{2.0});
217 T saturation;
218
219 if ( approximately_equal_to( lightness, T{0.0} ) || approximately_equal_to( lightness, T{1.0} ) )
220 saturation = T{0};
221 else
222 saturation = (input_hsv.value() - lightness) / std::min(lightness, T{1.0} - lightness);
223
224 return BasicHSL<T>{ input_hsv.value(), saturation, lightness };
225}
226
235template <std::floating_point T>
237{
238 // https://en.wikipedia.org/wiki/HSL_and_HSV (HSV to HSL)
239 //
240 // TODO: Use algorithms from Computer Graphics: Principles and Practice
241 T value = input_hsl.lightness() + input_hsl.saturation() * std::min(input_hsl.lightness(), T{1.0} - input_hsl.lightness());
242 T saturation;
243
244 if ( approximately_equal_to( value, T{0.0} ) )
245 saturation = T{0.0};
246 else
247 saturation = T{2.0} * (T{1.0} - input_hsl.lightness() / value);
248
249 return BasicHSV<T>{ input_hsl.hue(), saturation, value };
250}
251
252}
constexpr value_type saturation() const
Definition Types.hpp:849
constexpr Math::BasicDegree< value_type > hue() const
Definition Types.hpp:848
constexpr value_type value() const
Definition Types.hpp:850
constexpr value_type red() const
Definition Types.hpp:290
constexpr value_type blue() const
Definition Types.hpp:292
constexpr value_type g() const
Definition Types.hpp:295
constexpr value_type b() const
Definition Types.hpp:296
constexpr value_type r() const
Definition Types.hpp:294
constexpr value_type green() const
Definition Types.hpp:291
constexpr bool isNormalized() const
Definition Types.hpp:335
constexpr BasicDegree< T > modulo() const
Definition Angle.hpp:363
bool approximately_equal_to(float input, float near_to, float tolerance=0.0002f)
BasicHSV< T > ToHSV(const BasicUnitRGB< T > &input)
BasicHSL< T > ToHSL(const BasicHSV< T > &input_hsv)
BasicUnitRGB< T > ToRGB(const BasicHSV< T > &input_hsv)
Definition Angle.hpp:16
constexpr Type lerp(Type input_lower_bound, Type input_upper_bound, float percentage_zero_to_one)
Definition Functions.hpp:26
constexpr const Type & saturate(const Type &value, const Type &lower_bound, const Type &upper_bound)
Definition Functions.hpp:94