colors: Add HSL conversion and tune colors
When adding colors to length tuner, we depend on the window background color, which can be set by the user, resulting in an unreadable text. This uses the HSL conversion to detect which shade it should use for the coloring. Also adds test cases for round-trip HSL and HSV conversion Fixes: lp:1814530 * https://bugs.launchpad.net/kicad/+bug/1814530
This commit is contained in:
parent
f839278597
commit
7b3ef1b7ed
|
@ -2,7 +2,7 @@
|
||||||
* This program source code file is part of KICAD, a free EDA CAD application.
|
* This program source code file is part of KICAD, a free EDA CAD application.
|
||||||
*
|
*
|
||||||
* Copyright 2012 Torsten Hueter, torstenhtr <at> gmx.de
|
* Copyright 2012 Torsten Hueter, torstenhtr <at> gmx.de
|
||||||
* Copyright 2017 Kicad Developers, see AUTHORS.txt for contributors.
|
* Copyright 2017-2019 Kicad Developers, see AUTHORS.txt for contributors.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
|
@ -283,6 +283,78 @@ std::ostream &operator<<( std::ostream &aStream, COLOR4D const &aColor )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void COLOR4D::ToHSL( double& aOutHue, double& aOutSaturation, double& aOutLightness ) const
|
||||||
|
{
|
||||||
|
auto min = std::min( r, std::min( g, b ) );
|
||||||
|
auto max = std::max( r, std::max( g, b ) );
|
||||||
|
auto diff = max - min;
|
||||||
|
|
||||||
|
aOutLightness = ( max + min ) / 2.0;
|
||||||
|
|
||||||
|
if( aOutLightness >= 1.0 )
|
||||||
|
aOutSaturation = 0.0;
|
||||||
|
else
|
||||||
|
aOutSaturation = diff / ( 1.0 - std::abs( 2.0 * aOutLightness - 1.0 ) );
|
||||||
|
|
||||||
|
double hue;
|
||||||
|
|
||||||
|
if( diff <= 0.0 )
|
||||||
|
hue = 0.0;
|
||||||
|
else if( max == r )
|
||||||
|
hue = ( g - b ) / diff;
|
||||||
|
else if( max == g )
|
||||||
|
hue = ( b - r ) / diff + 2.0;
|
||||||
|
else
|
||||||
|
hue = ( r - g ) / diff + 4.0;
|
||||||
|
|
||||||
|
aOutHue = hue > 0.0 ? hue * 60.0 : hue * 60.0 + 360.0;
|
||||||
|
|
||||||
|
while( aOutHue < 0.0 )
|
||||||
|
aOutHue += 360.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void COLOR4D::FromHSL( double aInHue, double aInSaturation, double aInLightness )
|
||||||
|
{
|
||||||
|
const auto P = ( 1.0 - std::abs( 2.0 * aInLightness - 1.0 ) ) * aInSaturation;
|
||||||
|
const auto scaled_hue = aInHue / 60.0;
|
||||||
|
const auto Q = P * ( 1.0 - std::abs( std::fmod( scaled_hue, 2.0 ) - 1.0 ) );
|
||||||
|
|
||||||
|
r = g = b = aInLightness - P / 2.0;
|
||||||
|
|
||||||
|
if (scaled_hue < 1.0)
|
||||||
|
{
|
||||||
|
r += P;
|
||||||
|
g += Q;
|
||||||
|
}
|
||||||
|
else if (scaled_hue < 2.0)
|
||||||
|
{
|
||||||
|
r += Q;
|
||||||
|
g += P;
|
||||||
|
}
|
||||||
|
else if (scaled_hue < 3.0)
|
||||||
|
{
|
||||||
|
g += P;
|
||||||
|
b += Q;
|
||||||
|
}
|
||||||
|
else if (scaled_hue < 4.0)
|
||||||
|
{
|
||||||
|
g += Q;
|
||||||
|
b += P;
|
||||||
|
}
|
||||||
|
else if (scaled_hue < 5.0)
|
||||||
|
{
|
||||||
|
r += Q;
|
||||||
|
b += P;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r += P;
|
||||||
|
b += Q;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void COLOR4D::ToHSV( double& aOutHue, double& aOutSaturation, double& aOutValue, bool aAlwaysDefineHue ) const
|
void COLOR4D::ToHSV( double& aOutHue, double& aOutSaturation, double& aOutValue, bool aAlwaysDefineHue ) const
|
||||||
{
|
{
|
||||||
double min, max, delta;
|
double min, max, delta;
|
||||||
|
|
|
@ -139,6 +139,28 @@ public:
|
||||||
static EDA_COLOR_T GetNearestLegacyColor( const COLOR4D &aColor );
|
static EDA_COLOR_T GetNearestLegacyColor( const COLOR4D &aColor );
|
||||||
#endif /* WX_COMPATIBLITY */
|
#endif /* WX_COMPATIBLITY */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function ToHSL()
|
||||||
|
* Converts current color (stored in RGB) to HSL format.
|
||||||
|
*
|
||||||
|
* @param aOutHue is the conversion result for hue component, in degrees 0 ... 360.0
|
||||||
|
* @param aOutSaturation is the conversion result for saturation component (0 ... 1.0).
|
||||||
|
* @param aOutLightness is conversion result for value component (0 ... 1.0).
|
||||||
|
* @note saturation is set to 0.0 for black color if r = g = b,
|
||||||
|
*/
|
||||||
|
void ToHSL( double& aOutHue, double& aOutSaturation, double& aOutValue ) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function FromHSL()
|
||||||
|
* Changes currently used color to the one given by hue, saturation and lightness parameters.
|
||||||
|
*
|
||||||
|
* @param aInHue is hue component, in degrees (0.0 - 360.0)
|
||||||
|
* @param aInSaturation is saturation component (0.0 - 1.0)
|
||||||
|
* @param aInLightness is lightness component (0.0 - 1.0)
|
||||||
|
*/
|
||||||
|
void FromHSL( double aInHue, double aInSaturation, double aInLightness );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Brighten
|
* Function Brighten
|
||||||
* Makes the color brighter by a given factor.
|
* Makes the color brighter by a given factor.
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014-2015 CERN
|
* Copyright (C) 2014-2015 CERN
|
||||||
* Copyright (C) 2016 KiCad Developers, see AUTHORS.txt for contributors.
|
* Copyright (C) 2016-2019 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
@ -33,16 +33,33 @@ void PNS_TUNE_STATUS_POPUP::UpdateStatus( PNS::ROUTER* aRouter )
|
||||||
|
|
||||||
SetText( placer->TuningInfo( m_frame->GetUserUnits() ) );
|
SetText( placer->TuningInfo( m_frame->GetUserUnits() ) );
|
||||||
|
|
||||||
|
// Determine the background color first and choose a contrasting value
|
||||||
|
COLOR4D bg( m_panel->GetBackgroundColour() );
|
||||||
|
double h, s, l;
|
||||||
|
bg.ToHSL( h, s, l );
|
||||||
|
|
||||||
switch( placer->TuningStatus() )
|
switch( placer->TuningStatus() )
|
||||||
{
|
{
|
||||||
case PNS::MEANDER_PLACER::TUNED:
|
case PNS::MEANDER_PLACER::TUNED:
|
||||||
SetTextColor( wxColour( 0, 255, 0 ) );
|
if( l < 0.5 )
|
||||||
|
SetTextColor( wxColor( 0, 255, 0 ) );
|
||||||
|
else
|
||||||
|
SetTextColor( wxColor( 0, 128, 0 ) );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case PNS::MEANDER_PLACER::TOO_SHORT:
|
case PNS::MEANDER_PLACER::TOO_SHORT:
|
||||||
SetTextColor( wxColour( 255, 128, 128 ) );
|
if( l < 0.5 )
|
||||||
|
SetTextColor( wxColor( 255, 128, 128 ) );
|
||||||
|
else
|
||||||
|
SetTextColor( wxColor( 128, 64, 64 ) );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case PNS::MEANDER_PLACER::TOO_LONG:
|
case PNS::MEANDER_PLACER::TOO_LONG:
|
||||||
SetTextColor( wxColour( 128, 128, 255 ) );
|
if( l < 0.5 )
|
||||||
|
SetTextColor( wxColor( 24, 24, 255 ) );
|
||||||
|
else
|
||||||
|
SetTextColor( wxColor( 19, 19, 195 ) );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 KiCad Developers, see CHANGELOG.TXT for contributors.
|
* Copyright (C) 2018-2019 KiCad Developers, see CHANGELOG.TXT for contributors.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -217,16 +217,70 @@ struct FROM_HSV_TO_HEX_CASE
|
||||||
BOOST_AUTO_TEST_CASE( FromHsv )
|
BOOST_AUTO_TEST_CASE( FromHsv )
|
||||||
{
|
{
|
||||||
static const std::vector<FROM_HSV_TO_HEX_CASE> cases = {
|
static const std::vector<FROM_HSV_TO_HEX_CASE> cases = {
|
||||||
{ 90.0, 0.5, 0.5, 96, 128, 64 },
|
{ 10, 0.71, 0.66, 168, 69, 49 },
|
||||||
|
{ 15, 0.96, 0.34, 87, 24, 3 },
|
||||||
|
{ 120, 0.50, 0.50, 64, 128, 64 },
|
||||||
|
{ 190, 0.32, 0.97, 168, 234, 247 },
|
||||||
|
{ 240, 0.15, 0.75, 163, 163, 191 },
|
||||||
|
{ 240, 0.90, 0.75, 19, 19, 191 },
|
||||||
|
{ 310, 0.71, 0.66, 168, 49, 148 },
|
||||||
|
{ 331, 0.15, 0.85, 217, 184, 200 },
|
||||||
};
|
};
|
||||||
|
|
||||||
for( const auto& c : cases )
|
for( const auto& c : cases )
|
||||||
{
|
{
|
||||||
auto col = COLOR4D{};
|
auto col = COLOR4D{};
|
||||||
col.FromHSV( c.h, c.s, c.v );
|
col.FromHSV( c.h, c.s, c.v );
|
||||||
|
double new_h, new_s, new_v;
|
||||||
|
col.ToHSV( new_h, new_s, new_v );
|
||||||
const unsigned char alpha = 0xFF;
|
const unsigned char alpha = 0xFF;
|
||||||
|
|
||||||
BOOST_CHECK_PREDICATE( pred_colour_is_near_hex, ( col )( c.r )( c.g )( c.b )( alpha ) );
|
BOOST_CHECK_PREDICATE( pred_colour_is_near_hex, ( col )( c.r )( c.g )( c.b )( alpha ) );
|
||||||
|
BOOST_CHECK_CLOSE( c.h, new_h, 0.0001 );
|
||||||
|
BOOST_CHECK_CLOSE( c.s, new_s, 0.0001 );
|
||||||
|
BOOST_CHECK_CLOSE( c.v, new_v, 0.0001 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FROM_HSL_TO_HEX_CASE
|
||||||
|
{
|
||||||
|
double h;
|
||||||
|
double s;
|
||||||
|
double l;
|
||||||
|
unsigned char r;
|
||||||
|
unsigned char g;
|
||||||
|
unsigned char b;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check FromHSL
|
||||||
|
*/
|
||||||
|
BOOST_AUTO_TEST_CASE( FromHsl )
|
||||||
|
{
|
||||||
|
static const std::vector<FROM_HSL_TO_HEX_CASE> cases = {
|
||||||
|
{ 10, 0.71, 0.66, 230, 127, 107 },
|
||||||
|
{ 15, 0.96, 0.34, 170, 45, 3 },
|
||||||
|
{ 120, 0.5, 0.5, 64, 191, 64 },
|
||||||
|
{ 190, 0.32, 0.97, 245, 249, 250 },
|
||||||
|
{ 240, 0.15, 0.75, 182, 182, 201 },
|
||||||
|
{ 240, 0.90, 0.75, 134, 134, 249 },
|
||||||
|
{ 310, 0.71, 0.66, 230, 107, 209 },
|
||||||
|
{ 331, 0.15, 0.85, 222, 211, 217 },
|
||||||
|
};
|
||||||
|
|
||||||
|
for( const auto& c : cases )
|
||||||
|
{
|
||||||
|
auto col = COLOR4D{};
|
||||||
|
col.FromHSL( c.h, c.s, c.l );
|
||||||
|
double new_h, new_s, new_l;
|
||||||
|
col.ToHSL( new_h, new_s, new_l );
|
||||||
|
const unsigned char alpha = 0xFF;
|
||||||
|
|
||||||
|
BOOST_CHECK_PREDICATE( pred_colour_is_near_hex, ( col )( c.r )( c.g )( c.b )( alpha ) );
|
||||||
|
BOOST_CHECK_CLOSE( c.h, new_h, 0.0001 );
|
||||||
|
BOOST_CHECK_CLOSE( c.s, new_s, 0.0001 );
|
||||||
|
BOOST_CHECK_CLOSE( c.l, new_l, 0.0001 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue