KiCad PCB EDA Suite
color4d.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KICAD, a free EDA CAD application.
3  *
4  * Copyright 2012 Torsten Hueter, torstenhtr <at> gmx.de
5  * Copyright 2017-2019 Kicad Developers, see AUTHORS.txt for contributors.
6  *
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
26 #include <map>
27 #include <nlohmann/json.hpp>
28 #include <gal/color4d.h>
29 
30 using namespace KIGFX;
31 
33 {
34  if( aColor <= UNSPECIFIED_COLOR || aColor >= NBCOLORS )
35  {
36  *this = COLOR4D::UNSPECIFIED;
37  return;
38  }
39 
40  r = g_ColorRefs[aColor].m_Red / 255.0;
41  g = g_ColorRefs[aColor].m_Green / 255.0;
42  b = g_ColorRefs[aColor].m_Blue / 255.0;
43  a = 1.0;
44 }
45 
46 
47 #ifdef WX_COMPATIBILITY
48  COLOR4D::COLOR4D( const wxColour& aColor )
49  {
50  r = aColor.Red() / 255.0;
51  g = aColor.Green() / 255.0;
52  b = aColor.Blue() / 255.0;
53  a = aColor.Alpha() / 255.0;
54  }
55 
56 
57  bool COLOR4D::SetFromWxString( const wxString& aColorString )
58  {
59  wxColour c;
60 
61  if( c.Set( aColorString ) )
62  {
63  r = c.Red() / 255.0;
64  g = c.Green() / 255.0;
65  b = c.Blue() / 255.0;
66  a = c.Alpha() / 255.0;
67 
68  return true;
69  }
70 
71  return false;
72  }
73 
74 
75  wxString COLOR4D::ToWxString( long flags ) const
76  {
77  wxColour c = ToColour();
78  return c.GetAsString( flags );
79  }
80 
81 
82  wxColour COLOR4D::ToColour() const
83  {
84  using CHAN_T = wxColourBase::ChannelType;
85 
86  const wxColour colour(
87  static_cast<CHAN_T>( r * 255 + 0.5 ),
88  static_cast<CHAN_T>( g * 255 + 0.5 ),
89  static_cast<CHAN_T>( b * 255 + 0.5 ),
90  static_cast<CHAN_T>( a * 255 + 0.5 )
91  );
92  return colour;
93  }
94 
95 
96  COLOR4D COLOR4D::LegacyMix( COLOR4D aColor ) const
97  {
98  COLOR4D candidate;
99 
100  // Blend the two colors (i.e. OR the RGB values)
101  candidate.r = ( (unsigned)( 255.0 * r ) | (unsigned)( 255.0 * aColor.r ) ) / 255.0,
102  candidate.g = ( (unsigned)( 255.0 * g ) | (unsigned)( 255.0 * aColor.g ) ) / 255.0,
103  candidate.b = ( (unsigned)( 255.0 * b ) | (unsigned)( 255.0 * aColor.b ) ) / 255.0,
104 
105  // the alpha channel can be reinitialized
106  // but what is the best value?
107  candidate.a = ( aColor.a + a ) / 2;
108 
109  return candidate;
110  }
111 
112 
113  unsigned int COLOR4D::ToU32() const
114  {
115  return ToColour().GetRGB();
116  }
117 
118 
119  void COLOR4D::FromU32( unsigned int aPackedColor )
120  {
121  wxColour c;
122  c.SetRGB( aPackedColor );
123  r = c.Red() / 255.0;
124  g = c.Green() / 255.0;
125  b = c.Blue() / 255.0;
126  a = c.Alpha() / 255.0;
127  }
128 
129 #endif
130 
131 namespace KIGFX {
132 
133 const bool operator==( const COLOR4D& lhs, const COLOR4D& rhs )
134 {
135  return lhs.a == rhs.a && lhs.r == rhs.r && lhs.g == rhs.g && lhs.b == rhs.b;
136 }
137 
138 
139 const bool operator!=( const COLOR4D& lhs, const COLOR4D& rhs )
140 {
141  return !( lhs == rhs );
142 }
143 
144 std::ostream &operator<<( std::ostream &aStream, COLOR4D const &aColor )
145 {
146  return aStream << aColor.ToWxString( wxC2S_CSS_SYNTAX );
147 }
148 
149 void to_json( nlohmann::json& aJson, const COLOR4D& aColor )
150 {
151  aJson = nlohmann::json( aColor.ToWxString( wxC2S_CSS_SYNTAX ).ToStdString() );
152 }
153 
154 
155 void from_json( const nlohmann::json& aJson, COLOR4D& aColor )
156 {
157  aColor.SetFromWxString( aJson.get<std::string>() );
158 }
159 
160 }
161 
162 
163 void COLOR4D::ToHSL( double& aOutHue, double& aOutSaturation, double& aOutLightness ) const
164 {
165  auto min = std::min( r, std::min( g, b ) );
166  auto max = std::max( r, std::max( g, b ) );
167  auto diff = max - min;
168 
169  aOutLightness = ( max + min ) / 2.0;
170 
171  if( aOutLightness >= 1.0 )
172  aOutSaturation = 0.0;
173  else
174  aOutSaturation = diff / ( 1.0 - std::abs( 2.0 * aOutLightness - 1.0 ) );
175 
176  double hue;
177 
178  if( diff <= 0.0 )
179  hue = 0.0;
180  else if( max == r )
181  hue = ( g - b ) / diff;
182  else if( max == g )
183  hue = ( b - r ) / diff + 2.0;
184  else
185  hue = ( r - g ) / diff + 4.0;
186 
187  aOutHue = hue > 0.0 ? hue * 60.0 : hue * 60.0 + 360.0;
188 
189  while( aOutHue < 0.0 )
190  aOutHue += 360.0;
191 }
192 
193 
194 void COLOR4D::FromHSL( double aInHue, double aInSaturation, double aInLightness )
195 {
196  const auto P = ( 1.0 - std::abs( 2.0 * aInLightness - 1.0 ) ) * aInSaturation;
197  const auto scaled_hue = aInHue / 60.0;
198  const auto Q = P * ( 1.0 - std::abs( std::fmod( scaled_hue, 2.0 ) - 1.0 ) );
199 
200  r = g = b = aInLightness - P / 2.0;
201 
202  if (scaled_hue < 1.0)
203  {
204  r += P;
205  g += Q;
206  }
207  else if (scaled_hue < 2.0)
208  {
209  r += Q;
210  g += P;
211  }
212  else if (scaled_hue < 3.0)
213  {
214  g += P;
215  b += Q;
216  }
217  else if (scaled_hue < 4.0)
218  {
219  g += Q;
220  b += P;
221  }
222  else if (scaled_hue < 5.0)
223  {
224  r += Q;
225  b += P;
226  }
227  else
228  {
229  r += P;
230  b += Q;
231  }
232 }
233 
234 
235 void COLOR4D::ToHSV( double& aOutHue, double& aOutSaturation, double& aOutValue, bool aAlwaysDefineHue ) const
236 {
237  double min, max, delta;
238 
239  min = r < g ? r : g;
240  min = min < b ? min : b;
241 
242  max = r > g ? r : g;
243  max = max > b ? max : b;
244 
245  aOutValue = max; // value
246  delta = max - min;
247 
248  if( max > 0.0 )
249  {
250  aOutSaturation = ( delta / max );
251  }
252  else // for black color (r = g = b = 0 ) saturation is set to 0.
253  {
254  aOutSaturation = 0.0;
255  aOutHue = aAlwaysDefineHue ? 0.0 : NAN;
256  return;
257  }
258 
259  /* Hue in degrees (0...360) is coded according to this table
260  * 0 or 360 : red
261  * 60 : yellow
262  * 120 : green
263  * 180 : cyan
264  * 240 : blue
265  * 300 : magenta
266  */
267  if( delta != 0.0 )
268  {
269  if( r >= max )
270  aOutHue = ( g - b ) / delta; // between yellow & magenta
271  else if( g >= max )
272  aOutHue = 2.0 + ( b - r ) / delta; // between cyan & yellow
273  else
274  aOutHue = 4.0 + ( r - g ) / delta; // between magenta & cyan
275 
276  aOutHue *= 60.0; // degrees
277 
278  if( aOutHue < 0.0 )
279  aOutHue += 360.0;
280  }
281  else // delta = 0 means r = g = b. hue is set to 0.0
282  {
283  aOutHue = aAlwaysDefineHue ? 0.0 : NAN;
284  }
285 }
286 
287 
288 void COLOR4D::FromHSV( double aInH, double aInS, double aInV )
289 {
290  if( aInS <= 0.0 )
291  {
292  r = aInV;
293  g = aInV;
294  b = aInV;
295  return;
296  }
297 
298  double hh = aInH;
299 
300  while( hh >= 360.0 )
301  hh -= 360.0;
302 
303  /* Hue in degrees (0...360) is coded according to this table
304  * 0 or 360 : red
305  * 60 : yellow
306  * 120 : green
307  * 180 : cyan
308  * 240 : blue
309  * 300 : magenta
310  */
311  hh /= 60.0;
312 
313  int i = (int) hh;
314  double ff = hh - i;
315 
316  double p = aInV * ( 1.0 - aInS );
317  double q = aInV * ( 1.0 - ( aInS * ff ) );
318  double t = aInV * ( 1.0 - ( aInS * ( 1.0 - ff ) ) );
319 
320  switch( i )
321  {
322  case 0:
323  r = aInV;
324  g = t;
325  b = p;
326  break;
327 
328  case 1:
329  r = q;
330  g = aInV;
331  b = p;
332  break;
333 
334  case 2:
335  r = p;
336  g = aInV;
337  b = t;
338  break;
339 
340  case 3:
341  r = p;
342  g = q;
343  b = aInV;
344  break;
345 
346  case 4:
347  r = t;
348  g = p;
349  b = aInV;
350  break;
351 
352  case 5:
353  default:
354  r = aInV;
355  g = p;
356  b = q;
357  break;
358  }
359 }
360 
361 
362 COLOR4D& COLOR4D::Saturate( double aFactor )
363 {
364  // One can saturate a color only when r, v, b are not equal
365  if( r == g && r == b )
366  return *this;
367 
368  double h, s, v;
369 
370  ToHSV( h, s, v, true );
371  FromHSV( h, aFactor, 1.0 );
372 
373  return *this;
374 }
375 
376 constexpr COLOR4D COLOR4D::UNSPECIFIED( 0, 0, 0, 0 );
377 constexpr COLOR4D COLOR4D::WHITE( 1, 1, 1, 1 );
378 constexpr COLOR4D COLOR4D::BLACK( 0, 0, 0, 1 );
EDA_COLOR_T
NOTE: EDA_COLOR_T is deprecated and is kept around for compatibility with legacy canvas.
Definition: colors.h:42
void ToHSV(double &aOutHue, double &aOutSaturation, double &aOutValue, bool aAlwaysDefineHue=false) const
Function ToHSV() Converts current color (stored in RGB) to HSV format.
Definition: color4d.cpp:235
unsigned char m_Red
Definition: colors.h:146
Class CAIRO_GAL is the cairo implementation of the graphics abstraction layer.
Definition: color4d.cpp:131
COLOR4D & Saturate(double aFactor)
Saturates the color to a given factor (in HSV model)
Definition: color4d.cpp:362
unsigned char m_Green
Definition: colors.h:145
double g
Green component.
Definition: color4d.h:303
void from_json(const nlohmann::json &aJson, COLOR4D &aColor)
Definition: color4d.cpp:155
nlohmann::json json
Definition: gerbview.cpp:40
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition: color4d.h:308
double b
Blue component.
Definition: color4d.h:304
static const COLOR4D BLACK
Definition: color4d.h:312
double a
Alpha component.
Definition: color4d.h:305
unsigned char m_Blue
Definition: colors.h:144
const StructColors g_ColorRefs[NBCOLORS]
The predefined colors used in KiCad.
Definition: colors.cpp:37
static const COLOR4D WHITE
Definition: color4d.h:311
void ToHSL(double &aOutHue, double &aOutSaturation, double &aOutValue) const
Function ToHSL() Converts current color (stored in RGB) to HSL format.
Definition: color4d.cpp:163
std::ostream & operator<<(std::ostream &aStream, COLOR4D const &aColor)
Syntactic sugar for outputting colors to strings.
Definition: color4d.cpp:144
void FromHSV(double aInH, double aInS, double aInV)
Function FromHSV() Changes currently used color to the one given by hue, saturation and value paramet...
Definition: color4d.cpp:288
void to_json(nlohmann::json &aJson, const COLOR4D &aColor)
Definition: color4d.cpp:149
YYCODETYPE lhs
const bool operator==(const COLOR4D &lhs, const COLOR4D &rhs)
Equality operator, are two colors equal.
Definition: color4d.cpp:133
double r
Red component.
Definition: color4d.h:302
const bool operator!=(const COLOR4D &lhs, const COLOR4D &rhs)
Not equality operator, are two colors not equal.
Definition: color4d.cpp:139
void FromHSL(double aInHue, double aInSaturation, double aInLightness)
Function FromHSL() Changes currently used color to the one given by hue, saturation and lightness par...
Definition: color4d.cpp:194
Number of colors.
Definition: colors.h:75
COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:40