diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 9a5252949..f0c2338e9 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -189,6 +189,7 @@ set(SLIC3R_GUI_SOURCES GUI/Mouse3DController.hpp GUI/DoubleSlider.cpp GUI/DoubleSlider.hpp + GUI/DoubleSlider_Utils.hpp GUI/Notebook.cpp GUI/Notebook.hpp GUI/ObjectDataViewModel.cpp diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp index fc47484b5..363dadf1e 100644 --- a/src/slic3r/GUI/DoubleSlider.cpp +++ b/src/slic3r/GUI/DoubleSlider.cpp @@ -1,5 +1,6 @@ #include "libslic3r/libslic3r.h" #include "DoubleSlider.hpp" +#include "DoubleSlider_Utils.hpp" #include "libslic3r/GCode.hpp" #include "GUI.hpp" #include "GUI_App.hpp" @@ -2546,12 +2547,70 @@ bool Control::check_ticks_changed_event(Type type) std::string TickCodeInfo::get_color_for_tick(TickCode tick, Type type, const int extruder) { if (mode == SingleExtruder && type == ColorChange && m_use_default_colors) { +#if 1 + if (ticks.empty()) + return get_opposite_color((*m_colors)[0]); + + auto before_tick_it = std::lower_bound(ticks.begin(), ticks.end(), tick); + if (before_tick_it == ticks.end()) + { + while (before_tick_it != ticks.begin()) + 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]); + } + + 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); + + 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 get_opposite_color(frst_color); + } + + std::string frst_color = ""; + if (before_tick_it->type == ColorChange) + frst_color = before_tick_it->color; + else { + auto next_tick_it = before_tick_it; + while (next_tick_it != ticks.end()) + if (++next_tick_it; next_tick_it->type == ColorChange) { + frst_color = next_tick_it->color; + break; + } + } + + while (before_tick_it != ticks.begin()) + if (--before_tick_it; before_tick_it->type == ColorChange) + break; + + 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); + } + + if (frst_color.empty()) + return get_opposite_color((*m_colors)[0]); + return get_opposite_color((*m_colors)[0], frst_color); +#else const std::vector& colors = ColorPrintColors::get(); if (ticks.empty()) return colors[0]; m_default_color_idx++; return colors[m_default_color_idx % colors.size()]; +#endif } std::string color = (*m_colors)[extruder - 1]; diff --git a/src/slic3r/GUI/DoubleSlider_Utils.hpp b/src/slic3r/GUI/DoubleSlider_Utils.hpp new file mode 100644 index 000000000..1228b9e3d --- /dev/null +++ b/src/slic3r/GUI/DoubleSlider_Utils.hpp @@ -0,0 +1,172 @@ +#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) +{ + 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; +} + +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; +} + +double rand_val() +{ + return 0.1 * (10 - rand() % 8); +} + +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; +} + +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