From 27883caa08983f7c963cad8f185e3e45fc1432eb Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 9 Dec 2021 14:16:17 +0100 Subject: [PATCH] Follow-up https://github.com/prusa3d/PrusaSlicer/commit/b3074ad2cce49ab9ca929faf42ad5721f1b76849 Change random values of the S and V in HSV colors. To avoid generation of the extremely light or dark colors we use now generated values from the range [0.65; 0.1] --- src/slic3r/GUI/DoubleSlider.cpp | 22 +- src/slic3r/GUI/DoubleSlider.hpp | 2 + src/slic3r/GUI/DoubleSlider_Utils.hpp | 310 ++++++++++++++------------ 3 files changed, 176 insertions(+), 158 deletions(-) diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp index 5b0cf430c..3d914d5b6 100644 --- a/src/slic3r/GUI/DoubleSlider.cpp +++ b/src/slic3r/GUI/DoubleSlider.cpp @@ -1,6 +1,5 @@ #include "libslic3r/libslic3r.h" #include "DoubleSlider.hpp" -#include "DoubleSlider_Utils.hpp" #include "libslic3r/GCode.hpp" #include "GUI.hpp" #include "GUI_App.hpp" @@ -27,7 +26,6 @@ #include #include #include -#include #include "Field.hpp" #include "format.hpp" #include "NotificationManager.hpp" @@ -2562,7 +2560,7 @@ std::string TickCodeInfo::get_color_for_tick(TickCode tick, Type type, const int if (mode == SingleExtruder && type == ColorChange && m_use_default_colors) { #if 1 if (ticks.empty()) - return get_opposite_color((*m_colors)[0]); + return color_generator.get_opposite_color((*m_colors)[0]); auto before_tick_it = std::lower_bound(ticks.begin(), ticks.end(), tick); if (before_tick_it == ticks.end()) @@ -2571,24 +2569,24 @@ std::string TickCodeInfo::get_color_for_tick(TickCode tick, Type type, const int if (--before_tick_it; before_tick_it->type == ColorChange) break; if (before_tick_it->type == ColorChange) - return get_opposite_color(before_tick_it->color); - return get_opposite_color((*m_colors)[0]); + return color_generator.get_opposite_color(before_tick_it->color); + return color_generator.get_opposite_color((*m_colors)[0]); } if (before_tick_it == ticks.begin()) { const std::string& frst_color = (*m_colors)[0]; if (before_tick_it->type == ColorChange) - return get_opposite_color(frst_color, before_tick_it->color); + return color_generator.get_opposite_color(frst_color, before_tick_it->color); auto next_tick_it = before_tick_it; while (next_tick_it != ticks.end()) if (++next_tick_it; next_tick_it->type == ColorChange) break; if (next_tick_it->type == ColorChange) - return get_opposite_color(frst_color, next_tick_it->color); + return color_generator.get_opposite_color(frst_color, next_tick_it->color); - return get_opposite_color(frst_color); + return color_generator.get_opposite_color(frst_color); } std::string frst_color = ""; @@ -2609,13 +2607,13 @@ std::string TickCodeInfo::get_color_for_tick(TickCode tick, Type type, const int if (before_tick_it->type == ColorChange) { if (frst_color.empty()) - return get_opposite_color(before_tick_it->color); - return get_opposite_color(before_tick_it->color, frst_color); + return color_generator.get_opposite_color(before_tick_it->color); + return color_generator.get_opposite_color(before_tick_it->color, frst_color); } if (frst_color.empty()) - return get_opposite_color((*m_colors)[0]); - return get_opposite_color((*m_colors)[0], frst_color); + return color_generator.get_opposite_color((*m_colors)[0]); + return color_generator.get_opposite_color((*m_colors)[0], frst_color); #else const std::vector& colors = ColorPrintColors::get(); if (ticks.empty()) diff --git a/src/slic3r/GUI/DoubleSlider.hpp b/src/slic3r/GUI/DoubleSlider.hpp index e0f713d87..23275cf2a 100644 --- a/src/slic3r/GUI/DoubleSlider.hpp +++ b/src/slic3r/GUI/DoubleSlider.hpp @@ -3,6 +3,7 @@ #include "libslic3r/CustomGCode.hpp" #include "wxExtensions.hpp" +#include "DoubleSlider_Utils.hpp" #include #include @@ -118,6 +119,7 @@ class TickCodeInfo // int m_default_color_idx = 0; std::vector* m_colors {nullptr}; + ColorGenerator color_generator; std::string get_color_for_tick(TickCode tick, Type type, const int extruder); diff --git a/src/slic3r/GUI/DoubleSlider_Utils.hpp b/src/slic3r/GUI/DoubleSlider_Utils.hpp index 704eb5a87..b5955f2fc 100644 --- a/src/slic3r/GUI/DoubleSlider_Utils.hpp +++ b/src/slic3r/GUI/DoubleSlider_Utils.hpp @@ -1,173 +1,191 @@ #include +#include + #include "wx/colour.h" -// next code is borrowed from https://stackoverflow.com/questions/3018313/algorithm-to-convert-rgb-to-hsv-and-hsv-to-rgb-in-range-0-255-for-both - -typedef struct { - double r; // a fraction between 0 and 1 - double g; // a fraction between 0 and 1 - double b; // a fraction between 0 and 1 -} rgb; - -typedef struct { - double h; // angle in degrees - double s; // a fraction between 0 and 1 - double v; // a fraction between 0 and 1 -} hsv; - -static hsv rgb2hsv(rgb in); -static rgb hsv2rgb(hsv in); - -hsv rgb2hsv(rgb in) +class ColorGenerator { - hsv out; - double min, max, delta; + // Some of next code is borrowed from https://stackoverflow.com/questions/3018313/algorithm-to-convert-rgb-to-hsv-and-hsv-to-rgb-in-range-0-255-for-both + typedef struct { + double r; // a fraction between 0 and 1 + double g; // a fraction between 0 and 1 + double b; // a fraction between 0 and 1 + } rgb; - min = in.r < in.g ? in.r : in.g; - min = min < in.b ? min : in.b; + typedef struct { + double h; // angle in degrees + double s; // a fraction between 0 and 1 + double v; // a fraction between 0 and 1 + } hsv; - max = in.r > in.g ? in.r : in.g; - max = max > in.b ? max : in.b; + //static hsv rgb2hsv(rgb in); + //static rgb hsv2rgb(hsv in); - out.v = max; // v - delta = max - min; - if (delta < 0.00001) + hsv rgb2hsv(rgb in) { - out.s = 0; - out.h = 0; // undefined, maybe nan? + hsv out; + double min, max, delta; + + min = in.r < in.g ? in.r : in.g; + min = min < in.b ? min : in.b; + + max = in.r > in.g ? in.r : in.g; + max = max > in.b ? max : in.b; + + out.v = max; // v + delta = max - min; + if (delta < 0.00001) + { + out.s = 0; + out.h = 0; // undefined, maybe nan? + return out; + } + if (max > 0.0) { // NOTE: if Max is == 0, this divide would cause a crash + out.s = (delta / max); // s + } + else { + // if max is 0, then r = g = b = 0 + // s = 0, h is undefined + out.s = 0.0; + out.h = NAN; // its now undefined + return out; + } + if (in.r >= max) // > is bogus, just keeps compilor happy + out.h = (in.g - in.b) / delta; // between yellow & magenta + else + if (in.g >= max) + out.h = 2.0 + (in.b - in.r) / delta; // between cyan & yellow + else + out.h = 4.0 + (in.r - in.g) / delta; // between magenta & cyan + + out.h *= 60.0; // degrees + + if (out.h < 0.0) + out.h += 360.0; + return out; } - if( max > 0.0 ) { // NOTE: if Max is == 0, this divide would cause a crash - out.s = (delta / max); // s - } else { - // if max is 0, then r = g = b = 0 - // s = 0, h is undefined - out.s = 0.0; - out.h = NAN; // its now undefined + + hsv rgb2hsv(const std::string& str_clr_in) + { + wxColour clr(str_clr_in); + rgb in = { clr.Red() / 255.0, clr.Green() / 255.0, clr.Blue() / 255.0 }; + return rgb2hsv(in); + } + + + rgb hsv2rgb(hsv in) + { + double hh, p, q, t, ff; + long i; + rgb out; + + if (in.s <= 0.0) { // < is bogus, just shuts up warnings + out.r = in.v; + out.g = in.v; + out.b = in.v; + return out; + } + hh = in.h; + if (hh >= 360.0) hh -= 360.0;//hh = 0.0; + hh /= 60.0; + i = (long)hh; + ff = hh - i; + p = in.v * (1.0 - in.s); + q = in.v * (1.0 - (in.s * ff)); + t = in.v * (1.0 - (in.s * (1.0 - ff))); + + switch (i) { + case 0: + out.r = in.v; + out.g = t; + out.b = p; + break; + case 1: + out.r = q; + out.g = in.v; + out.b = p; + break; + case 2: + out.r = p; + out.g = in.v; + out.b = t; + break; + + case 3: + out.r = p; + out.g = q; + out.b = in.v; + break; + case 4: + out.r = t; + out.g = p; + out.b = in.v; + break; + case 5: + default: + out.r = in.v; + out.g = p; + out.b = q; + break; + } return out; } - if( in.r >= max ) // > is bogus, just keeps compilor happy - out.h = ( in.g - in.b ) / delta; // between yellow & magenta - else - if( in.g >= max ) - out.h = 2.0 + ( in.b - in.r ) / delta; // between cyan & yellow - else - out.h = 4.0 + ( in.r - in.g ) / delta; // between magenta & cyan - out.h *= 60.0; // degrees + std::random_device rd; - if( out.h < 0.0 ) - out.h += 360.0; +public: - return out; -} + ColorGenerator() {} + ~ColorGenerator() {} -hsv rgb2hsv(const std::string& str_clr_in) -{ - wxColour clr(str_clr_in); - rgb in = { clr.Red() / 255.0, clr.Green() / 255.0, clr.Blue() / 255.0 }; - return rgb2hsv(in); -} + double rand_val() + { + std::mt19937 rand_generator(rd()); - -rgb hsv2rgb(hsv in) -{ - double hh, p, q, t, ff; - long i; - rgb out; - - if(in.s <= 0.0) { // < is bogus, just shuts up warnings - out.r = in.v; - out.g = in.v; - out.b = in.v; - return out; + // this value will be used for Saturation and Value + // to avoid extremely light/dark colors, take this value from range [0.65; 1.0] + std::uniform_real_distribution distrib(0.65, 1.0); + return distrib(rand_generator); } - hh = in.h; - if (hh >= 360.0) hh -= 360.0;//hh = 0.0; - hh /= 60.0; - i = (long)hh; - ff = hh - i; - p = in.v * (1.0 - in.s); - q = in.v * (1.0 - (in.s * ff)); - t = in.v * (1.0 - (in.s * (1.0 - ff))); - switch(i) { - case 0: - out.r = in.v; - out.g = t; - out.b = p; - break; - case 1: - out.r = q; - out.g = in.v; - out.b = p; - break; - case 2: - out.r = p; - out.g = in.v; - out.b = t; - break; - case 3: - out.r = p; - out.g = q; - out.b = in.v; - break; - case 4: - out.r = t; - out.g = p; - out.b = in.v; - break; - case 5: - default: - out.r = in.v; - out.g = p; - out.b = q; - break; + std::string get_opposite_color(const std::string& color) + { + std::string opp_color = ""; + + hsv hsv_clr = rgb2hsv(color); + hsv_clr.h += 65; // 65 instead 60 to avoid circle values + hsv_clr.s = rand_val(); + hsv_clr.v = rand_val(); + + rgb rgb_opp_color = hsv2rgb(hsv_clr); + + wxString clr_str = wxString::Format(wxT("#%02X%02X%02X"), (unsigned char)(rgb_opp_color.r * 255), (unsigned char)(rgb_opp_color.g * 255), (unsigned char)(rgb_opp_color.b * 255)); + opp_color = clr_str.ToStdString(); + + return opp_color; } - return out; -} -double rand_val() -{ - return 0.1 * (10 - rand() % 8); -} + std::string get_opposite_color(const std::string& color_frst, const std::string& color_scnd) + { + std::string opp_color = ""; -std::string get_opposite_color(const std::string& color) -{ - std::string opp_color = ""; + hsv hsv_frst = rgb2hsv(color_frst); + hsv hsv_scnd = rgb2hsv(color_scnd); - hsv hsv_clr = rgb2hsv(color); - hsv_clr.h += 65; // 65 instead 60 to avoid circle values - hsv_clr.s = rand_val(); - hsv_clr.v = rand_val(); + double delta_h = fabs(hsv_frst.h - hsv_scnd.h); + double start_h = delta_h > 180 ? std::min(hsv_scnd.h, hsv_frst.h) : std::max(hsv_scnd.h, hsv_frst.h); + start_h += 5; // to avoid circle change of colors for 120 deg + if (delta_h < 180) + delta_h = 360 - delta_h; - rgb rgb_opp_color = hsv2rgb(hsv_clr); + hsv hsv_opp = hsv{ start_h + 0.5 * delta_h, rand_val(), rand_val() }; + rgb rgb_opp_color = hsv2rgb(hsv_opp); - wxString clr_str = wxString::Format(wxT("#%02X%02X%02X"), (unsigned char)(rgb_opp_color.r * 255), (unsigned char)(rgb_opp_color.g * 255), (unsigned char)(rgb_opp_color.b * 255)); - opp_color = clr_str.ToStdString(); + wxString clr_str = wxString::Format(wxT("#%02X%02X%02X"), (unsigned char)(rgb_opp_color.r * 255), (unsigned char)(rgb_opp_color.g * 255), (unsigned char)(rgb_opp_color.b * 255)); + opp_color = clr_str.ToStdString(); - return opp_color; -} - -std::string get_opposite_color(const std::string& color_frst, const std::string& color_scnd) -{ - std::string opp_color = ""; - - hsv hsv_frst = rgb2hsv(color_frst); - hsv hsv_scnd = rgb2hsv(color_scnd); - - double delta_h = fabs(hsv_frst.h - hsv_scnd.h); - double start_h = delta_h > 180 ? std::min(hsv_scnd.h, hsv_frst.h) : std::max(hsv_scnd.h, hsv_frst.h); - start_h += 5; // to avoid circle change of colors for 120 deg - if (delta_h < 180) - delta_h = 360 - delta_h; - - hsv hsv_opp = hsv{ start_h + 0.5 * delta_h, rand_val(), rand_val() }; - rgb rgb_opp_color = hsv2rgb(hsv_opp); - - wxString clr_str = wxString::Format(wxT("#%02X%02X%02X"), (unsigned char)(rgb_opp_color.r * 255), (unsigned char)(rgb_opp_color.g * 255), (unsigned char)(rgb_opp_color.b * 255)); - opp_color = clr_str.ToStdString(); - - return opp_color; -} \ No newline at end of file + return opp_color; + } +}; \ No newline at end of file