KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_footprint_realignment.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
21#include <boost/test/data/test_case.hpp>
22
23#include <optional>
24#include <ostream>
25#include <string>
26#include <utility>
27#include <vector>
28
29#include <footprint_utils.h>
30
31#include <board.h>
32#include <footprint.h>
33#include <pad.h>
34
35
40{
41 std::string m_name;
42 std::vector<std::pair<std::string, VECTOR2I>> m_pads;
43};
44
45
46std::ostream& operator<<( std::ostream& os, const ALIGN_FP_DEF& fpDef )
47{
48 os << "ALIGN_FP_DEF: " << fpDef.m_name;
49 return os;
50}
51
52
54{
55 std::string m_TestName;
58 std::optional<VECTOR2I> m_ExpectedPosShift;
59 std::optional<EDA_ANGLE> m_ExpectedAngleShift;
60
61 // Alls a data test case to print the name
62 friend std::ostream& operator<<( std::ostream& os, const FP_ALIGNMENT_TEST_CASE& testCase )
63 {
64 return os << testCase.m_TestName;
65 }
66};
67
68
70{
73
74 std::unique_ptr<FOOTPRINT> CreateFootprint( BOARD& aBoard, const ALIGN_FP_DEF& padPositions )
75 {
76 std::unique_ptr<FOOTPRINT> fp = std::make_unique<FOOTPRINT>( &aBoard );
77
78 for( const auto& [number, pos] : padPositions.m_pads )
79 {
80 PAD* pad = new PAD( fp.get() );
81 pad->SetNumber( number );
82 pad->SetFPRelativePosition( pos );
83 fp->Add( pad );
84 }
85
86 return fp;
87 }
88
89
90 void ExecuteTestCase( const FP_ALIGNMENT_TEST_CASE& testCase, bool originalFootprintIsFlipped )
91 {
92 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
93
94 const std::unique_ptr<FOOTPRINT> fpOrig = CreateFootprint( *board, testCase.m_OrigPadPositions );
95 const std::unique_ptr<FOOTPRINT> fpNew = CreateFootprint( *board, testCase.m_NewPadPositions );
96
97 if( originalFootprintIsFlipped )
98 fpOrig->Flip( fpOrig->GetPosition(), FLIP_DIRECTION::LEFT_RIGHT );
99
100 bool ok = ComputeFootprintShift( *fpOrig, *fpNew, m_PosShift, m_AngleShift );
101
102 if( testCase.m_ExpectedPosShift.has_value() && testCase.m_ExpectedAngleShift.has_value() )
103 {
104 BOOST_REQUIRE( ok );
105 BOOST_TEST( m_PosShift == testCase.m_ExpectedPosShift.value() );
106 BOOST_TEST( m_AngleShift == testCase.m_ExpectedAngleShift.value() );
107 }
108 else
109 {
110 BOOST_REQUIRE( !ok );
111 }
112
113 // Check that when the original footprint is rotated, we compute the same
114 // transform, but:
115 // - the move vector is rotated by the same angle
116 // - the angle shift is the same
117
118 fpOrig->SetOrientation( ANGLE_45 );
119
120 bool ok2 = ComputeFootprintShift( *fpOrig, *fpNew, m_PosShift, m_AngleShift );
121 if( testCase.m_ExpectedPosShift.has_value() && testCase.m_ExpectedAngleShift.has_value() )
122 {
123 VECTOR2I expectedPosShift = testCase.m_ExpectedPosShift.value();
124 RotatePoint( expectedPosShift, ANGLE_45 );
125
126 BOOST_REQUIRE( ok2 );
127 BOOST_TEST( m_PosShift == expectedPosShift );
128 BOOST_TEST( m_AngleShift == testCase.m_ExpectedAngleShift.value() );
129 }
130 else
131 {
132 BOOST_REQUIRE( !ok2 );
133 }
134 }
135};
136
137
139 "No pins",
140 {},
141};
142
143
145 "DIP4, pin 1 at origin",
146 {
147 { "1", { 0, 0 } },
148 { "2", { 0, 1000 } },
149 { "3", { 2000, 0 } },
150 { "4", { 2000, 1000 } },
151 },
152};
153
154
156 "DIP4, body center at origin",
157 {
158 { "1", { -1000, -500 } },
159 { "2", { -1000, 500 } },
160 { "3", { 1000, -500 } },
161 { "4", { 1000, 500 } },
162 },
163};
164
165
166// Pin 1 bottom left = Level B style
167// Rotated 90 degrees CCW around origin
169 "DIP4, rotated 90 deg CCW",
170 {
171 { "1", { 0, 0 } },
172 { "2", { 1000, 0 } },
173 { "3", { 1000, -2000 } },
174 { "4", { 0, -2000 } },
175 },
176};
177
178
180 "DIP4, body center at origin, rotated 90 deg CCW",
181 {
182 { "1", { -500, 1000 } },
183 { "2", { 500, 1000 } },
184 { "3", { 500, -1000 } },
185 { "4", { -500, -1000 } },
186 },
187};
188
189
191 "DIP4, pin 4 deleted",
192 {
193 { "1", { 0, 0 } },
194 { "2", { 0, 1000 } },
195 { "3", { 2000, 0 } },
196 },
197};
198
199
201 "DIP4, pin 4 moved",
202 {
203 { "1", { 0, 0 } },
204 { "2", { 0, 1000 } },
205 { "3", { 2000, 0 } },
206 { "4", { 2100, 1000 } },
207 },
208};
209
210
212 "DIP4, widened",
213 {
214 { "1", { 0, 0 } },
215 { "2", { 0, 1000 } },
216 { "3", { 2400, 0 } },
217 { "4", { 2400, 1000 } },
218 },
219};
220
221
223 "DIP4, with mechanical pins",
224 {
225 { "1", { 0, 0 } },
226 { "2", { 0, 1000 } },
227 { "3", { 2000, 0 } },
228 { "4", { 2000, 1000 } },
229 { "MP", { -1000, 500 } },
230 { "MP", { 3000, 500 } },
231 },
232};
233
234
245
246
247static const std::vector<SELF_ALIGNMENT_TEST_CASE> FpSelfToSelfCases = {
248 // No baseline, not enough information to align
249 { FpDef_NoPins, false },
250 { FpDef_DIP4_OrigPin1, true },
254 { FpDef_DIP4_Pin4Deleted, true },
255 { FpDef_DIP4_Pin4Moved, true },
256 { FpDef_DIP4_Widened, true },
257 { FpDef_DIP4_WithMPs, true },
258};
259
260
261std::ostream& operator<<( std::ostream& os, const SELF_ALIGNMENT_TEST_CASE& testCase )
262{
263 os << "SELF_ALIGNMENT_TEST_CASE: " << testCase.m_FpDef.m_name;
264 return os;
265}
266
267
268static const std::vector<FP_ALIGNMENT_TEST_CASE> FpAlignmentTestCases = {
269 {
270 "No pins",
273 std::nullopt,
274 std::nullopt,
275 },
276 {
277 "Origin point change",
280 VECTOR2I( 1000, 500 ),
281 ANGLE_0,
282 },
283 {
284 "Rotation",
287 VECTOR2I( 0, 0 ),
288 ANGLE_270,
289 },
290 {
291 "Rotation and origin point change",
294 VECTOR2I( 1000, 500 ),
295 ANGLE_270,
296 },
297 {
298 "Pin deleted",
301 VECTOR2I( 0, 0 ),
302 ANGLE_0,
303 },
304 {
305 "Pin moved",
308 VECTOR2I( 0, 0 ),
309 ANGLE_0,
310 },
311 {
312 "Footprint widened (all pins moved)",
315 VECTOR2I( -200, 0 ),
316 ANGLE_0,
317 },
318 {
319 "Ignore same named pads",
322 VECTOR2I( 0, 0 ),
323 ANGLE_0,
324 },
325};
326
327
328BOOST_FIXTURE_TEST_SUITE( FootprintRealignment, FP_REALIGNMENT_TEST_FIXTURE )
329
330
331BOOST_DATA_TEST_CASE( TestSelfToSelfCases,
332 boost::unit_test::data::make( FpSelfToSelfCases ),
333 selfCase )
334{
335 std::optional<VECTOR2I> expectedPosShift;
336 std::optional<EDA_ANGLE> expectedAngleShift;
337
338 // If the alignment can be computed, it's zero shift and zero rotation
339 if( selfCase.m_ExpectSuccess )
340 {
341 expectedPosShift = VECTOR2I( 0, 0 );
342 expectedAngleShift = ANGLE_0;
343 }
344
345 const FP_ALIGNMENT_TEST_CASE selfAlignTestCase = {
346 selfCase.m_FpDef.m_name + "-> " + selfCase.m_FpDef.m_name,
347 selfCase.m_FpDef,
348 selfCase.m_FpDef,
349 expectedPosShift,
350 expectedAngleShift,
351 };
352
353 // Check the front placements
354 BOOST_TEST_CONTEXT( "Front placement" )
355 {
356 ExecuteTestCase( selfAlignTestCase, false );
357 }
358
359 // And the back. Because we know the footprints are the same,
360 // we don't need to compensate for a flip in the transform (-0 == 0)
361 BOOST_TEST_CONTEXT( "Back placement" )
362 {
363 ExecuteTestCase( selfAlignTestCase, true );
364 }
365}
366
368 boost::unit_test::data::make( FpAlignmentTestCases ),
369 testCase )
370{
371 ExecuteTestCase( testCase, false );
372}
373
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:409
Definition pad.h:61
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:422
static constexpr EDA_ANGLE ANGLE_45
Definition eda_angle.h:423
static constexpr EDA_ANGLE ANGLE_270
Definition eda_angle.h:427
bool ComputeFootprintShift(const FOOTPRINT &aExisting, const FOOTPRINT &aNew, VECTOR2I &aShift, EDA_ANGLE &aAngleShift)
Compute position and angle shift between two footprints.
Collection of reusable/testable functions for footprint manipulation.
@ LEFT_RIGHT
Flip left to right (around the Y axis)
Definition mirror.h:24
Information needed to make a footprint to use for alignment tests.
std::vector< std::pair< std::string, VECTOR2I > > m_pads
std::optional< EDA_ANGLE > m_ExpectedAngleShift
const ALIGN_FP_DEF & m_OrigPadPositions
std::optional< VECTOR2I > m_ExpectedPosShift
friend std::ostream & operator<<(std::ostream &os, const FP_ALIGNMENT_TEST_CASE &testCase)
std::unique_ptr< FOOTPRINT > CreateFootprint(BOARD &aBoard, const ALIGN_FP_DEF &padPositions)
void ExecuteTestCase(const FP_ALIGNMENT_TEST_CASE &testCase, bool originalFootprintIsFlipped)
Definition of a test case for self-to-self alignment.
BOOST_DATA_TEST_CASE(ConvertToKicadUnit, boost::unit_test::data::make(altium_to_kicad_unit), input_value, expected_result)
Test conversation from Altium internal units into KiCad internal units.
static const std::vector< FP_ALIGNMENT_TEST_CASE > FpAlignmentTestCases
static const ALIGN_FP_DEF FpDef_DIP4_OrigBodyCenter
static const ALIGN_FP_DEF FpDef_DIP4_Rotated90DegCCW
static const std::vector< SELF_ALIGNMENT_TEST_CASE > FpSelfToSelfCases
static const ALIGN_FP_DEF FpDef_DIP4_OrigPin1
static const ALIGN_FP_DEF FpDef_DIP4_WithMPs
static const ALIGN_FP_DEF FpDef_DIP4_Pin4Deleted
static const ALIGN_FP_DEF FpDef_NoPins
static const ALIGN_FP_DEF FpDef_DIP4_Widened
static const ALIGN_FP_DEF FpDef_DIP4_OrigBodyCenter_Rotated90DegCCW
static const ALIGN_FP_DEF FpDef_DIP4_Pin4Moved
BOOST_DATA_TEST_CASE(TestSelfToSelfCases, boost::unit_test::data::make(FpSelfToSelfCases), selfCase)
std::ostream & operator<<(std::ostream &os, const ALIGN_FP_DEF &fpDef)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_TEST(netlist.find("R_G1 ARM_OUT1 DIE_B R='0.001 / ((SW_STATE)") !=std::string::npos)
BOOST_TEST_CONTEXT("Test Clearance")
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:225
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683