KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_drc_bitmap_overlay_panel.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
20#include <boost/test/unit_test.hpp>
22
23#include <algorithm>
24#include <vector>
25
26#include <wx/gdicmn.h>
27
28
34{
35
40double ComputeScaleFactor( double aRawScale )
41{
42 if( aRawScale < 1.25 )
43 return 1.0;
44 else if( aRawScale < 1.75 )
45 return 1.5;
46 else
47 return 2.0;
48}
49
50
55wxPoint ScalePosition( int aX, int aY, double aScaleFactor )
56{
57 return wxPoint( static_cast<int>( aX * aScaleFactor ), static_cast<int>( aY * aScaleFactor ) );
58}
59
60
65wxSize ScaleSize( int aWidth, int aHeight, double aScaleFactor )
66{
67 return wxSize( static_cast<int>( aWidth * aScaleFactor ), static_cast<int>( aHeight * aScaleFactor ) );
68}
69
70
75bool IsOutOfBounds( const wxPoint& aScaledPos, const wxSize& aScaledSize, const wxSize& aBitmapSize )
76{
77 return ( aScaledPos.x + aScaledSize.GetWidth() > aBitmapSize.GetWidth() ||
78 aScaledPos.y + aScaledSize.GetHeight() > aBitmapSize.GetHeight() );
79}
80
81
86void SortByTabOrder( std::vector<DRC_RE_FIELD_POSITION>& aPositions )
87{
88 std::sort( aPositions.begin(), aPositions.end(),
89 []( const DRC_RE_FIELD_POSITION& a, const DRC_RE_FIELD_POSITION& b )
90 {
91 return a.tabOrder < b.tabOrder;
92 } );
93}
94
95} // namespace BITMAP_OVERLAY_TEST_HELPERS
96
97
98BOOST_AUTO_TEST_SUITE( DrcBitmapOverlayPanel )
99
100
101// ============================================================================
102// T025: ScalePosition Tests
103// ============================================================================
104
105BOOST_AUTO_TEST_CASE( ScalePosition_1x )
106{
107 using namespace BITMAP_OVERLAY_TEST_HELPERS;
108
109 double scale = 1.0;
110
111 // Test various positions at 1x scale
112 wxPoint result1 = ScalePosition( 0, 0, scale );
113 BOOST_CHECK_EQUAL( result1.x, 0 );
114 BOOST_CHECK_EQUAL( result1.y, 0 );
115
116 wxPoint result2 = ScalePosition( 100, 50, scale );
117 BOOST_CHECK_EQUAL( result2.x, 100 );
118 BOOST_CHECK_EQUAL( result2.y, 50 );
119
120 wxPoint result3 = ScalePosition( 256, 128, scale );
121 BOOST_CHECK_EQUAL( result3.x, 256 );
122 BOOST_CHECK_EQUAL( result3.y, 128 );
123
124 // Test edge case with odd numbers
125 wxPoint result4 = ScalePosition( 127, 63, scale );
126 BOOST_CHECK_EQUAL( result4.x, 127 );
127 BOOST_CHECK_EQUAL( result4.y, 63 );
128}
129
130
131BOOST_AUTO_TEST_CASE( ScalePosition_1_5x )
132{
133 using namespace BITMAP_OVERLAY_TEST_HELPERS;
134
135 double scale = 1.5;
136
137 // Test various positions at 1.5x scale
138 wxPoint result1 = ScalePosition( 0, 0, scale );
139 BOOST_CHECK_EQUAL( result1.x, 0 );
140 BOOST_CHECK_EQUAL( result1.y, 0 );
141
142 wxPoint result2 = ScalePosition( 100, 50, scale );
143 BOOST_CHECK_EQUAL( result2.x, 150 );
144 BOOST_CHECK_EQUAL( result2.y, 75 );
145
146 wxPoint result3 = ScalePosition( 200, 100, scale );
147 BOOST_CHECK_EQUAL( result3.x, 300 );
148 BOOST_CHECK_EQUAL( result3.y, 150 );
149
150 // Test truncation behavior with odd numbers
151 wxPoint result4 = ScalePosition( 127, 63, scale );
152 BOOST_CHECK_EQUAL( result4.x, static_cast<int>( 127 * 1.5 ) ); // 190
153 BOOST_CHECK_EQUAL( result4.y, static_cast<int>( 63 * 1.5 ) ); // 94
154}
155
156
157BOOST_AUTO_TEST_CASE( ScalePosition_2x )
158{
159 using namespace BITMAP_OVERLAY_TEST_HELPERS;
160
161 double scale = 2.0;
162
163 // Test various positions at 2x scale
164 wxPoint result1 = ScalePosition( 0, 0, scale );
165 BOOST_CHECK_EQUAL( result1.x, 0 );
166 BOOST_CHECK_EQUAL( result1.y, 0 );
167
168 wxPoint result2 = ScalePosition( 100, 50, scale );
169 BOOST_CHECK_EQUAL( result2.x, 200 );
170 BOOST_CHECK_EQUAL( result2.y, 100 );
171
172 wxPoint result3 = ScalePosition( 256, 128, scale );
173 BOOST_CHECK_EQUAL( result3.x, 512 );
174 BOOST_CHECK_EQUAL( result3.y, 256 );
175
176 // Test that coordinates double exactly
177 wxPoint result4 = ScalePosition( 127, 63, scale );
178 BOOST_CHECK_EQUAL( result4.x, 254 );
179 BOOST_CHECK_EQUAL( result4.y, 126 );
180}
181
182
183BOOST_AUTO_TEST_CASE( ScaleSize_AllFactors )
184{
185 using namespace BITMAP_OVERLAY_TEST_HELPERS;
186
187 // Test size scaling at all three scale factors
188 int width = 80;
189 int height = 24;
190
191 wxSize size1x = ScaleSize( width, height, 1.0 );
192 BOOST_CHECK_EQUAL( size1x.GetWidth(), 80 );
193 BOOST_CHECK_EQUAL( size1x.GetHeight(), 24 );
194
195 wxSize size1_5x = ScaleSize( width, height, 1.5 );
196 BOOST_CHECK_EQUAL( size1_5x.GetWidth(), 120 );
197 BOOST_CHECK_EQUAL( size1_5x.GetHeight(), 36 );
198
199 wxSize size2x = ScaleSize( width, height, 2.0 );
200 BOOST_CHECK_EQUAL( size2x.GetWidth(), 160 );
201 BOOST_CHECK_EQUAL( size2x.GetHeight(), 48 );
202}
203
204
205// ============================================================================
206// T026: GetScaleFactor Tests
207// ============================================================================
208
209BOOST_AUTO_TEST_CASE( GetScaleFactor_Returns1x_ForLowDPI )
210{
211 using namespace BITMAP_OVERLAY_TEST_HELPERS;
212
213 // Values below 1.25 should return 1.0
217 BOOST_CHECK_EQUAL( ComputeScaleFactor( 1.249 ), 1.0 );
218
219 // Edge case at boundary (1.25 should NOT return 1.0)
220 BOOST_CHECK( ComputeScaleFactor( 1.25 ) != 1.0 );
221}
222
223
224BOOST_AUTO_TEST_CASE( GetScaleFactor_Returns1_5x_ForMediumDPI )
225{
226 using namespace BITMAP_OVERLAY_TEST_HELPERS;
227
228 // Values at or above 1.25 but below 1.75 should return 1.5
232 BOOST_CHECK_EQUAL( ComputeScaleFactor( 1.749 ), 1.5 );
233
234 // Edge case at boundary (1.75 should NOT return 1.5)
235 BOOST_CHECK( ComputeScaleFactor( 1.75 ) != 1.5 );
236}
237
238
239BOOST_AUTO_TEST_CASE( GetScaleFactor_Returns2x_ForHighDPI )
240{
241 using namespace BITMAP_OVERLAY_TEST_HELPERS;
242
243 // Values at or above 1.75 should return 2.0
248}
249
250
251BOOST_AUTO_TEST_CASE( GetScaleFactor_BoundaryValues )
252{
253 using namespace BITMAP_OVERLAY_TEST_HELPERS;
254
255 // Test exact boundary values
256 BOOST_CHECK_EQUAL( ComputeScaleFactor( 1.24999 ), 1.0 );
258 BOOST_CHECK_EQUAL( ComputeScaleFactor( 1.74999 ), 1.5 );
260}
261
262
263// ============================================================================
264// T027: Tab Order Sorting Tests
265// ============================================================================
266
267BOOST_AUTO_TEST_CASE( TabOrderSorting_AlreadySorted )
268{
269 using namespace BITMAP_OVERLAY_TEST_HELPERS;
270
271 std::vector<DRC_RE_FIELD_POSITION> fields = {
272 { 10, 50, 20, 1 }, // tabOrder = 1
273 { 60, 100, 20, 2 }, // tabOrder = 2
274 { 110, 150, 20, 3 } // tabOrder = 3
275 };
276
277 SortByTabOrder( fields );
278
279 BOOST_CHECK_EQUAL( fields[0].tabOrder, 1 );
280 BOOST_CHECK_EQUAL( fields[1].tabOrder, 2 );
281 BOOST_CHECK_EQUAL( fields[2].tabOrder, 3 );
282}
283
284
285BOOST_AUTO_TEST_CASE( TabOrderSorting_ReversedOrder )
286{
287 using namespace BITMAP_OVERLAY_TEST_HELPERS;
288
289 std::vector<DRC_RE_FIELD_POSITION> fields = {
290 { 10, 50, 20, 3 }, // tabOrder = 3
291 { 60, 100, 20, 2 }, // tabOrder = 2
292 { 110, 150, 20, 1 } // tabOrder = 1
293 };
294
295 SortByTabOrder( fields );
296
297 BOOST_CHECK_EQUAL( fields[0].tabOrder, 1 );
298 BOOST_CHECK_EQUAL( fields[1].tabOrder, 2 );
299 BOOST_CHECK_EQUAL( fields[2].tabOrder, 3 );
300
301 // Verify the associated coordinates moved with the tab order
302 BOOST_CHECK_EQUAL( fields[0].xStart, 110 ); // Was originally tabOrder 1
303 BOOST_CHECK_EQUAL( fields[1].xStart, 60 ); // Was originally tabOrder 2
304 BOOST_CHECK_EQUAL( fields[2].xStart, 10 ); // Was originally tabOrder 3
305}
306
307
308BOOST_AUTO_TEST_CASE( TabOrderSorting_MixedOrder )
309{
310 using namespace BITMAP_OVERLAY_TEST_HELPERS;
311
312 std::vector<DRC_RE_FIELD_POSITION> fields = {
313 { 10, 50, 20, 5 },
314 { 60, 100, 40, 1 },
315 { 110, 150, 60, 3 },
316 { 160, 200, 80, 2 },
317 { 210, 250, 100, 4 }
318 };
319
320 SortByTabOrder( fields );
321
322 BOOST_CHECK_EQUAL( fields[0].tabOrder, 1 );
323 BOOST_CHECK_EQUAL( fields[1].tabOrder, 2 );
324 BOOST_CHECK_EQUAL( fields[2].tabOrder, 3 );
325 BOOST_CHECK_EQUAL( fields[3].tabOrder, 4 );
326 BOOST_CHECK_EQUAL( fields[4].tabOrder, 5 );
327}
328
329
330BOOST_AUTO_TEST_CASE( TabOrderSorting_DuplicateOrders )
331{
332 using namespace BITMAP_OVERLAY_TEST_HELPERS;
333
334 // Duplicate tab orders should maintain relative position (stable sort behavior)
335 std::vector<DRC_RE_FIELD_POSITION> fields = {
336 { 10, 50, 20, 2 },
337 { 60, 100, 40, 1 },
338 { 110, 150, 60, 2 }, // Duplicate tabOrder = 2
339 { 160, 200, 80, 1 } // Duplicate tabOrder = 1
340 };
341
342 SortByTabOrder( fields );
343
344 // All tabOrder 1 fields should come before tabOrder 2 fields
345 BOOST_CHECK_EQUAL( fields[0].tabOrder, 1 );
346 BOOST_CHECK_EQUAL( fields[1].tabOrder, 1 );
347 BOOST_CHECK_EQUAL( fields[2].tabOrder, 2 );
348 BOOST_CHECK_EQUAL( fields[3].tabOrder, 2 );
349}
350
351
352BOOST_AUTO_TEST_CASE( TabOrderSorting_SingleField )
353{
354 using namespace BITMAP_OVERLAY_TEST_HELPERS;
355
356 std::vector<DRC_RE_FIELD_POSITION> fields = { { 10, 50, 20, 1 } };
357
358 SortByTabOrder( fields );
359
360 BOOST_CHECK_EQUAL( fields.size(), 1 );
361 BOOST_CHECK_EQUAL( fields[0].tabOrder, 1 );
362}
363
364
365BOOST_AUTO_TEST_CASE( TabOrderSorting_EmptyVector )
366{
367 using namespace BITMAP_OVERLAY_TEST_HELPERS;
368
369 std::vector<DRC_RE_FIELD_POSITION> fields;
370
371 SortByTabOrder( fields );
372
373 BOOST_CHECK( fields.empty() );
374}
375
376
377// ============================================================================
378// T028: Bounds Warning Tests
379// ============================================================================
380
381BOOST_AUTO_TEST_CASE( BoundsWarning_WithinBounds )
382{
383 using namespace BITMAP_OVERLAY_TEST_HELPERS;
384
385 wxSize bitmapSize( 300, 200 );
386
387 // Field completely within bounds
388 wxPoint pos1( 10, 10 );
389 wxSize size1( 80, 24 );
390 BOOST_CHECK( !IsOutOfBounds( pos1, size1, bitmapSize ) );
391
392 // Field at edge of bounds (exactly fitting)
393 wxPoint pos2( 220, 176 );
394 wxSize size2( 80, 24 );
395 BOOST_CHECK( !IsOutOfBounds( pos2, size2, bitmapSize ) );
396
397 // Field at origin
398 wxPoint pos3( 0, 0 );
399 wxSize size3( 100, 50 );
400 BOOST_CHECK( !IsOutOfBounds( pos3, size3, bitmapSize ) );
401}
402
403
404BOOST_AUTO_TEST_CASE( BoundsWarning_ExceedsWidth )
405{
406 using namespace BITMAP_OVERLAY_TEST_HELPERS;
407
408 wxSize bitmapSize( 300, 200 );
409
410 // Field exceeds right edge
411 wxPoint pos( 250, 10 );
412 wxSize size( 80, 24 );
413
414 BOOST_CHECK( IsOutOfBounds( pos, size, bitmapSize ) );
415}
416
417
418BOOST_AUTO_TEST_CASE( BoundsWarning_ExceedsHeight )
419{
420 using namespace BITMAP_OVERLAY_TEST_HELPERS;
421
422 wxSize bitmapSize( 300, 200 );
423
424 // Field exceeds bottom edge
425 wxPoint pos( 10, 180 );
426 wxSize size( 80, 30 );
427
428 BOOST_CHECK( IsOutOfBounds( pos, size, bitmapSize ) );
429}
430
431
432BOOST_AUTO_TEST_CASE( BoundsWarning_ExceedsBothDimensions )
433{
434 using namespace BITMAP_OVERLAY_TEST_HELPERS;
435
436 wxSize bitmapSize( 300, 200 );
437
438 // Field exceeds both edges
439 wxPoint pos( 250, 180 );
440 wxSize size( 80, 30 );
441
442 BOOST_CHECK( IsOutOfBounds( pos, size, bitmapSize ) );
443}
444
445
446BOOST_AUTO_TEST_CASE( BoundsWarning_FieldLargerThanBitmap )
447{
448 using namespace BITMAP_OVERLAY_TEST_HELPERS;
449
450 wxSize bitmapSize( 300, 200 );
451
452 // Field larger than entire bitmap
453 wxPoint pos( 0, 0 );
454 wxSize size( 400, 300 );
455
456 BOOST_CHECK( IsOutOfBounds( pos, size, bitmapSize ) );
457}
458
459
460BOOST_AUTO_TEST_CASE( BoundsWarning_AtScaledPositions )
461{
462 using namespace BITMAP_OVERLAY_TEST_HELPERS;
463
464 // Simulate a field at 1x coordinates that fits, but may not fit when scaled
465 int baseX = 250;
466 int baseY = 180;
467 int baseWidth = 40;
468 int baseHeight = 15;
469
470 // At 1x, bitmap is 300x200
471 wxSize bitmap1x( 300, 200 );
472 wxPoint pos1x = ScalePosition( baseX, baseY, 1.0 );
473 wxSize size1x = ScaleSize( baseWidth, baseHeight, 1.0 );
474 BOOST_CHECK( !IsOutOfBounds( pos1x, size1x, bitmap1x ) );
475
476 // At 1.5x, bitmap becomes 450x300
477 wxSize bitmap1_5x( 450, 300 );
478 wxPoint pos1_5x = ScalePosition( baseX, baseY, 1.5 );
479 wxSize size1_5x = ScaleSize( baseWidth, baseHeight, 1.5 );
480 BOOST_CHECK( !IsOutOfBounds( pos1_5x, size1_5x, bitmap1_5x ) );
481
482 // At 2x, bitmap becomes 600x400
483 wxSize bitmap2x( 600, 400 );
484 wxPoint pos2x = ScalePosition( baseX, baseY, 2.0 );
485 wxSize size2x = ScaleSize( baseWidth, baseHeight, 2.0 );
486 BOOST_CHECK( !IsOutOfBounds( pos2x, size2x, bitmap2x ) );
487}
488
489
490BOOST_AUTO_TEST_CASE( BoundsWarning_EdgeCases )
491{
492 using namespace BITMAP_OVERLAY_TEST_HELPERS;
493
494 wxSize bitmapSize( 300, 200 );
495
496 // Field exactly at boundary (should be within bounds)
497 wxPoint posExact( 220, 176 );
498 wxSize sizeExact( 80, 24 );
499 BOOST_CHECK( !IsOutOfBounds( posExact, sizeExact, bitmapSize ) );
500
501 // Field 1 pixel over width
502 wxPoint posOverWidth( 221, 176 );
503 BOOST_CHECK( IsOutOfBounds( posOverWidth, sizeExact, bitmapSize ) );
504
505 // Field 1 pixel over height
506 wxPoint posOverHeight( 220, 177 );
507 BOOST_CHECK( IsOutOfBounds( posOverHeight, sizeExact, bitmapSize ) );
508}
509
510
511BOOST_AUTO_TEST_CASE( BoundsWarning_ZeroSizedField )
512{
513 using namespace BITMAP_OVERLAY_TEST_HELPERS;
514
515 wxSize bitmapSize( 300, 200 );
516
517 // Zero-sized field should never be out of bounds
518 wxPoint pos( 0, 0 );
519 wxSize zeroSize( 0, 0 );
520 BOOST_CHECK( !IsOutOfBounds( pos, zeroSize, bitmapSize ) );
521
522 // Zero-sized field at edge
523 wxPoint posEdge( 300, 200 );
524 BOOST_CHECK( !IsOutOfBounds( posEdge, zeroSize, bitmapSize ) );
525}
526
527
Helper functions that mirror the logic from DRC_RE_BITMAP_OVERLAY_PANEL.
void SortByTabOrder(std::vector< DRC_RE_FIELD_POSITION > &aPositions)
Sort field positions by tab order.
wxSize ScaleSize(int aWidth, int aHeight, double aScaleFactor)
Scale a size from 1x bitmap coordinates to display coordinates.
wxPoint ScalePosition(int aX, int aY, double aScaleFactor)
Scale a position from 1x bitmap coordinates to display coordinates.
double ComputeScaleFactor(double aRawScale)
Compute the scale factor from a raw content scale factor.
bool IsOutOfBounds(const wxPoint &aScaledPos, const wxSize &aScaledSize, const wxSize &aBitmapSize)
Check if a field position exceeds bitmap bounds.
const int scale
Specifies the position and size of a field overlaid on a constraint bitmap.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_CASE(ScalePosition_1x)
BOOST_AUTO_TEST_SUITE_END()
BOOST_CHECK_EQUAL(result, "25.4")