KiCad PCB EDA Suite
colors.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 (C) 2014 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2014 KiCad Developers, see CHANGELOG.TXT for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 #include <colors.h>
26 #include <i18n_utility.h>
27 
28 
38 {
39  { 0, 0, 0, BLACK, _HKI( "Black" ), DARKDARKGRAY },
40  { 72, 72, 72, DARKDARKGRAY, _HKI( "Gray 1" ), DARKGRAY },
41  { 132, 132, 132, DARKGRAY, _HKI( "Gray 2" ), LIGHTGRAY },
42  { 194, 194, 194, LIGHTGRAY, _HKI( "Gray 3" ), WHITE },
43  { 255, 255, 255, WHITE, _HKI( "White" ), WHITE },
44  { 194, 255, 255, LIGHTYELLOW, _HKI( "L.Yellow" ), WHITE },
45  { 72, 0, 0, DARKBLUE, _HKI( "Blue 1" ), BLUE },
46  { 0, 72, 0, DARKGREEN, _HKI( "Green 1" ), GREEN },
47  { 72, 72, 0, DARKCYAN, _HKI( "Cyan 1" ), CYAN },
48  { 0, 0, 72, DARKRED, _HKI( "Red 1" ), RED },
49  { 72, 0, 72, DARKMAGENTA, _HKI( "Magenta 1" ), MAGENTA },
50  { 0, 72, 72, DARKBROWN, _HKI( "Brown 1" ), BROWN },
51  { 132, 0, 0, BLUE, _HKI( "Blue 2" ), LIGHTBLUE },
52  { 0, 132, 0, GREEN, _HKI( "Green 2" ), LIGHTGREEN },
53  { 132, 132, 0, CYAN, _HKI( "Cyan 2" ), LIGHTCYAN },
54  { 0, 0, 132, RED, _HKI( "Red 2" ), LIGHTRED },
55  { 132, 0, 132, MAGENTA, _HKI( "Magenta 2" ), LIGHTMAGENTA },
56  { 0, 132, 132, BROWN, _HKI( "Brown 2" ), YELLOW },
57  { 194, 0, 0, LIGHTBLUE, _HKI( "Blue 3" ), PUREBLUE, },
58  { 0, 194, 0, LIGHTGREEN, _HKI( "Green 3" ), PUREGREEN },
59  { 194, 194, 0, LIGHTCYAN, _HKI( "Cyan 3" ), PURECYAN },
60  { 0, 0, 194, LIGHTRED, _HKI( "Red 3" ), PURERED },
61  { 194, 0, 194, LIGHTMAGENTA, _HKI( "Magenta 3" ), PUREMAGENTA },
62  { 0, 194, 194, YELLOW, _HKI( "Yellow 3" ), PUREYELLOW },
63  { 255, 0, 0, PUREBLUE, _HKI( "Blue 4" ), WHITE },
64  { 0, 255, 0, PUREGREEN, _HKI( "Green 4" ), WHITE },
65  { 255, 255, 0, PURECYAN, _HKI( "Cyan 4" ), WHITE },
66  { 0, 0, 255, PURERED, _HKI( "Red 4" ), WHITE },
67  { 255, 0, 255, PUREMAGENTA, _HKI( "Magenta 4" ), WHITE },
68  { 0, 255, 255, PUREYELLOW, _HKI( "Yellow 4" ), WHITE },
69 };
70 
71 
72 EDA_COLOR_T ColorByName( const wxString& aName )
73 {
74  // look for a match in the palette itself
75  for( EDA_COLOR_T trying = BLACK; trying < NBCOLORS; trying = NextColor(trying) )
76  {
77  if( 0 == aName.CmpNoCase( ColorGetName( trying ) ) )
78  return trying;
79  }
80 
81  // Not found, no idea...
82  return UNSPECIFIED_COLOR;
83 }
84 
85 
86 bool ColorIsLight( EDA_COLOR_T aColor )
87 {
88  const StructColors &c = g_ColorRefs[ColorGetBase( aColor )];
89  int r = c.m_Red;
90  int g = c.m_Green;
91  int b = c.m_Blue;
92  return ((r * r) + (g * g) + (b * b)) > (128 * 128 * 3);
93 }
94 
95 
96 EDA_COLOR_T ColorFindNearest( const wxColour &aColor )
97 {
98  return ColorFindNearest( aColor.Red(), aColor.Green(), aColor.Blue() );
99 }
100 
101 
102 EDA_COLOR_T ColorFindNearest( int aR, int aG, int aB )
103 {
104  EDA_COLOR_T candidate = BLACK;
105 
106  /* Find the 'nearest' color in the palette. This is fun. There is
107  a gazilion of metrics for the color space and no one of the
108  useful one is in the RGB color space. Who cares, this is a CAD,
109  not a photosomething...
110 
111  I hereby declare that the distance is the sum of the square of the
112  component difference. Think about the RGB color cube. Now get the
113  euclidean distance, but without the square root... for ordering
114  purposes it's the same, obviously. Also each component can't be
115  less of the target one, since I found this currently work better...
116  */
117  int nearest_distance = 255 * 255 * 3 + 1; // Can't beat this
118 
119  for( EDA_COLOR_T trying = BLACK; trying < NBCOLORS; trying = NextColor(trying) )
120  {
121  const StructColors &c = g_ColorRefs[trying];
122  int distance = (aR - c.m_Red) * (aR - c.m_Red) +
123  (aG - c.m_Green) * (aG - c.m_Green) +
124  (aB - c.m_Blue) * (aB - c.m_Blue);
125 
126  if( distance < nearest_distance && c.m_Red >= aR &&
127  c.m_Green >= aG && c.m_Blue >= aB )
128  {
129  nearest_distance = distance;
130  candidate = trying;
131  }
132  }
133 
134  return candidate;
135 }
136 
137 
139 {
140  /* Memoization storage. This could be potentially called for each
141  * color merge so a cache is useful (there are few colours anyway) */
142  static EDA_COLOR_T mix_cache[NBCOLORS][NBCOLORS];
143 
144  // TODO how is alpha used? it's a mac only thing, I have no idea
145  aColor1 = ColorGetBase( aColor1 );
146  aColor2 = ColorGetBase( aColor2 );
147 
148  // First easy thing: a black gives always the other colour
149  if( aColor1 == BLACK )
150  return aColor2;
151 
152  if( aColor2 == BLACK)
153  return aColor1;
154 
155  /* Now we are sure that black can't occur, so the rule is:
156  * BLACK means not computed yet. If we're lucky we already have
157  * an answer */
158  EDA_COLOR_T candidate = mix_cache[aColor1][aColor2];
159 
160  if( candidate != BLACK )
161  return candidate;
162 
163  // Blend the two colors (i.e. OR the RGB values)
164  const StructColors &c1 = g_ColorRefs[aColor1];
165  const StructColors &c2 = g_ColorRefs[aColor2];
166 
167  // Ask the palette for the nearest color to the mix
168  wxColour mixed( c1.m_Red | c2.m_Red,
169  c1.m_Green | c2.m_Green,
170  c1.m_Blue | c2.m_Blue );
171  candidate = ColorFindNearest( mixed );
172 
173  /* Here, BLACK is *not* a good answer, since it would recompute the next time.
174  * Even theorically its not possible (with the current rules), but
175  * maybe the metric will change in the future */
176  if( candidate == BLACK )
177  candidate = DARKDARKGRAY;
178 
179  // Store the result in the cache. The operation is commutative, too
180  mix_cache[aColor1][aColor2] = candidate;
181  mix_cache[aColor2][aColor1] = candidate;
182  return candidate;
183 }
184 
Definition: colors.h:57
EDA_COLOR_T ColorGetBase(EDA_COLOR_T aColor)
Return only the plain color part.
Definition: colors.h:96
EDA_COLOR_T
NOTE: EDA_COLOR_T is deprecated and is kept around for compatibility with legacy canvas.
Definition: colors.h:42
bool ColorIsLight(EDA_COLOR_T aColor)
Check if a color is light i.e.
Definition: colors.cpp:86
EDA_COLOR_T ColorFindNearest(const wxColour &aColor)
Find the nearest color match.
Definition: colors.cpp:96
EDA_COLOR_T ColorByName(const wxString &aName)
Find a color by name.
Definition: colors.cpp:72
unsigned char m_Red
Definition: colors.h:146
Definition: colors.h:61
unsigned char m_Green
Definition: colors.h:145
Definition: colors.h:54
Definition: colors.h:72
unsigned char m_Blue
Definition: colors.h:144
Definition: colors.h:59
const wxChar * ColorGetName(EDA_COLOR_T aColor)
Definition: colors.h:185
const StructColors g_ColorRefs[NBCOLORS]
The predefined colors used in KiCad.
Definition: colors.cpp:37
Definition: colors.h:60
EDA_COLOR_T ColorMix(EDA_COLOR_T aColor1, EDA_COLOR_T aColor2)
Mix two colors in some way (hopefully like a logical OR)
Definition: colors.cpp:138
Some functions to handle hotkeys in KiCad.
Definition: colors.h:58
Definition: colors.h:49
Definition: colors.h:45
Definition: colors.h:68
#define _HKI(x)
Number of colors.
Definition: colors.h:75
EDA_COLOR_T NextColor(EDA_COLOR_T &aColor)
Definition: colors.h:87
Definition: colors.h:62