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