KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_gal_xor_mode.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 The KiCad Developers, see AUTHORS.TXT for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
27
28#include <boost/test/unit_test.hpp>
29
30#include <gal/color4d.h>
31#include <cairo.h>
32#include <cmath>
33
34using namespace KIGFX;
35
36
37BOOST_AUTO_TEST_SUITE( GalXorMode )
38
39
40
43static COLOR4D getPixelColor( cairo_surface_t* surface, int x, int y )
44{
45 cairo_surface_flush( surface );
46
47 int stride = cairo_image_surface_get_stride( surface );
48 unsigned char* data = cairo_image_surface_get_data( surface );
49
50 unsigned char* pixel = data + y * stride + x * 4;
51
52 // Cairo ARGB32 format: B, G, R, A (little endian)
53 double b = pixel[0] / 255.0;
54 double g = pixel[1] / 255.0;
55 double r = pixel[2] / 255.0;
56 double a = pixel[3] / 255.0;
57
58 return COLOR4D( r, g, b, a );
59}
60
61
65static bool colorsApproxEqual( const COLOR4D& a, const COLOR4D& b, double tolerance = 0.02 )
66{
67 return std::abs( a.r - b.r ) < tolerance &&
68 std::abs( a.g - b.g ) < tolerance &&
69 std::abs( a.b - b.b ) < tolerance;
70}
71
72
77BOOST_AUTO_TEST_CASE( CairoDifferenceIdenticalColors )
78{
79 const int width = 100;
80 const int height = 100;
81
82 // Create destination surface (red background)
83 cairo_surface_t* destSurface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width, height );
84 cairo_t* destCtx = cairo_create( destSurface );
85
86 // Fill with solid red
87 cairo_set_source_rgba( destCtx, 1.0, 0.0, 0.0, 1.0 );
88 cairo_paint( destCtx );
89
90 // Create source surface (also red)
91 cairo_surface_t* srcSurface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width, height );
92 cairo_t* srcCtx = cairo_create( srcSurface );
93
94 // Fill with solid red (same as destination)
95 cairo_set_source_rgba( srcCtx, 1.0, 0.0, 0.0, 1.0 );
96 cairo_paint( srcCtx );
97
98 // Apply CAIRO_OPERATOR_DIFFERENCE: |src - dst| = |red - red| = black
99 cairo_set_operator( destCtx, CAIRO_OPERATOR_DIFFERENCE );
100 cairo_set_source_surface( destCtx, srcSurface, 0, 0 );
101 cairo_paint( destCtx );
102
103 // Check that the center pixel is black (identical colors cancel out)
104 COLOR4D result = getPixelColor( destSurface, 50, 50 );
105 COLOR4D expected( 0.0, 0.0, 0.0, 1.0 );
106
108 "Identical colors should cancel to black. Got: ("
109 << result.r << ", " << result.g << ", " << result.b << ")" );
110
111 // Cleanup
112 cairo_destroy( srcCtx );
113 cairo_surface_destroy( srcSurface );
114 cairo_destroy( destCtx );
115 cairo_surface_destroy( destSurface );
116}
117
118
122BOOST_AUTO_TEST_CASE( CairoDifferenceDifferentColors )
123{
124 const int width = 100;
125 const int height = 100;
126
127 // Create destination surface (red)
128 cairo_surface_t* destSurface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width, height );
129 cairo_t* destCtx = cairo_create( destSurface );
130
131 cairo_set_source_rgba( destCtx, 1.0, 0.0, 0.0, 1.0 ); // Red
132 cairo_paint( destCtx );
133
134 // Create source surface (green)
135 cairo_surface_t* srcSurface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width, height );
136 cairo_t* srcCtx = cairo_create( srcSurface );
137
138 cairo_set_source_rgba( srcCtx, 0.0, 1.0, 0.0, 1.0 ); // Green
139 cairo_paint( srcCtx );
140
141 // Apply CAIRO_OPERATOR_DIFFERENCE: |green - red| = (|0-1|, |1-0|, 0) = (1, 1, 0) = yellow
142 cairo_set_operator( destCtx, CAIRO_OPERATOR_DIFFERENCE );
143 cairo_set_source_surface( destCtx, srcSurface, 0, 0 );
144 cairo_paint( destCtx );
145
146 // Check that the result is yellow (difference of red and green)
147 COLOR4D result = getPixelColor( destSurface, 50, 50 );
148 COLOR4D expected( 1.0, 1.0, 0.0, 1.0 ); // Yellow
149
151 "Red - Green difference should be yellow. Got: ("
152 << result.r << ", " << result.g << ", " << result.b << ")" );
153
154 // Cleanup
155 cairo_destroy( srcCtx );
156 cairo_surface_destroy( srcSurface );
157 cairo_destroy( destCtx );
158 cairo_surface_destroy( destSurface );
159}
160
161
165BOOST_AUTO_TEST_CASE( CairoDifferenceNonOverlapping )
166{
167 const int width = 100;
168 const int height = 100;
169
170 // Create destination surface (transparent/black)
171 cairo_surface_t* destSurface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width, height );
172 cairo_t* destCtx = cairo_create( destSurface );
173
174 // Clear to black (no content)
175 cairo_set_source_rgba( destCtx, 0.0, 0.0, 0.0, 1.0 );
176 cairo_paint( destCtx );
177
178 // Create source surface (blue)
179 cairo_surface_t* srcSurface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width, height );
180 cairo_t* srcCtx = cairo_create( srcSurface );
181
182 cairo_set_source_rgba( srcCtx, 0.0, 0.0, 1.0, 1.0 ); // Blue
183 cairo_paint( srcCtx );
184
185 // Apply CAIRO_OPERATOR_DIFFERENCE: |blue - black| = blue
186 cairo_set_operator( destCtx, CAIRO_OPERATOR_DIFFERENCE );
187 cairo_set_source_surface( destCtx, srcSurface, 0, 0 );
188 cairo_paint( destCtx );
189
190 // Check that the result is blue (source on empty shows source)
191 COLOR4D result = getPixelColor( destSurface, 50, 50 );
192 COLOR4D expected( 0.0, 0.0, 1.0, 1.0 ); // Blue
193
195 "Blue on black should show blue. Got: ("
196 << result.r << ", " << result.g << ", " << result.b << ")" );
197
198 // Cleanup
199 cairo_destroy( srcCtx );
200 cairo_surface_destroy( srcSurface );
201 cairo_destroy( destCtx );
202 cairo_surface_destroy( destSurface );
203}
204
205
209BOOST_AUTO_TEST_CASE( CairoDifferencePartialOverlap )
210{
211 const int width = 100;
212 const int height = 100;
213
214 // Create destination surface with a red rectangle on the left half
215 cairo_surface_t* destSurface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width, height );
216 cairo_t* destCtx = cairo_create( destSurface );
217
218 // Clear to black
219 cairo_set_source_rgba( destCtx, 0.0, 0.0, 0.0, 1.0 );
220 cairo_paint( destCtx );
221
222 // Draw red rectangle on left half
223 cairo_set_source_rgba( destCtx, 1.0, 0.0, 0.0, 1.0 );
224 cairo_rectangle( destCtx, 0, 0, 50, 100 );
225 cairo_fill( destCtx );
226
227 // Create source surface with a red rectangle on the right half (partially overlapping)
228 cairo_surface_t* srcSurface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width, height );
229 cairo_t* srcCtx = cairo_create( srcSurface );
230
231 // Clear to black
232 cairo_set_source_rgba( srcCtx, 0.0, 0.0, 0.0, 1.0 );
233 cairo_paint( srcCtx );
234
235 // Draw red rectangle on right half (overlaps with left at x=25-50)
236 cairo_set_source_rgba( srcCtx, 1.0, 0.0, 0.0, 1.0 );
237 cairo_rectangle( srcCtx, 25, 0, 50, 100 );
238 cairo_fill( srcCtx );
239
240 // Apply CAIRO_OPERATOR_DIFFERENCE
241 cairo_set_operator( destCtx, CAIRO_OPERATOR_DIFFERENCE );
242 cairo_set_source_surface( destCtx, srcSurface, 0, 0 );
243 cairo_paint( destCtx );
244
245 // Check three regions:
246 // 1. Left-only (x=10): dest=red, src=black → |red-black| = red
247 // 2. Overlap (x=37): dest=red, src=red → |red-red| = black
248 // 3. Right-only (x=65): dest=black, src=red → |red-black| = red
249
250 COLOR4D leftOnly = getPixelColor( destSurface, 10, 50 );
251 COLOR4D overlap = getPixelColor( destSurface, 37, 50 );
252 COLOR4D rightOnly = getPixelColor( destSurface, 65, 50 );
253
254 COLOR4D expectedRed( 1.0, 0.0, 0.0, 1.0 );
255 COLOR4D expectedBlack( 0.0, 0.0, 0.0, 1.0 );
256
257 BOOST_CHECK_MESSAGE( colorsApproxEqual( leftOnly, expectedRed ),
258 "Left-only region should be red. Got: ("
259 << leftOnly.r << ", " << leftOnly.g << ", " << leftOnly.b << ")" );
260
261 BOOST_CHECK_MESSAGE( colorsApproxEqual( overlap, expectedBlack ),
262 "Overlap region should be black (canceled). Got: ("
263 << overlap.r << ", " << overlap.g << ", " << overlap.b << ")" );
264
265 BOOST_CHECK_MESSAGE( colorsApproxEqual( rightOnly, expectedRed ),
266 "Right-only region should be red. Got: ("
267 << rightOnly.r << ", " << rightOnly.g << ", " << rightOnly.b << ")" );
268
269 // Cleanup
270 cairo_destroy( srcCtx );
271 cairo_surface_destroy( srcSurface );
272 cairo_destroy( destCtx );
273 cairo_surface_destroy( destSurface );
274}
275
276
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
double r
Red component.
Definition color4d.h:389
double g
Green component.
Definition color4d.h:390
double b
Blue component.
Definition color4d.h:391
The Cairo implementation of the graphics abstraction layer.
Definition eda_group.h:29
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
static COLOR4D getPixelColor(cairo_surface_t *surface, int x, int y)
Helper to get a pixel color from a Cairo ARGB32 surface.
static bool colorsApproxEqual(const COLOR4D &a, const COLOR4D &b, double tolerance=0.02)
Helper to check if two colors are approximately equal.
BOOST_AUTO_TEST_CASE(CairoDifferenceIdenticalColors)
Test that CAIRO_OPERATOR_DIFFERENCE correctly computes |src - dst| for identical overlapping colors (...
BOOST_AUTO_TEST_SUITE_END()
VECTOR3I expected(15, 30, 45)
BOOST_CHECK_MESSAGE(totalMismatches==0, std::to_string(totalMismatches)+" board(s) with strategy disagreements")
wxString result
Test unit parsing edge cases and error handling.