KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_multichannel.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
26#include <board.h>
28#include <pad.h>
29#include <pcb_track.h>
30#include <pcb_text.h>
31#include <pcb_field.h>
32#include <footprint.h>
33#include <zone.h>
34#include <drc/drc_item.h>
38#include <lib_id.h>
39
47
49{
50public:
53
54 virtual wxWindow* GetToolCanvas() const override { return nullptr; }
55};
56
57BOOST_FIXTURE_TEST_SUITE( MultichannelTool, MULTICHANNEL_TEST_FIXTURE )
58
59RULE_AREA* findRuleAreaByPartialName( MULTICHANNEL_TOOL* aTool, const wxString& aName )
60{
61 for( RULE_AREA& ra : aTool->GetData()->m_areas )
62 {
63 if( ra.m_ruleName.Contains( ( aName ) ) )
64 return &ra;
65 }
66
67 return nullptr;
68}
69
70
72{
74
75 std::vector<wxString> tests = { "vme-wren" };
76
77 for( const wxString& relPath : tests )
78 {
79 KI_TEST::LoadBoard( m_settingsManager, relPath, m_board );
80
81 TOOL_MANAGER toolMgr;
82 MOCK_TOOLS_HOLDER* toolsHolder = new MOCK_TOOLS_HOLDER;
83
84 toolMgr.SetEnvironment( m_board.get(), nullptr, nullptr, nullptr, toolsHolder );
85
86 MULTICHANNEL_TOOL* mtTool = new MULTICHANNEL_TOOL; // TOOL_MANAGER owns the tools
87 toolMgr.RegisterTool( mtTool );
88
89 //RULE_AREAS_DATA* raData = m_parentTool->GetData();
90
92
93 auto ruleData = mtTool->GetData();
94
95 BOOST_TEST_MESSAGE( wxString::Format( "RA multichannel sheets = %d",
96 static_cast<int>( ruleData->m_areas.size() ) ) );
97
98 BOOST_CHECK_EQUAL( ruleData->m_areas.size(), 72 );
99
100 int cnt = 0;
101
102 ruleData->m_replaceExisting = true;
103
104 for( RULE_AREA& ra : ruleData->m_areas )
105 {
106 if( ra.m_sheetName == wxT( "io_driver.kicad_sch" )
107 || ra.m_sheetName == wxT( "pp_driver_2x.kicad_sch" ) )
108 {
109 ra.m_generateEnabled = true;
110 cnt++;
111 }
112 }
113
114 BOOST_TEST_MESSAGE( wxString::Format( "Autogenerating %d RAs", cnt ) );
115
116 TOOL_EVENT dummyEvent;
117
118 mtTool->AutogenerateRuleAreas( dummyEvent );
119 mtTool->FindExistingRuleAreas();
120
121 int n_areas_io = 0, n_areas_pp = 0, n_areas_other = 0;
122
123 BOOST_TEST_MESSAGE( wxString::Format( "Found %d RAs after commit",
124 static_cast<int>(ruleData->m_areas.size() ) ) );
125
126 for( const RULE_AREA& ra : ruleData->m_areas )
127 {
128 BOOST_TEST_MESSAGE( wxString::Format( "SN '%s'", ra.m_ruleName ) );
129
130 if( ra.m_ruleName.Contains( wxT( "io_drivers_fp" ) ) )
131 {
132 n_areas_io++;
133 BOOST_CHECK_EQUAL( ra.m_components.size(), 31 );
134 }
135 else if( ra.m_ruleName.Contains( wxT( "io_drivers_pp" ) ) )
136 {
137 n_areas_pp++;
138 BOOST_CHECK_EQUAL( ra.m_components.size(), 11 );
139 }
140 else
141 {
142 n_areas_other++;
143 }
144 }
145
146 BOOST_TEST_MESSAGE( wxString::Format( "IO areas=%d, PP areas=%d, others=%d",
147 n_areas_io, n_areas_pp, n_areas_other ) );
148
149 BOOST_CHECK_EQUAL( n_areas_io, 16 );
150 BOOST_CHECK_EQUAL( n_areas_pp, 16 );
151 BOOST_CHECK_EQUAL( n_areas_other, 0 );
152
153 const std::vector<wxString> rulesToTest = { wxT( "io_drivers_fp" ),
154 wxT( "io_drivers_pp" ) };
155
156 for( const wxString& ruleName : rulesToTest )
157 {
158 for( const RULE_AREA& refArea : ruleData->m_areas )
159 {
160 if( !refArea.m_ruleName.Contains( ruleName ) )
161 continue;
162
163 BOOST_TEST_MESSAGE( wxString::Format( "REF AREA: '%s'", refArea.m_ruleName ) );
164
165 for( const RULE_AREA& targetArea : ruleData->m_areas )
166 {
167 if( targetArea.m_zone == refArea.m_zone )
168 continue;
169
170 if( !targetArea.m_ruleName.Contains( ruleName ) )
171 continue;
172
173 auto cgRef = CONNECTION_GRAPH::BuildFromFootprintSet( refArea.m_components );
174 auto cgTarget =
175 CONNECTION_GRAPH::BuildFromFootprintSet( targetArea.m_components );
176
178
179 std::vector<TMATCH::TOPOLOGY_MISMATCH_REASON> details;
180 bool status = cgRef->FindIsomorphism( cgTarget.get(), result, details );
181
182 BOOST_TEST_MESSAGE( wxString::Format(
183 "topo match: '%s' [%d] -> '%s' [%d] result %d", refArea.m_ruleName.c_str().AsChar(),
184 static_cast<int>( refArea.m_components.size() ), targetArea.m_ruleName.c_str().AsChar(),
185 static_cast<int>( targetArea.m_components.size() ), status ? 1 : 0 ) );
186
187 for( const auto& iter : result )
188 {
189 BOOST_TEST_MESSAGE( wxString::Format( "%s : %s",
190 iter.second->GetReference(),
191 iter.first->GetReference() ) );
192 }
193
194 BOOST_CHECK( status );
195 BOOST_CHECK( details.empty() );
196 }
197 }
198 }
199
200 auto refArea = findRuleAreaByPartialName( mtTool, wxT( "io_drivers_fp/bank3/io78/" ) );
201
202 BOOST_ASSERT( refArea );
203
204 const std::vector<wxString> targetAreaNames( { wxT( "io_drivers_fp/bank2/io78/" ),
205 wxT( "io_drivers_fp/bank1/io78/" ),
206 wxT( "io_drivers_fp/bank0/io01/" ) } );
207
208 for( const wxString& targetRaName : targetAreaNames )
209 {
210 auto targetRA = findRuleAreaByPartialName( mtTool, targetRaName );
211
212 BOOST_ASSERT( targetRA != nullptr );
213
214 BOOST_TEST_MESSAGE( wxString::Format( "Clone to: %s", targetRA->m_ruleName ) );
215
216 ruleData->m_compatMap[targetRA].m_doCopy = true;
217 }
218
219 int result = mtTool->RepeatLayout( TOOL_EVENT(), refArea->m_zone );
220
221 BOOST_ASSERT( result >= 0 );
222 }
223}
224
225
230BOOST_FIXTURE_TEST_CASE( RepeatLayoutCopiesFootprintProperties, MULTICHANNEL_TEST_FIXTURE )
231{
232 KI_TEST::LoadBoard( m_settingsManager, "issue22548/issue22548", m_board );
233
234 TOOL_MANAGER toolMgr;
235 MOCK_TOOLS_HOLDER* toolsHolder = new MOCK_TOOLS_HOLDER;
236
237 toolMgr.SetEnvironment( m_board.get(), nullptr, nullptr, nullptr, toolsHolder );
238
240 toolMgr.RegisterTool( mtTool );
241
242 mtTool->FindExistingRuleAreas();
243
244 auto ruleData = mtTool->GetData();
245
246 BOOST_TEST_MESSAGE( wxString::Format( "Found %d rule areas",
247 static_cast<int>( ruleData->m_areas.size() ) ) );
248
249 BOOST_CHECK( ruleData->m_areas.size() >= 2 );
250
251 if( ruleData->m_areas.size() < 2 )
252 return;
253
254 RULE_AREA* refArea = nullptr;
255 RULE_AREA* targetArea = nullptr;
256
257 for( RULE_AREA& ra : ruleData->m_areas )
258 {
259 if( ra.m_ruleName.Contains( wxT( "Untitled Sheet/" ) ) )
260 refArea = &ra;
261 else if( ra.m_ruleName.Contains( wxT( "Untitled Sheet1/" ) ) )
262 targetArea = &ra;
263 }
264
265 if( !refArea || !targetArea )
266 {
267 BOOST_TEST_MESSAGE( "Could not find Untitled Sheet and Untitled Sheet1 rule areas, skipping test" );
268 return;
269 }
270
271 BOOST_TEST_MESSAGE( wxString::Format( "Reference area: %s, Target area: %s",
272 refArea->m_ruleName, targetArea->m_ruleName ) );
273
274 FOOTPRINT* refFP = nullptr;
275 FOOTPRINT* targetFP = nullptr;
276
277 for( FOOTPRINT* fp : refArea->m_components )
278 {
279 if( fp->GetReference().StartsWith( wxT( "U1" ) ) )
280 {
281 refFP = fp;
282 break;
283 }
284 }
285
286 for( FOOTPRINT* fp : targetArea->m_components )
287 {
288 if( fp->GetReference().StartsWith( wxT( "U2" ) ) )
289 {
290 targetFP = fp;
291 break;
292 }
293 }
294
295 if( !refFP || !targetFP )
296 {
297 BOOST_TEST_MESSAGE( "Could not find matching footprints in the rule areas, skipping test" );
298 return;
299 }
300
301 PCB_FIELD* refValueField = refFP->GetField( FIELD_T::VALUE );
302 bool refValueVisible = refValueField ? refValueField->IsVisible() : true;
303
304 std::vector<FP_3DMODEL> refModels = refFP->Models();
305
306 mtTool->CheckRACompatibility( refArea->m_zone );
307
308 ruleData->m_compatMap[targetArea].m_doCopy = true;
309 ruleData->m_options.m_copyPlacement = true;
310
311 int result = mtTool->RepeatLayout( TOOL_EVENT(), refArea->m_zone );
312
313 BOOST_CHECK( result >= 0 );
314
315 PCB_FIELD* targetValueField = targetFP->GetField( FIELD_T::VALUE );
316
317 if( targetValueField && refValueField )
318 {
319 BOOST_CHECK_EQUAL( targetValueField->IsVisible(), refValueVisible );
320 BOOST_TEST_MESSAGE( wxString::Format( "Value field visibility: ref=%d, target=%d",
321 refValueVisible, targetValueField->IsVisible() ) );
322 }
323
324 BOOST_CHECK_EQUAL( targetFP->Models().size(), refModels.size() );
325
326 if( !refModels.empty() )
327 {
328 BOOST_TEST_MESSAGE( wxString::Format( "3D models: ref=%d, target=%d",
329 static_cast<int>( refModels.size() ),
330 static_cast<int>( targetFP->Models().size() ) ) );
331 }
332}
333
334
342BOOST_FIXTURE_TEST_CASE( RepeatLayoutDoesNotRemoveReferenceVias, MULTICHANNEL_TEST_FIXTURE )
343{
344 KI_TEST::LoadBoard( m_settingsManager, "issue21184/issue21184", m_board );
345
346 TOOL_MANAGER toolMgr;
347 MOCK_TOOLS_HOLDER* toolsHolder = new MOCK_TOOLS_HOLDER;
348
349 toolMgr.SetEnvironment( m_board.get(), nullptr, nullptr, nullptr, toolsHolder );
350
352 toolMgr.RegisterTool( mtTool );
353
354 mtTool->FindExistingRuleAreas();
355
356 auto ruleData = mtTool->GetData();
357
358 BOOST_TEST_MESSAGE( wxString::Format( "Found %d rule areas",
359 static_cast<int>( ruleData->m_areas.size() ) ) );
360
361 BOOST_CHECK_EQUAL( ruleData->m_areas.size(), 2 );
362
363 if( ruleData->m_areas.size() < 2 )
364 return;
365
366 RULE_AREA* refArea = nullptr;
367 RULE_AREA* targetArea = nullptr;
368
369 for( RULE_AREA& ra : ruleData->m_areas )
370 {
371 if( ra.m_ruleName == wxT( "Test1" ) )
372 refArea = &ra;
373 else if( ra.m_ruleName == wxT( "Test2" ) )
374 targetArea = &ra;
375 }
376
377 BOOST_REQUIRE( refArea != nullptr );
378 BOOST_REQUIRE( targetArea != nullptr );
379
380 int refViaCountBefore = 0;
381
382 for( PCB_TRACK* track : m_board->Tracks() )
383 {
384 if( track->Type() == PCB_VIA_T )
385 {
386 PCB_VIA* via = static_cast<PCB_VIA*>( track );
387 VECTOR2I viaPos = via->GetPosition();
388
389 if( refArea->m_zone->Outline()->Contains( viaPos ) )
390 refViaCountBefore++;
391 }
392 }
393
394 BOOST_TEST_MESSAGE( wxString::Format( "Reference area vias before repeat: %d", refViaCountBefore ) );
395 BOOST_CHECK( refViaCountBefore > 0 );
396
397 mtTool->CheckRACompatibility( refArea->m_zone );
398
399 ruleData->m_compatMap[targetArea].m_doCopy = true;
400 ruleData->m_options.m_copyPlacement = true;
401 ruleData->m_options.m_copyRouting = true;
402
403 int result = mtTool->RepeatLayout( TOOL_EVENT(), refArea->m_zone );
404
405 BOOST_CHECK( result >= 0 );
406
407 int refViaCountAfter = 0;
408
409 for( PCB_TRACK* track : m_board->Tracks() )
410 {
411 if( track->Type() == PCB_VIA_T )
412 {
413 PCB_VIA* via = static_cast<PCB_VIA*>( track );
414 VECTOR2I viaPos = via->GetPosition();
415
416 if( refArea->m_zone->Outline()->Contains( viaPos ) )
417 refViaCountAfter++;
418 }
419 }
420
421 BOOST_TEST_MESSAGE( wxString::Format( "Reference area vias after repeat: %d", refViaCountAfter ) );
422
423 BOOST_CHECK_EQUAL( refViaCountAfter, refViaCountBefore );
424}
425
426
435{
437 using TMATCH::COMPONENT;
438
439 // Create two connection graphs with components that have dotted reference designators
440 auto cgRef = std::make_unique<CONNECTION_GRAPH>();
441 auto cgTarget = std::make_unique<CONNECTION_GRAPH>();
442
443 // Create mock footprints with the same FPID
444 LIB_ID fpid( wxT( "Package_SO" ), wxT( "SOIC-8_3.9x4.9mm_P1.27mm" ) );
445
446 // Create reference footprint TRIM_1.1 and target footprint TRIM_2.1
447 FOOTPRINT fpRef( nullptr );
448 fpRef.SetFPID( fpid );
449 fpRef.SetReference( wxT( "TRIM_1.1" ) );
450
451 FOOTPRINT fpTarget( nullptr );
452 fpTarget.SetFPID( fpid );
453 fpTarget.SetReference( wxT( "TRIM_2.1" ) );
454
455 // Create matching pad structures
456 PAD padRef1( &fpRef );
457 padRef1.SetNumber( wxT( "1" ) );
458 padRef1.SetNetCode( 1 );
459 fpRef.Add( &padRef1 );
460
461 PAD padRef2( &fpRef );
462 padRef2.SetNumber( wxT( "2" ) );
463 padRef2.SetNetCode( 2 );
464 fpRef.Add( &padRef2 );
465
466 PAD padTarget1( &fpTarget );
467 padTarget1.SetNumber( wxT( "1" ) );
468 padTarget1.SetNetCode( 3 );
469 fpTarget.Add( &padTarget1 );
470
471 PAD padTarget2( &fpTarget );
472 padTarget2.SetNumber( wxT( "2" ) );
473 padTarget2.SetNetCode( 4 );
474 fpTarget.Add( &padTarget2 );
475
476 // Build connection graphs
477 cgRef->AddFootprint( &fpRef, VECTOR2I( 0, 0 ) );
478 cgTarget->AddFootprint( &fpTarget, VECTOR2I( 0, 0 ) );
479
480 cgRef->BuildConnectivity();
481 cgTarget->BuildConnectivity();
482
483 // Check that the components are considered the same kind
484 BOOST_CHECK_EQUAL( cgRef->Components().size(), 1 );
485 BOOST_CHECK_EQUAL( cgTarget->Components().size(), 1 );
486
487 COMPONENT* cmpRef = cgRef->Components()[0];
488 COMPONENT* cmpTarget = cgTarget->Components()[0];
489
490 bool sameKind = cmpRef->IsSameKind( *cmpTarget );
491
492 BOOST_TEST_MESSAGE( wxString::Format( "TRIM_1.1 and TRIM_2.1 IsSameKind: %d", sameKind ? 1 : 0 ) );
493 BOOST_CHECK( sameKind );
494
495 // Test topology matching
497 std::vector<TMATCH::TOPOLOGY_MISMATCH_REASON> details;
498 bool status = cgRef->FindIsomorphism( cgTarget.get(), result, details );
499
500 BOOST_TEST_MESSAGE( wxString::Format( "Topology match result: %d", status ? 1 : 0 ) );
501
502 if( !status && !details.empty() )
503 {
504 for( const auto& reason : details )
505 {
506 BOOST_TEST_MESSAGE( wxString::Format( "Mismatch: %s <-> %s: %s",
507 reason.m_reference, reason.m_candidate, reason.m_reason ) );
508 }
509 }
510
511 BOOST_CHECK( status );
512 BOOST_CHECK( details.empty() );
513
514 // Cleanup: remove pads before footprints go out of scope
515 fpRef.Pads().clear();
516 fpTarget.Pads().clear();
517}
518
519
bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
Store all of the related component information found in a netlist.
virtual bool IsVisible() const
Definition eda_text.h:187
void SetFPID(const LIB_ID &aFPID)
Definition footprint.h:352
PCB_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this footprint.
std::deque< PAD * > & Pads()
Definition footprint.h:306
void SetReference(const wxString &aReference)
Definition footprint.h:757
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
std::vector< FP_3DMODEL > & Models()
Definition footprint.h:323
const wxString & GetReference() const
Definition footprint.h:751
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:49
virtual wxWindow * GetToolCanvas() const override
Canvas access.
int CheckRACompatibility(ZONE *aRefZone)
RULE_AREAS_DATA * GetData()
int RepeatLayout(const TOOL_EVENT &aEvent, ZONE *aRefZone)
int AutogenerateRuleAreas(const TOOL_EVENT &aEvent)
Definition pad.h:55
void SetNumber(const wxString &aNumber)
Set the pad number (note that it can be alphanumeric, such as the array reference "AA12").
Definition pad.h:136
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, int aAccuracy=0, bool aUseBBoxCaches=false) const
Return true if a given subpolygon contains the point aP.
Generic, UI-independent tool event.
Definition tool_event.h:171
Master controller class:
void RegisterTool(TOOL_BASE *aTool)
Add a tool to the manager set and sets it up.
void SetEnvironment(EDA_ITEM *aModel, KIGFX::VIEW *aView, KIGFX::VIEW_CONTROLS *aViewControls, APP_SETTINGS_BASE *aSettings, TOOLS_HOLDER *aFrame)
Set the work environment (model, view, view controls and the parent window).
SHAPE_POLY_SET * Outline()
Definition zone.h:341
void LoadBoard(SETTINGS_MANAGER &aSettingsManager, const wxString &aRelPath, std::unique_ptr< BOARD > &aBoard)
std::map< FOOTPRINT *, FOOTPRINT * > COMPONENT_MATCHES
Definition topo_match.h:172
std::unique_ptr< BOARD > m_board
wxString m_sheetName
std::set< FOOTPRINT * > m_components
wxString m_ruleName
@ VALUE
Field Value of part, i.e. "3.3K".
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
RULE_AREA * findRuleAreaByPartialName(MULTICHANNEL_TOOL *aTool, const wxString &aName)
BOOST_FIXTURE_TEST_CASE(MultichannelToolRegressions, MULTICHANNEL_TEST_FIXTURE)
BOOST_TEST_MESSAGE("Polyline has "<< chain.PointCount()<< " points")
wxString result
Test unit parsing edge cases and error handling.
BOOST_CHECK_EQUAL(result, "25.4")
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:97
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695