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-2021 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#include <i18n_utility.h>
30#include <wx/crt.h>
31#include <math/util.h>
32
33using namespace KIGFX;
34
35#define TS( string ) wxString( _HKI( string ) ).ToStdString()
36
37// We can't have this as a plain static variable, because it is referenced during the initialization
38// of other static variables, so we must initialize it explicitly on first use.
40{
41 static StructColors s_ColorRefs[NBCOLORS] =
42 {
43 { 0, 0, 0, BLACK, TS( "Black" ), DARKDARKGRAY },
44 { 72, 72, 72, DARKDARKGRAY, TS( "Gray 1" ), DARKGRAY },
45 { 132, 132, 132, DARKGRAY, TS( "Gray 2" ), LIGHTGRAY },
46 { 194, 194, 194, LIGHTGRAY, TS( "Gray 3" ), WHITE },
47 { 255, 255, 255, WHITE, TS( "White" ), WHITE },
48 { 194, 255, 255, LIGHTYELLOW, TS( "L.Yellow" ), WHITE },
49 { 191, 229, 255, LIGHTERORANGE, TS( "L.Orange" ), WHITE },
50 { 72, 0, 0, DARKBLUE, TS( "Blue 1" ), BLUE },
51 { 0, 72, 0, DARKGREEN, TS( "Green 1" ), GREEN },
52 { 72, 72, 0, DARKCYAN, TS( "Cyan 1" ), CYAN },
53 { 0, 0, 72, DARKRED, TS( "Red 1" ), RED },
54 { 72, 0, 72, DARKMAGENTA, TS( "Magenta 1" ), MAGENTA },
55 { 0, 72, 72, DARKBROWN, TS( "Brown 1" ), BROWN },
56 { 0, 77, 128, DARKORANGE, TS( "Orange 1" ), ORANGE },
57 { 132, 0, 0, BLUE, TS( "Blue 2" ), LIGHTBLUE },
58 { 0, 132, 0, GREEN, TS( "Green 2" ), LIGHTGREEN },
59 { 132, 132, 0, CYAN, TS( "Cyan 2" ), LIGHTCYAN },
60 { 0, 0, 132, RED, TS( "Red 2" ), LIGHTRED },
61 { 132, 0, 132, MAGENTA, TS( "Magenta 2" ), LIGHTMAGENTA },
62 { 0, 132, 132, BROWN, TS( "Brown 2" ), YELLOW },
63 { 0, 102, 204, ORANGE, TS( "Orange 2" ), LIGHTORANGE },
64 { 194, 0, 0, LIGHTBLUE, TS( "Blue 3" ), PUREBLUE, },
65 { 0, 194, 0, LIGHTGREEN, TS( "Green 3" ), PUREGREEN },
66 { 194, 194, 0, LIGHTCYAN, TS( "Cyan 3" ), PURECYAN },
67 { 0, 0, 194, LIGHTRED, TS( "Red 3" ), PURERED },
68 { 194, 0, 194, LIGHTMAGENTA, TS( "Magenta 3" ), PUREMAGENTA },
69 { 0, 194, 194, YELLOW, TS( "Yellow 3" ), PUREYELLOW },
70 { 0, 133, 221, LIGHTORANGE, TS( "Orange 3" ), PUREORANGE },
71 { 255, 0, 0, PUREBLUE, TS( "Blue 4" ), WHITE },
72 { 0, 255, 0, PUREGREEN, TS( "Green 4" ), WHITE },
73 { 255, 255, 0, PURECYAN, TS( "Cyan 4" ), WHITE },
74 { 0, 0, 255, PURERED, TS( "Red 4" ), WHITE },
75 { 255, 0, 255, PUREMAGENTA, TS( "Magenta 4" ), WHITE },
76 { 0, 255, 255, PUREYELLOW, TS( "Yellow 4" ), WHITE },
77 { 0, 153, 255, PUREORANGE, TS( "Orange 4" ), WHITE },
78 };
79 return s_ColorRefs;
80}
81
82
83COLOR4D::COLOR4D( EDA_COLOR_T aColor )
84{
85 if( aColor <= UNSPECIFIED_COLOR || aColor >= NBCOLORS )
86 {
88 return;
89 }
90
91 int candidate = 0;
92
93 for( ; candidate < NBCOLORS; ++candidate )
94 {
95 if( colorRefs()[candidate].m_Numcolor == aColor )
96 break;
97 }
98
99 if( candidate >= NBCOLORS )
100 {
101 *this = COLOR4D::UNSPECIFIED;
102 return;
103 }
104
105 r = colorRefs()[candidate].m_Red / 255.0;
106 g = colorRefs()[candidate].m_Green / 255.0;
107 b = colorRefs()[candidate].m_Blue / 255.0;
108 a = 1.0;
109}
110
111
112#ifdef WX_COMPATIBILITY
113COLOR4D::COLOR4D( const wxString& aColorStr )
114{
115 if( !SetFromHexString( aColorStr ) )
116 SetFromWxString( aColorStr );
117}
118
119
120COLOR4D::COLOR4D( const wxColour& aColor )
121{
122 r = aColor.Red() / 255.0;
123 g = aColor.Green() / 255.0;
124 b = aColor.Blue() / 255.0;
125 a = aColor.Alpha() / 255.0;
126}
127
128
129bool COLOR4D::SetFromWxString( const wxString& aColorString )
130{
131 wxColour c;
132
133 if( c.Set( aColorString ) )
134 {
135 r = c.Red() / 255.0;
136 g = c.Green() / 255.0;
137 b = c.Blue() / 255.0;
138 a = c.Alpha() / 255.0;
139
140 return true;
141 }
142
143 return false;
144}
145
146
147wxString COLOR4D::ToCSSString() const
148{
149 wxColour c = ToColour();
150 wxString str;
151
152 const int red = c.Red();
153 const int green = c.Green();
154 const int blue = c.Blue();
155 const int alpha = c.Alpha();
156
157 if ( alpha == wxALPHA_OPAQUE )
158 {
159 str.Printf( wxT( "rgb(%d, %d, %d)" ), red, green, blue );
160 }
161 else // use rgba() form
162 {
163 wxString alpha_str = wxString::FromCDouble( alpha / 255.0, 3 );
164
165 // The wxC2S_CSS_SYNTAX is particularly sensitive to ','s (as it uses them for value
166 // delimiters), and wxWidgets is known to be buggy in this respect when dealing with
167 // Serbian and Russian locales (at least), so we enforce an extra level of safety.
168 alpha_str.Replace( wxT( "," ), wxT( "." ) );
169
170 str.Printf( wxT( "rgba(%d, %d, %d, %s)" ), red, green, blue, alpha_str );
171 }
172
173 return str;
174}
175
176
177bool COLOR4D::SetFromHexString( const wxString& aColorString )
178{
179 wxString str = aColorString;
180 str.Trim( true );
181 str.Trim( false );
182
183 if( str.length() < 7 || str.GetChar( 0 ) != '#' )
184 return false;
185
186 unsigned long tmp;
187
188 if( wxSscanf( str.wx_str() + 1, wxT( "%lx" ), &tmp ) != 1 )
189 return false;
190
191 if( str.length() >= 9 )
192 {
193 r = ( (tmp >> 24) & 0xFF ) / 255.0;
194 g = ( (tmp >> 16) & 0xFF ) / 255.0;
195 b = ( (tmp >> 8) & 0xFF ) / 255.0;
196 a = ( tmp & 0xFF ) / 255.0;
197 }
198 else
199 {
200 r = ( (tmp >> 16) & 0xFF ) / 255.0;
201 g = ( (tmp >> 8) & 0xFF ) / 255.0;
202 b = ( tmp & 0xFF ) / 255.0;
203 a = 1.0;
204 }
205
206 return true;
207}
208
209
210wxString COLOR4D::ToHexString() const
211{
212 return wxString::Format( wxT("#%02X%02X%02X%02X" ),
213 KiROUND( r * 255.0 ),
214 KiROUND( g * 255.0 ),
215 KiROUND( b * 255.0 ),
216 KiROUND( a * 255.0 ) );
217}
218
219
220wxColour COLOR4D::ToColour() const
221{
222 using CHAN_T = wxColourBase::ChannelType;
223
224 const wxColour colour(
225 static_cast<CHAN_T>( r * 255 + 0.5 ), static_cast<CHAN_T>( g * 255 + 0.5 ),
226 static_cast<CHAN_T>( b * 255 + 0.5 ), static_cast<CHAN_T>( a * 255 + 0.5 ) );
227 return colour;
228}
229
230#endif
231
232
233COLOR4D COLOR4D::LegacyMix( const COLOR4D& aColor ) const
234{
235 COLOR4D candidate;
236
237 // Blend the two colors (i.e. OR the RGB values)
238 candidate.r = ( (unsigned) ( 255.0 * r ) | (unsigned) ( 255.0 * aColor.r ) ) / 255.0,
239 candidate.g = ( (unsigned) ( 255.0 * g ) | (unsigned) ( 255.0 * aColor.g ) ) / 255.0,
240 candidate.b = ( (unsigned) ( 255.0 * b ) | (unsigned) ( 255.0 * aColor.b ) ) / 255.0,
241
242 // the alpha channel can be reinitialized but what is the best value?
243 candidate.a = ( aColor.a + a ) / 2;
244
245 return candidate;
246}
247
248
249unsigned int COLOR4D::ToU32() const
250{
251 return ToColour().GetRGB();
252}
253
254
255void COLOR4D::FromU32( unsigned int aPackedColor )
256{
257 wxColour c;
258 c.SetRGB( aPackedColor );
259 r = c.Red() / 255.0;
260 g = c.Green() / 255.0;
261 b = c.Blue() / 255.0;
262 a = c.Alpha() / 255.0;
263}
264
265
266namespace KIGFX {
267
268const bool operator==( const COLOR4D& lhs, const COLOR4D& rhs )
269{
270 return lhs.a == rhs.a && lhs.r == rhs.r && lhs.g == rhs.g && lhs.b == rhs.b;
271}
272
273
274const bool operator!=( const COLOR4D& lhs, const COLOR4D& rhs )
275{
276 return !( lhs == rhs );
277}
278
279
280const bool operator<( const COLOR4D& lhs, const COLOR4D& rhs )
281{
282 if( lhs.r < rhs.r )
283 return true;
284 else if( lhs.g < rhs.g )
285 return true;
286 else if( lhs.b < rhs.b )
287 return true;
288 else if( lhs.a < rhs.a )
289 return true;
290
291 return false;
292}
293
294
295std::ostream &operator<<( std::ostream &aStream, COLOR4D const &aColor )
296{
297 return aStream << aColor.ToCSSString();
298}
299
300
301void to_json( nlohmann::json& aJson, const COLOR4D& aColor )
302{
303 aJson = nlohmann::json( aColor.ToCSSString().ToStdString() );
304}
305
306
307void from_json( const nlohmann::json& aJson, COLOR4D& aColor )
308{
309 aColor.SetFromWxString( aJson.get<std::string>() );
310}
311
312}
313
314
315void COLOR4D::ToHSL( double& aOutHue, double& aOutSaturation, double& aOutLightness ) const
316{
317 auto min = std::min( r, std::min( g, b ) );
318 auto max = std::max( r, std::max( g, b ) );
319 auto diff = max - min;
320
321 aOutLightness = ( max + min ) / 2.0;
322
323 if( aOutLightness >= 1.0 )
324 aOutSaturation = 0.0;
325 else
326 aOutSaturation = diff / ( 1.0 - std::abs( 2.0 * aOutLightness - 1.0 ) );
327
328 double hue;
329
330 if( diff <= 0.0 )
331 hue = 0.0;
332 else if( max == r )
333 hue = ( g - b ) / diff;
334 else if( max == g )
335 hue = ( b - r ) / diff + 2.0;
336 else
337 hue = ( r - g ) / diff + 4.0;
338
339 aOutHue = hue > 0.0 ? hue * 60.0 : hue * 60.0 + 360.0;
340
341 while( aOutHue < 0.0 )
342 aOutHue += 360.0;
343}
344
345
346void COLOR4D::FromHSL( double aInHue, double aInSaturation, double aInLightness )
347{
348 const auto P = ( 1.0 - std::abs( 2.0 * aInLightness - 1.0 ) ) * aInSaturation;
349 const auto scaled_hue = aInHue / 60.0;
350 const auto Q = P * ( 1.0 - std::abs( std::fmod( scaled_hue, 2.0 ) - 1.0 ) );
351
352 r = g = b = aInLightness - P / 2.0;
353
354 if (scaled_hue < 1.0)
355 {
356 r += P;
357 g += Q;
358 }
359 else if (scaled_hue < 2.0)
360 {
361 r += Q;
362 g += P;
363 }
364 else if (scaled_hue < 3.0)
365 {
366 g += P;
367 b += Q;
368 }
369 else if (scaled_hue < 4.0)
370 {
371 g += Q;
372 b += P;
373 }
374 else if (scaled_hue < 5.0)
375 {
376 r += Q;
377 b += P;
378 }
379 else
380 {
381 r += P;
382 b += Q;
383 }
384}
385
386
387void COLOR4D::ToHSV( double& aOutHue, double& aOutSaturation, double& aOutValue,
388 bool aAlwaysDefineHue ) const
389{
390 double min, max, delta;
391
392 min = r < g ? r : g;
393 min = min < b ? min : b;
394
395 max = r > g ? r : g;
396 max = max > b ? max : b;
397
398 aOutValue = max; // value
399 delta = max - min;
400
401 if( max > 0.0 )
402 {
403 aOutSaturation = ( delta / max );
404 }
405 else // for black color (r = g = b = 0 ) saturation is set to 0.
406 {
407 aOutSaturation = 0.0;
408 aOutHue = aAlwaysDefineHue ? 0.0 : NAN;
409 return;
410 }
411
412 /* Hue in degrees (0...360) is coded according to this table
413 * 0 or 360 : red
414 * 60 : yellow
415 * 120 : green
416 * 180 : cyan
417 * 240 : blue
418 * 300 : magenta
419 */
420 if( delta != 0.0 )
421 {
422 if( r >= max )
423 aOutHue = ( g - b ) / delta; // between yellow & magenta
424 else if( g >= max )
425 aOutHue = 2.0 + ( b - r ) / delta; // between cyan & yellow
426 else
427 aOutHue = 4.0 + ( r - g ) / delta; // between magenta & cyan
428
429 aOutHue *= 60.0; // degrees
430
431 if( aOutHue < 0.0 )
432 aOutHue += 360.0;
433 }
434 else // delta = 0 means r = g = b. hue is set to 0.0
435 {
436 aOutHue = aAlwaysDefineHue ? 0.0 : NAN;
437 }
438}
439
440
441void COLOR4D::FromHSV( double aInH, double aInS, double aInV )
442{
443 if( aInS <= 0.0 )
444 {
445 r = aInV;
446 g = aInV;
447 b = aInV;
448 return;
449 }
450
451 double hh = aInH;
452
453 while( hh >= 360.0 )
454 hh -= 360.0;
455
456 /* Hue in degrees (0...360) is coded according to this table
457 * 0 or 360 : red
458 * 60 : yellow
459 * 120 : green
460 * 180 : cyan
461 * 240 : blue
462 * 300 : magenta
463 */
464 hh /= 60.0;
465
466 int i = (int) hh;
467 double ff = hh - i;
468
469 double p = aInV * ( 1.0 - aInS );
470 double q = aInV * ( 1.0 - ( aInS * ff ) );
471 double t = aInV * ( 1.0 - ( aInS * ( 1.0 - ff ) ) );
472
473 switch( i )
474 {
475 case 0:
476 r = aInV;
477 g = t;
478 b = p;
479 break;
480
481 case 1:
482 r = q;
483 g = aInV;
484 b = p;
485 break;
486
487 case 2:
488 r = p;
489 g = aInV;
490 b = t;
491 break;
492
493 case 3:
494 r = p;
495 g = q;
496 b = aInV;
497 break;
498
499 case 4:
500 r = t;
501 g = p;
502 b = aInV;
503 break;
504
505 case 5:
506 default:
507 r = aInV;
508 g = p;
509 b = q;
510 break;
511 }
512}
513
514
515COLOR4D& COLOR4D::Saturate( double aFactor )
516{
517 // One can saturate a color only when r, v, b are not equal
518 if( r == g && r == b )
519 return *this;
520
521 double h, s, v;
522
523 ToHSV( h, s, v, true );
524 FromHSV( h, aFactor, 1.0 );
525
526 return *this;
527}
528
529
530const COLOR4D COLOR4D::UNSPECIFIED( 0, 0, 0, 0 );
531const COLOR4D COLOR4D::WHITE( 1, 1, 1, 1 );
532const COLOR4D COLOR4D::BLACK( 0, 0, 0, 1 );
533const COLOR4D COLOR4D::CLEAR( 1, 0, 1, 0 );
534
535
536double COLOR4D::Distance( const COLOR4D& other ) const
537{
538 return ( r - other.r ) * ( r - other.r )
539 + ( g - other.g ) * ( g - other.g )
540 + ( b - other.b ) * ( b - other.b );
541}
542
543
545{
547
548 /* Find the 'nearest' color in the palette. This is fun. There is
549 a gazilion of metrics for the color space and no one of the
550 useful one is in the RGB color space. Who cares, this is a CAD,
551 not a photosomething...
552
553 I hereby declare that the distance is the sum of the square of the
554 component difference. Think about the RGB color cube. Now get the
555 euclidean distance, but without the square root... for ordering
556 purposes it's the same, obviously. Also each component can't be
557 less of the target one, since I found this currently work better...
558 */
559 int nearest_distance = 255 * 255 * 3 + 1; // Can't beat this
560
562 trying = static_cast<EDA_COLOR_T>( int( trying ) + 1 ) )
563 {
564 const StructColors &c = colorRefs()[trying];
565 int distance = ( aR - c.m_Red ) * ( aR - c.m_Red ) +
566 ( aG - c.m_Green ) * ( aG - c.m_Green ) +
567 ( aB - c.m_Blue ) * ( aB - c.m_Blue );
568
569 if( distance < nearest_distance && c.m_Red >= aR &&
570 c.m_Green >= aG && c.m_Blue >= aB )
571 {
572 nearest_distance = distance;
573 candidate = trying;
574 }
575 }
576
577 return candidate;
578}
579
580
581COLOR4D& COLOR4D::FromCSSRGBA( int aRed, int aGreen, int aBlue, double aAlpha )
582{
583 r = std::max( 0, std::min( 255, aRed ) ) / 255.0;
584 g = std::max( 0, std::min( 255, aGreen ) ) / 255.0;
585 b = std::max( 0, std::min( 255, aBlue ) ) / 255.0;
586 a = std::max( 0.0, std::min( 1.0, aAlpha ) );
587
588 return *this;
589}
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
void ToHSL(double &aOutHue, double &aOutSaturation, double &aOutValue) const
Converts current color (stored in RGB) to HSL format.
Definition: color4d.cpp:315
double r
Red component.
Definition: color4d.h:384
double g
Green component.
Definition: color4d.h:385
static const COLOR4D CLEAR
Definition: color4d.h:395
void ToHSV(double &aOutHue, double &aOutSaturation, double &aOutValue, bool aAlwaysDefineHue=false) const
Convert current color (stored in RGB) to HSV format.
Definition: color4d.cpp:387
static EDA_COLOR_T FindNearestLegacyColor(int aR, int aG, int aB)
Returns a legacy color ID that is closest to the given 8-bit RGB values.
Definition: color4d.cpp:544
void FromHSV(double aInH, double aInS, double aInV)
Changes currently used color to the one given by hue, saturation and value parameters.
Definition: color4d.cpp:441
static const COLOR4D WHITE
Definition: color4d.h:393
double a
Alpha component.
Definition: color4d.h:387
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition: color4d.h:390
double Distance(const COLOR4D &other) const
Returns the distance (in RGB space) between two colors.
Definition: color4d.cpp:536
void FromHSL(double aInHue, double aInSaturation, double aInLightness)
Change currently used color to the one given by hue, saturation and lightness parameters.
Definition: color4d.cpp:346
static const COLOR4D BLACK
Definition: color4d.h:394
COLOR4D & FromCSSRGBA(int aRed, int aGreen, int aBlue, double aAlpha=1.0)
Initialize the color from a RGBA value with 0-255 red/green/blue and 0-1 alpha.
Definition: color4d.cpp:581
COLOR4D & Saturate(double aFactor)
Saturates the color to a given factor (in HSV model)
Definition: color4d.cpp:515
double b
Blue component.
Definition: color4d.h:386
const StructColors * colorRefs()
Global list of legacy color names, still used all over the place for constructing COLOR4D's.
Definition: color4d.cpp:39
#define TS(string)
Definition: color4d.cpp:35
EDA_COLOR_T
Legacy color enumeration.
Definition: color4d.h:42
@ LIGHTGREEN
Definition: color4d.h:63
@ PUREORANGE
Definition: color4d.h:78
@ BROWN
Definition: color4d.h:61
@ PURECYAN
Definition: color4d.h:70
@ LIGHTBLUE
Definition: color4d.h:62
@ WHITE
Definition: color4d.h:48
@ LIGHTERORANGE
Definition: color4d.h:74
@ LIGHTORANGE
Definition: color4d.h:77
@ BLUE
Definition: color4d.h:56
@ LIGHTGRAY
Definition: color4d.h:47
@ DARKGRAY
Definition: color4d.h:46
@ MAGENTA
Definition: color4d.h:60
@ DARKORANGE
Definition: color4d.h:75
@ DARKMAGENTA
Definition: color4d.h:54
@ LIGHTYELLOW
Definition: color4d.h:49
@ DARKCYAN
Definition: color4d.h:52
@ NBCOLORS
Number of colors.
Definition: color4d.h:79
@ PURERED
Definition: color4d.h:71
@ GREEN
Definition: color4d.h:57
@ CYAN
Definition: color4d.h:58
@ DARKRED
Definition: color4d.h:53
@ DARKBLUE
Definition: color4d.h:50
@ LIGHTCYAN
Definition: color4d.h:64
@ DARKDARKGRAY
Definition: color4d.h:45
@ ORANGE
Definition: color4d.h:76
@ PUREGREEN
Definition: color4d.h:69
@ LIGHTMAGENTA
Definition: color4d.h:66
@ PUREYELLOW
Definition: color4d.h:73
@ YELLOW
Definition: color4d.h:67
@ PUREBLUE
Definition: color4d.h:68
@ LIGHTRED
Definition: color4d.h:65
@ BLACK
Definition: color4d.h:44
@ DARKGREEN
Definition: color4d.h:51
@ PUREMAGENTA
Definition: color4d.h:72
@ RED
Definition: color4d.h:59
@ DARKBROWN
Definition: color4d.h:55
nlohmann::json json
Definition: gerbview.cpp:44
Some functions to handle hotkeys in KiCad.
The Cairo implementation of the graphics abstraction layer.
Definition: color4d.cpp:266
void from_json(const nlohmann::json &aJson, COLOR4D &aColor)
Definition: color4d.cpp:307
std::ostream & operator<<(std::ostream &aStream, COLOR4D const &aColor)
Syntactic sugar for outputting colors to strings.
Definition: color4d.cpp:295
const bool operator<(const COLOR4D &lhs, const COLOR4D &rhs)
Definition: color4d.cpp:280
const bool operator==(const COLOR4D &lhs, const COLOR4D &rhs)
Equality operator, are two colors equal.
Definition: color4d.cpp:268
const bool operator!=(const COLOR4D &lhs, const COLOR4D &rhs)
Not equality operator, are two colors not equal.
Definition: color4d.cpp:274
void to_json(nlohmann::json &aJson, const COLOR4D &aColor)
Definition: color4d.cpp:301
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:401
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
#define Q()
#define P()
unsigned char m_Blue
Definition: color4d.h:86
unsigned char m_Green
Definition: color4d.h:87
unsigned char m_Red
Definition: color4d.h:88
constexpr int delta
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:80