KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_pcb_grid_helper.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 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#define BOOST_TEST_NO_MAIN
19#include <boost/test/unit_test.hpp>
20
22#include <geometry/seg.h>
23#include <geometry/shape_arc.h>
24#include <footprint.h>
25#include <pad.h>
26#include <pcb_shape.h>
27#include <pcb_track.h>
28#include <zone.h>
29#include <pcb_text.h>
30
31// Mock EDA_ITEM class for testing GetItemGrid
33{
34public:
35 MOCK_BOARD_ITEM( KICAD_T aType ) : BOARD_ITEM( nullptr, aType ) {}
36
37 // Required virtual functions
38 wxString GetClass() const override { return "MockEDAItem"; }
39 void Move( const VECTOR2I& aMoveVector ) override {}
40 VECTOR2I GetPosition() const override { return VECTOR2I( 0, 0 ); }
41 void SetPosition( const VECTOR2I& aPos ) override {}
42 BOARD_ITEM* Clone() const override { return new MOCK_BOARD_ITEM( Type() ); }
43
44 // Implement pure virtuals from BOARD_ITEM
45 double Similarity( const BOARD_ITEM& aItem ) const override { return this == &aItem ? 1.0 : 0.0; }
46 bool operator==( const BOARD_ITEM& aItem ) const override { return this == &aItem; }
47};
48
49// Test fixture for accessing protected members
51{
52public:
54 {
55 helper.SetGridSize( VECTOR2D( 100, 100 ) );
56 helper.SetOrigin( VECTOR2I( 0, 0 ) );
57 helper.SetGridSnapping( true );
58 helper.SetSnap( true );
59 }
60
62};
63
64BOOST_AUTO_TEST_SUITE( PCBGridHelperTest )
65
66BOOST_AUTO_TEST_CASE( DefaultConstructor )
67{
68 PCB_GRID_HELPER helper;
69
70 // Test default state matches base class
71 BOOST_CHECK( helper.GetSnap() );
72 BOOST_CHECK( helper.GetUseGrid() );
73
74 // Test that GetSnapped returns nullptr initially
75 BOOST_CHECK( helper.GetSnapped() == nullptr );
76}
77
78BOOST_AUTO_TEST_CASE( AlignToSegmentBasic )
79{
80 PCB_GRID_HELPER helper;
81 helper.SetGridSize( VECTOR2D( 100, 100 ) );
82 helper.SetOrigin( VECTOR2I( 0, 0 ) );
83 helper.SetGridSnapping( true );
84
85 // Horizontal segment
86 SEG seg( VECTOR2I( 0, 0 ), VECTOR2I( 300, 0 ) );
87 VECTOR2I result = helper.AlignToSegment( VECTOR2I( 150, 50 ), seg );
88
89 // Should snap to grid point that intersects with segment
90 BOOST_CHECK_EQUAL( result.x, 200 );
91 BOOST_CHECK_EQUAL( result.y, 0 );
92}
93
94BOOST_AUTO_TEST_CASE( AlignToSegmentVertical )
95{
96 PCB_GRID_HELPER helper;
97 helper.SetGridSize( VECTOR2D( 100, 100 ) );
98 helper.SetOrigin( VECTOR2I( 0, 0 ) );
99 helper.SetGridSnapping( true );
100
101 // Vertical segment
102 SEG seg( VECTOR2I( 200, 0 ), VECTOR2I( 200, 400 ) );
103 VECTOR2I result = helper.AlignToSegment( VECTOR2I( 150, 150 ), seg );
104
105 // Should snap to intersection with vertical line
106 BOOST_CHECK_EQUAL( result.x, 200 );
107 BOOST_CHECK_EQUAL( result.y, 200 );
108}
109
110BOOST_AUTO_TEST_CASE( AlignToSegmentDiagonal )
111{
112 PCB_GRID_HELPER helper;
113 helper.SetGridSize( VECTOR2D( 100, 100 ) );
114 helper.SetOrigin( VECTOR2I( 0, 0 ) );
115 helper.SetGridSnapping( true );
116
117 // Diagonal segment
118 SEG seg( VECTOR2I( 0, 0 ), VECTOR2I( 400, 400 ) );
119 VECTOR2I result = helper.AlignToSegment( VECTOR2I( 150, 250 ), seg );
120
121 // 250,250 is the closest point to the nearest grid point to the segment.
122 // First, it snaps to grid point (200, 300) and then finds the closest point on the segment.
123 // So the result should be (250, 250).
124 BOOST_CHECK_EQUAL( result.x, 250 );
125 BOOST_CHECK_EQUAL( result.y, 250 );
126}
127
128BOOST_AUTO_TEST_CASE( AlignToSegmentEndpoints )
129{
130 PCB_GRID_HELPER helper;
131 helper.SetGridSize( VECTOR2D( 100, 100 ) );
132 helper.SetOrigin( VECTOR2I( 0, 0 ) );
133 helper.SetGridSnapping( true );
134
135 SEG seg( VECTOR2I( 50, 50 ), VECTOR2I( 150, 50 ) );
136
137 // Point very close to start endpoint
138 VECTOR2I result = helper.AlignToSegment( VECTOR2I( 55, 55 ), seg );
139 BOOST_CHECK_EQUAL( result.x, 50 );
140 BOOST_CHECK_EQUAL( result.y, 50 );
141
142 // Point very close to end endpoint
143 result = helper.AlignToSegment( VECTOR2I( 145, 55 ), seg );
144 BOOST_CHECK_EQUAL( result.x, 150 );
145 BOOST_CHECK_EQUAL( result.y, 50 );
146}
147
148BOOST_AUTO_TEST_CASE( AlignToSegmentSnapDisabled )
149{
150 PCB_GRID_HELPER helper;
151 helper.SetGridSize( VECTOR2D( 100, 100 ) );
152 helper.SetOrigin( VECTOR2I( 0, 0 ) );
153 helper.SetGridSnapping( true );
154 helper.SetSnap( false ); // Disable snapping
155
156 SEG seg( VECTOR2I( 0, 0 ), VECTOR2I( 300, 0 ) );
157 VECTOR2I point( 150, 50 );
158 VECTOR2I result = helper.AlignToSegment( point, seg );
159
160 // Should return grid-aligned point when snap is disabled
161 VECTOR2I expected = helper.Align( point );
162 BOOST_CHECK_EQUAL( result.x, expected.x );
163 BOOST_CHECK_EQUAL( result.y, expected.y );
164}
165
166BOOST_AUTO_TEST_CASE( AlignToArcBasic )
167{
168 PCB_GRID_HELPER helper;
169 helper.SetGridSize( VECTOR2D( 100, 100 ) );
170 helper.SetOrigin( VECTOR2I( 0, 0 ) );
171 helper.SetGridSnapping( true );
172
173 // Create a simple arc (quarter circle)
174 SHAPE_ARC arc( VECTOR2I( 100, 0 ), VECTOR2I( 0, 100 ), ANGLE_90 );
175
176 VECTOR2I result = helper.AlignToArc( VECTOR2I( 50, 50 ), arc );
177
178 // Should snap to arc endpoints or intersections
179 BOOST_CHECK( result.x >= 0 );
180 BOOST_CHECK( result.y >= 0 );
181}
182
183// TODO: Fix broken AlignToArc Routine
184// BOOST_AUTO_TEST_CASE( AlignToArcEndpoints )
185// {
186// PCB_GRID_HELPER helper;
187// helper.SetGridSize( VECTOR2D( 100, 100 ) );
188// helper.SetOrigin( VECTOR2I( 0, 0 ) );
189// helper.SetGridSnapping( true );
190
191// SHAPE_ARC arc( VECTOR2I( 100, 0 ), VECTOR2I( 65, 65 ), VECTOR2I( 0, 100 ), 0 );
192
193// // Point close to start
194// VECTOR2I result = helper.AlignToArc( VECTOR2I( 95, 5 ), arc );
195// BOOST_CHECK_EQUAL( result.x, arc.GetP0().x );
196// BOOST_CHECK_EQUAL( result.y, arc.GetP0().y );
197
198// // Point close to end
199// result = helper.AlignToArc( VECTOR2I( 5, 95 ), arc );
200// BOOST_CHECK_EQUAL( result.x, arc.GetP1().x );
201// BOOST_CHECK_EQUAL( result.y, arc.GetP1().y );
202// }
203
204BOOST_AUTO_TEST_CASE( AlignToArcSnapDisabled )
205{
206 PCB_GRID_HELPER helper;
207 helper.SetGridSize( VECTOR2D( 100, 100 ) );
208 helper.SetOrigin( VECTOR2I( 0, 0 ) );
209 helper.SetGridSnapping( true );
210 helper.SetSnap( false ); // Disable snapping
211
212 SHAPE_ARC arc( VECTOR2I( 100, 0 ), VECTOR2I( 0, 100 ), ANGLE_90 );
213 VECTOR2I point( 50, 50 );
214 VECTOR2I result = helper.AlignToArc( point, arc );
215
216 // Should return grid-aligned point when snap is disabled
217 VECTOR2I expected = helper.Align( point );
218 BOOST_CHECK_EQUAL( result.x, expected.x );
219 BOOST_CHECK_EQUAL( result.y, expected.y );
220}
221
222BOOST_AUTO_TEST_CASE( GetItemGridFootprint )
223{
224 PCB_GRID_HELPER helper;
225
226 MOCK_BOARD_ITEM footprint( PCB_FOOTPRINT_T );
227 GRID_HELPER_GRIDS grid = helper.GetItemGrid( &footprint );
229}
230
231BOOST_AUTO_TEST_CASE( GetItemGridPad )
232{
233 PCB_GRID_HELPER helper;
234
238}
239
240BOOST_AUTO_TEST_CASE( GetItemGridText )
241{
242 PCB_GRID_HELPER helper;
243
247
249 grid = helper.GetItemGrid( &field );
251}
252
253BOOST_AUTO_TEST_CASE( GetItemGridGraphics )
254{
255 PCB_GRID_HELPER helper;
256
258 GRID_HELPER_GRIDS grid = helper.GetItemGrid( &shape );
260
261 MOCK_BOARD_ITEM dimension( PCB_DIMENSION_T );
262 grid = helper.GetItemGrid( &dimension );
264
266 grid = helper.GetItemGrid( &refImage );
268
270 grid = helper.GetItemGrid( &textbox );
272}
273
274BOOST_AUTO_TEST_CASE( GetItemGridTracks )
275{
276 PCB_GRID_HELPER helper;
277
279 GRID_HELPER_GRIDS grid = helper.GetItemGrid( &trace );
281
283 grid = helper.GetItemGrid( &arc );
285}
286
287BOOST_AUTO_TEST_CASE( GetItemGridVias )
288{
289 PCB_GRID_HELPER helper;
290
294}
295
296BOOST_AUTO_TEST_CASE( GetItemGridDefault )
297{
298 PCB_GRID_HELPER helper;
299
300 // Test with unknown item type
304
305 // Test with nullptr
306 grid = helper.GetItemGrid( nullptr );
308}
309
310BOOST_AUTO_TEST_CASE( GetSnappedInitiallyNull )
311{
312 PCB_GRID_HELPER helper;
313
314 BOARD_ITEM* snapped = helper.GetSnapped();
315 BOOST_CHECK( snapped == nullptr );
316}
317
318BOOST_AUTO_TEST_CASE( OnBoardItemRemovedClearsSnap )
319{
320 PCB_GRID_HELPER helper;
321
322 // Create a mock board and item - this test verifies the interface exists
323 // In a real scenario, the snap item would be set by other operations
324 BOARD board;
326
327 // This should not crash even if no snap item is set
328 helper.OnBoardItemRemoved( board, static_cast<BOARD_ITEM*>( &item ) );
329
330 BOOST_CHECK( helper.GetSnapped() == nullptr );
331}
332
333
334BOOST_AUTO_TEST_CASE( GeometricSnapTolerance )
335{
336 PCB_GRID_HELPER helper;
337 helper.SetGridSize( VECTOR2D( 100, 100 ) );
338 helper.SetOrigin( VECTOR2I( 0, 0 ) );
339 helper.SetGridSnapping( true );
340
341 SEG seg( VECTOR2I( 0, 0 ), VECTOR2I( 200, 0 ) );
342
343 // Test that points very far from segment don't snap to unrealistic locations
344 VECTOR2I result = helper.AlignToSegment( VECTOR2I( 50, 100000 ), seg );
345
346 // Should snap to midpoint of segment
347 BOOST_CHECK( result == VECTOR2I( 100, 0 ) );
348}
349
350BOOST_AUTO_TEST_CASE( SegmentIntersectionPriority )
351{
352 PCB_GRID_HELPER helper;
353 helper.SetGridSize( VECTOR2D( 50, 50 ) );
354 helper.SetOrigin( VECTOR2I( 0, 0 ) );
355 helper.SetGridSnapping( true );
356
357 // Segment that passes through a grid point
358 SEG seg( VECTOR2I( 0, 25 ), VECTOR2I( 100, 25 ) );
359
360 // Point near a grid intersection with the segment
361 VECTOR2I result = helper.AlignToSegment( VECTOR2I( 48, 27 ), seg );
362
363 // Should snap to the intersection at (50, 25)
364 BOOST_CHECK_EQUAL( result.x, 50 );
365 BOOST_CHECK_EQUAL( result.y, 25 );
366}
367
368BOOST_AUTO_TEST_CASE( ArcIntersectionWithGrid )
369{
370 PCB_GRID_HELPER helper;
371 helper.SetGridSize( VECTOR2D( 50, 50 ) );
372 helper.SetOrigin( VECTOR2I( 0, 0 ) );
373 helper.SetGridSnapping( true );
374
375 // Arc that should intersect grid lines
376 SHAPE_ARC arc( VECTOR2I( 50, 0 ), VECTOR2I( 50, 50 ), VECTOR2I( 0, 50 ), 0 );
377
378 // Point that should snap to an intersection
379 VECTOR2I result = helper.AlignToArc( VECTOR2I( 25, 25 ), arc );
380
381 // Should snap to the mid point of the arc
382 BOOST_CHECK_EQUAL( result.x, 50 );
383 BOOST_CHECK_EQUAL( result.y, 50 );
384}
385
387{
388 // Test with larger grid to verify scaling behavior
389 helper.SetGridSize( VECTOR2D( 1000, 1000 ) );
390
391 SEG seg( VECTOR2I( 500, 0 ), VECTOR2I( 500, 2000 ) );
392 VECTOR2I result = helper.AlignToSegment( VECTOR2I( 400, 800 ), seg );
393
394 // Should snap to the segment at grid intersection
395 BOOST_CHECK_EQUAL( result.x, 500 );
396 BOOST_CHECK_EQUAL( result.y, 1000 );
397}
398
400{
401 // Edge case: zero-length segment (point)
402 SEG seg( VECTOR2I( 100, 100 ), VECTOR2I( 100, 100 ) );
403 VECTOR2I result = helper.AlignToSegment( VECTOR2I( 95, 95 ), seg );
404
405 // Should snap to the point itself
406 BOOST_CHECK_EQUAL( result.x, 100 );
407 BOOST_CHECK_EQUAL( result.y, 100 );
408}
409
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:79
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:317
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:110
bool GetSnap() const
Definition: grid_helper.h:119
void SetSnap(bool aSnap)
Definition: grid_helper.h:118
bool GetUseGrid() const
Definition: grid_helper.h:122
void SetOrigin(const VECTOR2I &aOrigin)
Definition: grid_helper.h:69
void SetGridSnapping(bool aEnable)
Definition: grid_helper.h:70
void SetGridSize(const VECTOR2D &aGrid)
Definition: grid_helper.h:67
wxString GetClass() const override
Return the class name.
MOCK_BOARD_ITEM(KICAD_T aType)
VECTOR2I GetPosition() const override
void Move(const VECTOR2I &aMoveVector) override
Move this object.
BOARD_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
double Similarity(const BOARD_ITEM &aItem) const override
Return a measure of how likely the other object is to represent the same object.
void SetPosition(const VECTOR2I &aPos) override
bool operator==(const BOARD_ITEM &aItem) const override
VECTOR2I AlignToArc(const VECTOR2I &aPoint, const SHAPE_ARC &aSeg)
virtual void OnBoardItemRemoved(BOARD &aBoard, BOARD_ITEM *aBoardItem) override
BOARD_ITEM * GetSnapped() const
Function GetSnapped If the PCB_GRID_HELPER has highlighted a snap point (target shown),...
GRID_HELPER_GRIDS GetItemGrid(const EDA_ITEM *aItem) const override
Get the coarsest grid that applies to an item.
VECTOR2I AlignToSegment(const VECTOR2I &aPoint, const SEG &aSeg)
virtual VECTOR2I Align(const VECTOR2I &aPoint, GRID_HELPER_GRIDS aGrid) const
Definition: grid_helper.h:74
Definition: seg.h:42
T y
Definition: vector3.h:64
T x
Definition: vector3.h:63
static constexpr EDA_ANGLE ANGLE_90
Definition: eda_angle.h:413
GRID_HELPER_GRIDS
Definition: grid_helper.h:43
@ GRID_VIAS
Definition: grid_helper.h:49
@ GRID_TEXT
Definition: grid_helper.h:50
@ GRID_CURRENT
Definition: grid_helper.h:45
@ GRID_GRAPHICS
Definition: grid_helper.h:51
@ GRID_CONNECTABLE
Definition: grid_helper.h:47
@ GRID_WIRES
Definition: grid_helper.h:48
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_CHECK_EQUAL(ret, c.m_exp_result)
BOOST_AUTO_TEST_SUITE_END()
VECTOR3I expected(15, 30, 45)
BOOST_FIXTURE_TEST_CASE(LargeGridSegmentSnap, PCBGridHelperTestFixture)
BOOST_AUTO_TEST_CASE(DefaultConstructor)
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:78
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:88
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition: typeinfo.h:93
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:107
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:92
@ PCB_REFERENCE_IMAGE_T
class PCB_REFERENCE_IMAGE, bitmap on a layer
Definition: typeinfo.h:89
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition: typeinfo.h:90
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition: typeinfo.h:86
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:98
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
Definition: typeinfo.h:100
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695
VECTOR2< double > VECTOR2D
Definition: vector2d.h:694