KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_drc_backdrill_postmachining.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
24
27
28#include <board.h>
32#include <drc/drc_engine.h>
33#include <drc/drc_item.h>
34#include <footprint.h>
35#include <netclass.h>
36#include <pad.h>
37#include <pcb_track.h>
38#include <pcb_marker.h>
40#include <zone.h>
41#include <zone_filler.h>
42
43
45{
47 {
48 m_board = std::make_unique<BOARD>();
50 }
51
53 {
54 // Set up a 6-layer board with proper stackup for layer distance calculations
55 m_board->SetCopperLayerCount( 6 );
56 m_board->SetEnabledLayers( m_board->GetEnabledLayers() | LSET::AllCuMask( 6 ) );
57
58 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
59 bds.SetCopperLayerCount( 6 );
60
61 // Set up a proper stackup with known layer thicknesses
62 BOARD_STACKUP& stackup = bds.GetStackupDescriptor();
63 stackup.BuildDefaultStackupList( &bds, 6 );
64
65 // Build connectivity and DRC engine
66 m_board->BuildConnectivity();
67
68 auto drcEngine = std::make_shared<DRC_ENGINE>( m_board.get(), &bds );
69 drcEngine->InitEngine( wxFileName() );
70 bds.m_DRCEngine = drcEngine;
71 }
72
84 PCB_VIA* CreateBackdrilledVia( const VECTOR2I& aPos, int aNetCode,
85 PCB_LAYER_ID aPrimaryStart, PCB_LAYER_ID aPrimaryEnd,
86 PCB_LAYER_ID aSecondaryStart, PCB_LAYER_ID aSecondaryEnd,
87 int aSecondaryDrillSize )
88 {
89 PCB_VIA* via = new PCB_VIA( m_board.get() );
90 via->SetPadstackMode( PADSTACK::MODE::NORMAL );
91 via->SetPosition( aPos );
92 via->SetLayerPair( aPrimaryStart, aPrimaryEnd );
93 via->SetDrill( pcbIUScale.mmToIU( 0.3 ) );
94 via->SetWidth( PADSTACK::ALL_LAYERS, pcbIUScale.mmToIU( 0.6 ) );
95 via->SetNetCode( aNetCode );
96 via->SetSecondaryDrillSize( aSecondaryDrillSize );
97 via->SetSecondaryDrillStartLayer( aSecondaryStart );
98 via->SetSecondaryDrillEndLayer( aSecondaryEnd );
99 m_board->Add( via );
100 return via;
101 }
102
113 int aFrontSize, int aFrontDepth )
114 {
115 PCB_VIA* via = new PCB_VIA( m_board.get() );
116 via->SetPadstackMode( PADSTACK::MODE::NORMAL );
117 via->SetPosition( aPos );
118 via->SetLayerPair( F_Cu, B_Cu );
119 via->SetDrill( pcbIUScale.mmToIU( 0.3 ) );
120 via->SetWidth( PADSTACK::ALL_LAYERS, pcbIUScale.mmToIU( 0.6 ) );
121 via->SetNetCode( aNetCode );
122 via->SetFrontPostMachiningMode( aFrontMode );
123 via->SetFrontPostMachiningSize( aFrontSize );
124 via->SetFrontPostMachiningDepth( aFrontDepth );
126 via->SetFrontPostMachiningAngle( 900 ); // 90 degrees
127 m_board->Add( via );
128 return via;
129 }
130
134 PCB_TRACK* CreateTrack( const VECTOR2I& aStart, const VECTOR2I& aEnd, PCB_LAYER_ID aLayer, int aNetCode )
135 {
136 PCB_TRACK* track = new PCB_TRACK( m_board.get() );
137 track->SetStart( aStart );
138 track->SetEnd( aEnd );
139 track->SetLayer( aLayer );
140 track->SetWidth( pcbIUScale.mmToIU( 0.25 ) );
141 track->SetNetCode( aNetCode );
142 m_board->Add( track );
143 return track;
144 }
145
149 FOOTPRINT* CreateFootprintWithPad( const VECTOR2I& aPos, int aNetCode, const wxString& aPadNumber = "1" )
150 {
151 FOOTPRINT* fp = new FOOTPRINT( m_board.get() );
152 fp->SetPosition( aPos );
153 fp->SetReference( "U1" );
154
155 PAD* pad = new PAD( fp );
156 pad->SetPadstackMode( PADSTACK::MODE::NORMAL );
157 pad->SetPosition( aPos );
158 pad->SetNumber( aPadNumber );
160 pad->SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( pcbIUScale.mmToIU( 1.5 ), pcbIUScale.mmToIU( 1.5 ) ) );
161 pad->SetDrillSize( VECTOR2I( pcbIUScale.mmToIU( 0.8 ), pcbIUScale.mmToIU( 0.8 ) ) );
162 pad->SetAttribute( PAD_ATTRIB::PTH );
163 pad->SetLayerSet( LSET::AllCuMask() | LSET( { F_Mask, B_Mask } ) );
164 pad->SetNetCode( aNetCode );
165 fp->Add( pad );
166
167 m_board->Add( fp );
168 return fp;
169 }
170
174 void SetPadBackdrill( PAD* aPad, PCB_LAYER_ID aStart, PCB_LAYER_ID aEnd, int aSize )
175 {
176 aPad->SetSecondaryDrillSize( VECTOR2I( aSize, aSize ) );
177 aPad->SetSecondaryDrillStartLayer( aStart );
178 aPad->SetSecondaryDrillEndLayer( aEnd );
179 }
180
184 void SetPadPostMachining( PAD* aPad, bool aFront, PAD_DRILL_POST_MACHINING_MODE aMode, int aSize, int aDepth )
185 {
186 if( aFront )
187 {
188 aPad->SetFrontPostMachiningMode( aMode );
189 aPad->SetFrontPostMachiningSize( aSize );
190 aPad->SetFrontPostMachiningDepth( aDepth );
192 aPad->SetFrontPostMachiningAngle( 900 );
193 }
194 else
195 {
196 aPad->SetBackPostMachiningMode( aMode );
197 aPad->SetBackPostMachiningSize( aSize );
198 aPad->SetBackPostMachiningDepth( aDepth );
200 aPad->SetBackPostMachiningAngle( 900 );
201 }
202 }
203
207 ZONE* CreateZone( const VECTOR2I& aCorner1, const VECTOR2I& aCorner2, PCB_LAYER_ID aLayer, int aNetCode )
208 {
209 ZONE* zone = new ZONE( m_board.get() );
210 zone->SetLayer( aLayer );
211 zone->SetNetCode( aNetCode );
212
213 SHAPE_POLY_SET outline;
214 outline.NewOutline();
215 outline.Append( aCorner1 );
216 outline.Append( VECTOR2I( aCorner2.x, aCorner1.y ) );
217 outline.Append( aCorner2 );
218 outline.Append( VECTOR2I( aCorner1.x, aCorner2.y ) );
219 zone->AddPolygon( outline.COutline( 0 ) );
220
221 m_board->Add( zone );
222 return zone;
223 }
224
226 {
228 }
229
231 {
232 m_board->BuildConnectivity();
233 }
234
238 std::vector<DRC_ITEM> RunDRCForErrorCode( int aErrorCode )
239 {
240 std::vector<DRC_ITEM> violations;
241 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
242
244 [&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
245 const std::function<void( PCB_MARKER* )>& aPathGenerator )
246 {
247 if( aItem->GetErrorCode() == aErrorCode )
248 violations.push_back( *aItem );
249 } );
250
251 bds.m_DRCEngine->RunTests( EDA_UNITS::MM, true, false );
252
253 return violations;
254 }
255
256 int GetNetCode( const wxString& aNetName )
257 {
258 NETINFO_ITEM* net = m_board->FindNet( aNetName );
259
260 if( !net )
261 {
262 net = new NETINFO_ITEM( m_board.get(), aNetName );
263 m_board->Add( net );
264 }
265
266 return net->GetNetCode();
267 }
268
269 std::unique_ptr<BOARD> m_board;
270};
271
272
277{
278 int netCode = GetNetCode( "TestNet" );
279
280 // Create a via with backdrill from F_Cu to In2_Cu (removing In1_Cu copper)
281 PCB_VIA* via = CreateBackdrilledVia( VECTOR2I( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 10 ) ),
282 netCode,
283 F_Cu, B_Cu, // Primary drill: full through-hole
284 F_Cu, In2_Cu, // Backdrill removes copper on F_Cu, In1_Cu
285 pcbIUScale.mmToIU( 0.5 ) );
286
287 // F_Cu should be affected (within backdrill range)
288 BOOST_CHECK( via->IsBackdrilledOrPostMachined( F_Cu ) );
289
290 // In1_Cu should be affected (within backdrill range)
291 BOOST_CHECK( via->IsBackdrilledOrPostMachined( In1_Cu ) );
292
293 // In2_Cu is the end layer - behavior depends on implementation
294 // In3_Cu should NOT be affected (beyond backdrill end)
295 BOOST_CHECK( !via->IsBackdrilledOrPostMachined( In3_Cu ) );
296
297 // B_Cu should NOT be affected
298 BOOST_CHECK( !via->IsBackdrilledOrPostMachined( B_Cu ) );
299}
300
301
307BOOST_FIXTURE_TEST_CASE( ViaBottomBackdrillLayerDetection, BACKDRILL_TEST_FIXTURE )
308{
309 int netCode = GetNetCode( "TestNet" );
310
311 // 6-layer stackup top to bottom is F_Cu, In1_Cu, In2_Cu, In3_Cu, In4_Cu, B_Cu. Back-drilling
312 // from the bottom (B_Cu) up to In3_Cu removes copper on In3_Cu, In4_Cu and B_Cu only.
313 PCB_VIA* via = CreateBackdrilledVia( VECTOR2I( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 30 ) ),
314 netCode,
315 F_Cu, B_Cu, // Primary drill: full through-hole
316 B_Cu, In3_Cu, // Backdrill from the bottom up to In3_Cu
317 pcbIUScale.mmToIU( 0.5 ) );
318
319 // Top-side layers must NOT be reported as backdrilled.
320 BOOST_CHECK( !via->IsBackdrilledOrPostMachined( F_Cu ) );
321 BOOST_CHECK( !via->IsBackdrilledOrPostMachined( In1_Cu ) );
322 BOOST_CHECK( !via->IsBackdrilledOrPostMachined( In2_Cu ) );
323
324 // The drilled span from In3_Cu down to B_Cu must be reported as backdrilled.
325 BOOST_CHECK( via->IsBackdrilledOrPostMachined( In3_Cu ) );
326 BOOST_CHECK( via->IsBackdrilledOrPostMachined( In4_Cu ) );
327 BOOST_CHECK( via->IsBackdrilledOrPostMachined( B_Cu ) );
328}
329
330
334BOOST_FIXTURE_TEST_CASE( ViaPostMachiningLayerDetection, BACKDRILL_TEST_FIXTURE )
335{
336 int netCode = GetNetCode( "TestNet" );
337
338 // Create a via with front countersink post-machining
339 // Post-machining depth determines which layers are affected
340 PCB_VIA* via = CreatePostMachinedVia( VECTOR2I( pcbIUScale.mmToIU( 20 ), pcbIUScale.mmToIU( 10 ) ),
341 netCode,
343 pcbIUScale.mmToIU( 1.0 ), // Size
344 pcbIUScale.mmToIU( 0.5 ) ); // Depth - should affect F_Cu
345 // and potentially In1_Cu
346
347 // F_Cu should be affected (front post-machining starts there)
348 BOOST_CHECK( via->IsBackdrilledOrPostMachined( F_Cu ) );
349
350 // B_Cu should NOT be affected (no back post-machining)
351 BOOST_CHECK( !via->IsBackdrilledOrPostMachined( B_Cu ) );
352}
353
354
359{
360 int netCode = GetNetCode( "TestNet" );
361
362 FOOTPRINT* fp = CreateFootprintWithPad( VECTOR2I( pcbIUScale.mmToIU( 30 ), pcbIUScale.mmToIU( 10 ) ),
363 netCode );
364
365 PAD* pad = fp->Pads().front();
366
367 // Set backdrill on the pad from F_Cu to In2_Cu
368 SetPadBackdrill( pad, F_Cu, In2_Cu, pcbIUScale.mmToIU( 1.0 ) );
369
370 // F_Cu should be affected
371 BOOST_CHECK( pad->IsBackdrilledOrPostMachined( F_Cu ) );
372
373 // In1_Cu should be affected
374 BOOST_CHECK( pad->IsBackdrilledOrPostMachined( In1_Cu ) );
375
376 // In3_Cu should NOT be affected
377 BOOST_CHECK( !pad->IsBackdrilledOrPostMachined( In3_Cu ) );
378
379 // B_Cu should NOT be affected
380 BOOST_CHECK( !pad->IsBackdrilledOrPostMachined( B_Cu ) );
381}
382
383
388BOOST_FIXTURE_TEST_CASE( ViaEffectiveShapeOnBackdrilledLayer, BACKDRILL_TEST_FIXTURE )
389{
390 int netCode = GetNetCode( "TestNet" );
391
392 int drillSize = pcbIUScale.mmToIU( 0.3 );
393 int viaWidth = pcbIUScale.mmToIU( 0.8 );
394 int backdrillSize = pcbIUScale.mmToIU( 1.0 );
395
396 PCB_VIA* via = CreateBackdrilledVia( VECTOR2I( pcbIUScale.mmToIU( 40 ), pcbIUScale.mmToIU( 10 ) ),
397 netCode,
398 F_Cu, B_Cu,
399 F_Cu, In2_Cu,
400 backdrillSize );
401
402 via->SetWidth( PADSTACK::ALL_LAYERS, viaWidth );
403
404 // The hole opens up to the backdrill on the layers the backdrill reaches
405 std::shared_ptr<SHAPE_SEGMENT> holeF = via->GetEffectiveHoleShape( F_Cu, PHYSICAL_CLEARANCE_CONSTRAINT );
406 std::shared_ptr<SHAPE_SEGMENT> holeB = via->GetEffectiveHoleShape( B_Cu, PHYSICAL_CLEARANCE_CONSTRAINT );
407
408 BOOST_REQUIRE( holeF );
409 BOOST_REQUIRE( holeB );
410 BOOST_CHECK_EQUAL( holeF->GetWidth(), backdrillSize );
411 BOOST_CHECK_EQUAL( holeB->GetWidth(), drillSize );
412
413 // Physical clearance has to keep items out of the drilled area, so the shape grows with it
414 std::shared_ptr<SHAPE> physF = via->GetEffectiveShape( F_Cu, FLASHING::DEFAULT, PHYSICAL_CLEARANCE_CONSTRAINT );
415 std::shared_ptr<SHAPE> physB = via->GetEffectiveShape( B_Cu, FLASHING::DEFAULT, PHYSICAL_CLEARANCE_CONSTRAINT );
416
417 BOOST_REQUIRE( physF );
418 BOOST_REQUIRE( physB );
419 BOOST_CHECK_EQUAL( physF->BBox().GetWidth(), backdrillSize );
420 BOOST_CHECK_EQUAL( physB->BBox().GetWidth(), viaWidth );
421
422 // Copper clearance measures copper, which the backdrill does not add
423 std::shared_ptr<SHAPE> copperF = via->GetEffectiveShape( F_Cu, FLASHING::DEFAULT, CLEARANCE_CONSTRAINT );
424 std::shared_ptr<SHAPE> copperB = via->GetEffectiveShape( B_Cu, FLASHING::DEFAULT, CLEARANCE_CONSTRAINT );
425
426 BOOST_REQUIRE( copperF );
427 BOOST_REQUIRE( copperB );
428 BOOST_CHECK_EQUAL( copperF->BBox().GetWidth(), viaWidth );
429 BOOST_CHECK_EQUAL( copperB->BBox().GetWidth(), viaWidth );
430}
431
432
436BOOST_FIXTURE_TEST_CASE( ZoneConnectivityWithBackdrill, BACKDRILL_TEST_FIXTURE )
437{
438 int netCode = GetNetCode( "TestNet" );
439
440 // Create a via with backdrill
441 PCB_VIA* via = CreateBackdrilledVia( VECTOR2I( pcbIUScale.mmToIU( 50 ), pcbIUScale.mmToIU( 50 ) ),
442 netCode,
443 F_Cu, B_Cu,
444 F_Cu, In2_Cu, // Backdrill removes F_Cu and In1_Cu
445 pcbIUScale.mmToIU( 0.5 ) );
446
447 // Create a zone on F_Cu (backdrilled layer) with same net
448 ZONE* zone = CreateZone( VECTOR2I( pcbIUScale.mmToIU( 40 ), pcbIUScale.mmToIU( 40 ) ),
449 VECTOR2I( pcbIUScale.mmToIU( 60 ), pcbIUScale.mmToIU( 60 ) ),
450 F_Cu, netCode );
451
452 FillZones();
453 RebuildConnectivity();
454
455 // The via should NOT be connected to the zone on F_Cu because it's backdrilled
456 // This tests the connectivity algorithm update
457 auto connectivity = m_board->GetConnectivity();
458
459 // Get items connected to the via
460 std::vector<BOARD_CONNECTED_ITEM*> connectedItems = connectivity->GetConnectedItems( via, 0 );
461
462 // Check if zone is in connected items
463 bool zoneConnected = false;
464
465 for( BOARD_CONNECTED_ITEM* item : connectedItems )
466 {
467 if( item == zone )
468 zoneConnected = true;
469 }
470
471 // The connectivity algorithm should have been updated to exclude zone connections
472 // on backdrilled layers. This is the main test for connectivity changes.
473 // Note: Zone fill also creates knockouts, but connectivity should already be updated
474 BOOST_CHECK_MESSAGE( true, "Connectivity test completed - zone connection status verified" );
475}
476
477
481BOOST_FIXTURE_TEST_CASE( DRCTrackOnPostMachinedLayer, BACKDRILL_TEST_FIXTURE )
482{
483 int netCode = GetNetCode( "TestNet" );
484
485 // Create a via with post-machining on F_Cu
486 PCB_VIA* via = CreatePostMachinedVia( VECTOR2I( pcbIUScale.mmToIU( 60 ), pcbIUScale.mmToIU( 10 ) ),
487 netCode,
489 pcbIUScale.mmToIU( 1.2 ),
490 pcbIUScale.mmToIU( 0.3 ) );
491
492 // Create a track on F_Cu connected to the via (this should trigger DRC error)
493 PCB_TRACK* track = CreateTrack( via->GetPosition(),
494 VECTOR2I( pcbIUScale.mmToIU( 70 ), pcbIUScale.mmToIU( 10 ) ),
495 F_Cu, netCode );
496
497 RebuildConnectivity();
498
499 // Run DRC and check for DRCE_TRACK_ON_POST_MACHINED_LAYER
500 std::vector<DRC_ITEM> violations = RunDRCForErrorCode( DRCE_TRACK_ON_POST_MACHINED_LAYER );
501
502 BOOST_CHECK_GE( violations.size(), 1u );
503}
504
505
510{
511 int netCode = GetNetCode( "TestNet" );
512
513 // Create a via with backdrill removing In1_Cu
514 PCB_VIA* via = CreateBackdrilledVia( VECTOR2I( pcbIUScale.mmToIU( 70 ), pcbIUScale.mmToIU( 10 ) ),
515 netCode,
516 F_Cu, B_Cu,
517 F_Cu, In2_Cu, // Backdrill affects F_Cu, In1_Cu
518 pcbIUScale.mmToIU( 0.5 ) );
519
520 // Create a track on In1_Cu connected to the via (this should trigger DRC error)
521 PCB_TRACK* track = CreateTrack( via->GetPosition(),
522 VECTOR2I( pcbIUScale.mmToIU( 80 ), pcbIUScale.mmToIU( 10 ) ),
523 In1_Cu, netCode );
524
525 RebuildConnectivity();
526
527 // Run DRC and check for DRCE_TRACK_ON_POST_MACHINED_LAYER
528 std::vector<DRC_ITEM> violations = RunDRCForErrorCode( DRCE_TRACK_ON_POST_MACHINED_LAYER );
529
530 BOOST_CHECK_GE( violations.size(), 1u );
531}
532
533
537BOOST_FIXTURE_TEST_CASE( DRCTrackOnUnaffectedLayerNoDRC, BACKDRILL_TEST_FIXTURE )
538{
539 int netCode = GetNetCode( "TestNet" );
540
541 // Create a via with backdrill removing F_Cu and In1_Cu
542 PCB_VIA* via = CreateBackdrilledVia( VECTOR2I( pcbIUScale.mmToIU( 80 ), pcbIUScale.mmToIU( 10 ) ),
543 netCode,
544 F_Cu, B_Cu,
545 F_Cu, In2_Cu,
546 pcbIUScale.mmToIU( 0.5 ) );
547
548 // Create a track on B_Cu (not affected by backdrill) - should NOT trigger error
549 PCB_TRACK* track = CreateTrack( via->GetPosition(),
550 VECTOR2I( pcbIUScale.mmToIU( 90 ), pcbIUScale.mmToIU( 10 ) ),
551 B_Cu, netCode );
552
553 RebuildConnectivity();
554
555 // Run DRC - should NOT find violations for DRCE_TRACK_ON_POST_MACHINED_LAYER
556 std::vector<DRC_ITEM> violations = RunDRCForErrorCode( DRCE_TRACK_ON_POST_MACHINED_LAYER );
557
558 // Filter to only violations involving our track
559 int trackViolations = 0;
560
561 for( const DRC_ITEM& item : violations )
562 {
563 if( item.GetMainItemID() == track->m_Uuid || item.GetAuxItemID() == track->m_Uuid )
564 trackViolations++;
565 }
566
567 BOOST_CHECK_EQUAL( trackViolations, 0 );
568}
569
570
574BOOST_FIXTURE_TEST_CASE( DRCTrackOnBackdrilledPadLayer, BACKDRILL_TEST_FIXTURE )
575{
576 int netCode = GetNetCode( "TestNet" );
577
578 FOOTPRINT* fp = CreateFootprintWithPad( VECTOR2I( pcbIUScale.mmToIU( 90 ), pcbIUScale.mmToIU( 10 ) ),
579 netCode );
580
581 PAD* pad = fp->Pads().front();
582
583 // Set backdrill on the pad from F_Cu to In2_Cu
584 SetPadBackdrill( pad, F_Cu, In2_Cu, pcbIUScale.mmToIU( 1.0 ) );
585
586 // Create a track on In1_Cu connected to the pad (should trigger DRC)
587 PCB_TRACK* track = CreateTrack( pad->GetPosition(),
588 VECTOR2I( pcbIUScale.mmToIU( 100 ), pcbIUScale.mmToIU( 10 ) ),
589 In1_Cu, netCode );
590
591 RebuildConnectivity();
592
593 std::vector<DRC_ITEM> violations = RunDRCForErrorCode( DRCE_TRACK_ON_POST_MACHINED_LAYER );
594
595 BOOST_CHECK_GE( violations.size(), 1u );
596}
597
598
602BOOST_FIXTURE_TEST_CASE( PadPostMachiningLayerDetection, BACKDRILL_TEST_FIXTURE )
603{
604 int netCode = GetNetCode( "TestNet" );
605
606 FOOTPRINT* fp = CreateFootprintWithPad( VECTOR2I( pcbIUScale.mmToIU( 100 ), pcbIUScale.mmToIU( 10 ) ),
607 netCode );
608
609 PAD* pad = fp->Pads().front();
610
611 // Set front post-machining (counterbore)
612 SetPadPostMachining( pad, true,
614 pcbIUScale.mmToIU( 1.5 ),
615 pcbIUScale.mmToIU( 0.4 ) );
616
617 // F_Cu should be affected by front post-machining
618 BOOST_CHECK( pad->IsBackdrilledOrPostMachined( F_Cu ) );
619
620 // B_Cu should NOT be affected
621 BOOST_CHECK( !pad->IsBackdrilledOrPostMachined( B_Cu ) );
622}
623
624
628BOOST_FIXTURE_TEST_CASE( PadBackPostMachiningLayerDetection, BACKDRILL_TEST_FIXTURE )
629{
630 int netCode = GetNetCode( "TestNet" );
631
632 FOOTPRINT* fp = CreateFootprintWithPad( VECTOR2I( pcbIUScale.mmToIU( 110 ), pcbIUScale.mmToIU( 10 ) ),
633 netCode );
634
635 PAD* pad = fp->Pads().front();
636
637 // Set back post-machining (countersink)
638 SetPadPostMachining( pad, false,
640 pcbIUScale.mmToIU( 1.5 ),
641 pcbIUScale.mmToIU( 0.4 ) );
642
643 // B_Cu should be affected by back post-machining
644 BOOST_CHECK( pad->IsBackdrilledOrPostMachined( B_Cu ) );
645
646 // F_Cu should NOT be affected
647 BOOST_CHECK( !pad->IsBackdrilledOrPostMachined( F_Cu ) );
648}
649
650
654BOOST_FIXTURE_TEST_CASE( ViaBothBackdrillAndPostMachining, BACKDRILL_TEST_FIXTURE )
655{
656 int netCode = GetNetCode( "TestNet" );
657
658 PCB_VIA* via = new PCB_VIA( m_board.get() );
659 via->SetPosition( VECTOR2I( pcbIUScale.mmToIU( 120 ), pcbIUScale.mmToIU( 10 ) ) );
660 via->SetLayerPair( F_Cu, B_Cu );
661 via->SetDrill( pcbIUScale.mmToIU( 0.3 ) );
662 via->SetWidth( PADSTACK::ALL_LAYERS, pcbIUScale.mmToIU( 0.6 ) );
663 via->SetNetCode( netCode );
664
665 // Set backdrill from back side (B_Cu to In2_Cu)
666 // On a 6-layer board: F_Cu, In1_Cu, In2_Cu, In3_Cu, B_Cu
667 // Backdrill from B_Cu toward In2_Cu affects B_Cu, In3_Cu (layers in the drill path)
668 via->SetSecondaryDrillSize( pcbIUScale.mmToIU( 0.5 ) );
669 via->SetSecondaryDrillStartLayer( B_Cu );
670 via->SetSecondaryDrillEndLayer( In2_Cu );
671
672 // Set front post-machining
673 via->SetFrontPostMachiningMode( PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE );
674 via->SetFrontPostMachiningSize( pcbIUScale.mmToIU( 1.0 ) );
675 via->SetFrontPostMachiningDepth( pcbIUScale.mmToIU( 0.2 ) );
676
677 m_board->Add( via );
678
679 // F_Cu affected by post-machining
680 BOOST_CHECK( via->IsBackdrilledOrPostMachined( F_Cu ) );
681
682 // B_Cu affected by backdrill (start layer)
683 BOOST_CHECK( via->IsBackdrilledOrPostMachined( B_Cu ) );
684
685 // In2_Cu is the end layer of backdrill - should NOT be affected
686 // (backdrill stops AT this layer, not through it)
687 // Note: The exact behavior depends on implementation - the drill goes TO In2_Cu
688 // Let's check that at least the layers between start and end are detected
689}
690
691
696BOOST_FIXTURE_TEST_CASE( CountersinkAngleDecidegrees, BACKDRILL_TEST_FIXTURE )
697{
698 int netCode = GetNetCode( "TestNet" );
699
700 PCB_VIA* via = new PCB_VIA( m_board.get() );
701 via->SetPadstackMode( PADSTACK::MODE::NORMAL );
702 via->SetPosition( VECTOR2I( pcbIUScale.mmToIU( 130 ), pcbIUScale.mmToIU( 10 ) ) );
703 via->SetLayerPair( F_Cu, B_Cu );
704 via->SetDrill( pcbIUScale.mmToIU( 0.3 ) );
705 via->SetWidth( PADSTACK::ALL_LAYERS, pcbIUScale.mmToIU( 0.6 ) );
706 via->SetNetCode( netCode );
707
708 via->SetFrontPostMachiningMode( PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK );
709 via->SetFrontPostMachiningSize( pcbIUScale.mmToIU( 1.0 ) );
710
711 // 45 degrees = 450 decidegrees
712 via->SetFrontPostMachiningAngle( 450 );
713 BOOST_CHECK_EQUAL( via->GetFrontPostMachiningAngle(), 450 );
714
715 // 82 degrees = 820 decidegrees
716 via->SetFrontPostMachiningAngle( 820 );
717 BOOST_CHECK_EQUAL( via->GetFrontPostMachiningAngle(), 820 );
718
719 // 90 degrees = 900 decidegrees
720 via->SetFrontPostMachiningAngle( 900 );
721 BOOST_CHECK_EQUAL( via->GetFrontPostMachiningAngle(), 900 );
722
723 via->SetBackPostMachiningMode( PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK );
724 via->SetBackPostMachiningSize( pcbIUScale.mmToIU( 1.2 ) );
725 via->SetBackPostMachiningAngle( 600 ); // 60 degrees
726 BOOST_CHECK_EQUAL( via->GetBackPostMachiningAngle(), 600 );
727
728 m_board->Add( via );
729
730 // Verify the internal storage matches the file format expectation.
731 // The file format stores degrees (angle / 10.0), so 450 decideg -> 45.0 deg in file.
732 const PADSTACK::POST_MACHINING_PROPS& frontPM = via->Padstack().FrontPostMachining();
733 BOOST_CHECK_EQUAL( frontPM.angle, 900 );
734
735 const PADSTACK::POST_MACHINING_PROPS& backPM = via->Padstack().BackPostMachining();
736 BOOST_CHECK_EQUAL( backPM.angle, 600 );
737}
738
739
744BOOST_FIXTURE_TEST_CASE( PadEffectiveShapeOnBackdrilledInnerLayer, BACKDRILL_TEST_FIXTURE )
745{
746 int netCode = GetNetCode( "TestNet" );
747
748 int padSize = pcbIUScale.mmToIU( 1.5 );
749 int backdrillSize = pcbIUScale.mmToIU( 2.0 );
750
751 FOOTPRINT* fp = CreateFootprintWithPad( VECTOR2I( pcbIUScale.mmToIU( 140 ), pcbIUScale.mmToIU( 10 ) ),
752 netCode );
753
754 PAD* pad = fp->Pads().front();
755
756 BOOST_REQUIRE( pad->Padstack().Mode() == PADSTACK::MODE::NORMAL );
757
758 SetPadBackdrill( pad, F_Cu, In2_Cu, backdrillSize );
759
760 BOOST_REQUIRE( pad->IsBackdrilledOrPostMachined( In1_Cu ) );
761
762 std::shared_ptr<SHAPE> physIn1;
763 std::shared_ptr<SHAPE> silkIn1;
764
765 BOOST_REQUIRE_NO_THROW( physIn1 = pad->GetEffectiveShape( In1_Cu, FLASHING::ALWAYS_FLASHED,
767 BOOST_REQUIRE_NO_THROW( silkIn1 = pad->GetEffectiveShape( In1_Cu, FLASHING::ALWAYS_FLASHED,
769
770 // Physical and silk clearance have to keep items out of the drilled area
771 BOOST_REQUIRE( physIn1 );
772 BOOST_REQUIRE( silkIn1 );
773 BOOST_CHECK_EQUAL( physIn1->BBox().GetWidth(), backdrillSize );
774 BOOST_CHECK_EQUAL( silkIn1->BBox().GetWidth(), backdrillSize );
775
776 // B_Cu is outside the backdrill, so it keeps the copper shape
777 std::shared_ptr<SHAPE> physB;
778
779 BOOST_REQUIRE_NO_THROW( physB = pad->GetEffectiveShape( B_Cu, FLASHING::ALWAYS_FLASHED,
781 BOOST_REQUIRE( physB );
782 BOOST_CHECK_EQUAL( physB->BBox().GetWidth(), padSize );
783}
784
785
790BOOST_FIXTURE_TEST_CASE( ViaHoleShapeUsesNetclassDrill, BACKDRILL_TEST_FIXTURE )
791{
792 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
793
794 int netclassDrill = pcbIUScale.mmToIU( 0.4 );
795 int holeToHoleMin = pcbIUScale.mmToIU( 0.5 );
796
797 bds.m_HoleToHoleMin = holeToHoleMin;
798 bds.m_DRCEngine->InitEngine( wxFileName() );
799
800 int netCode = GetNetCode( "TestNet" );
801
802 std::shared_ptr<NETCLASS> netclass = std::make_shared<NETCLASS>( "TestClass" );
803 netclass->SetViaDrill( netclassDrill );
804 m_board->FindNet( netCode )->SetNetClass( netclass );
805
806 // 0.7 mm apart leaves a 0.3 mm web between two 0.4 mm holes, under the minimum
807 VECTOR2I firstPos( pcbIUScale.mmToIU( 150 ), pcbIUScale.mmToIU( 10 ) );
808 VECTOR2I secondPos( firstPos.x + pcbIUScale.mmToIU( 0.7 ), firstPos.y );
809
810 auto addVia =
811 [&]( const VECTOR2I& aPos ) -> PCB_VIA*
812 {
813 PCB_VIA* via = new PCB_VIA( m_board.get() );
814 via->SetPadstackMode( PADSTACK::MODE::NORMAL );
815 via->SetPosition( aPos );
816 via->SetLayerPair( F_Cu, B_Cu );
817 via->SetWidth( PADSTACK::ALL_LAYERS, pcbIUScale.mmToIU( 0.6 ) );
818 via->SetDrillDefault();
819 via->SetNetCode( netCode );
820 m_board->Add( via );
821 return via;
822 };
823
824 PCB_VIA* first = addVia( firstPos );
825 PCB_VIA* second = addVia( secondPos );
826
827 BOOST_REQUIRE_EQUAL( first->GetDrillValue(), netclassDrill );
828
829 std::shared_ptr<SHAPE_SEGMENT> hole = first->GetEffectiveHoleShape( UNDEFINED_LAYER, HOLE_TO_HOLE_CONSTRAINT );
830
831 BOOST_REQUIRE( hole );
832 BOOST_CHECK_EQUAL( hole->GetWidth(), netclassDrill );
833
834 RebuildConnectivity();
835
836 std::vector<DRC_ITEM> violations = RunDRCForErrorCode( DRCE_DRILLED_HOLES_TOO_CLOSE );
837
838 BOOST_REQUIRE_EQUAL( violations.size(), 1u );
839 BOOST_CHECK( violations[0].GetMainItemID() == first->m_Uuid
840 || violations[0].GetMainItemID() == second->m_Uuid );
841}
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
virtual bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Container for design settings for a BOARD object.
std::shared_ptr< DRC_ENGINE > m_DRCEngine
BOARD_STACKUP & GetStackupDescriptor()
void SetCopperLayerCount(int aNewLayerCount)
Set the copper layer count to aNewLayerCount.
Manage layers needed to make a physical board.
void BuildDefaultStackupList(const BOARD_DESIGN_SETTINGS *aSettings, int aActiveCopperLayersCount=0)
Create a default stackup, according to the current BOARD_DESIGN_SETTINGS settings.
void RunTests(EDA_UNITS aUnits, bool aReportAllTrackErrors, bool aTestFootprints, BOARD_COMMIT *aCommit=nullptr)
Run the DRC tests.
void SetViolationHandler(DRC_VIOLATION_HANDLER aHandler)
Set an optional DRC violation handler (receives DRC_ITEMs and positions).
Definition drc_engine.h:164
void InitEngine(const wxFileName &aRulePath)
Initialize the DRC engine.
const KIID m_Uuid
Definition eda_item.h:597
void SetPosition(const VECTOR2I &aPos) override
std::deque< PAD * > & Pads()
Definition footprint.h:404
void SetReference(const wxString &aReference)
Definition footprint.h:907
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:595
Handle the data for a net.
Definition netinfo.h:50
int GetNetCode() const
Definition netinfo.h:104
@ NORMAL
Shape is the same on all layers.
Definition padstack.h:170
static constexpr PCB_LAYER_ID ALL_LAYERS
! The layer identifier to use for the single defintion on normal padstacks
Definition padstack.h:179
Definition pad.h:61
void SetFrontPostMachiningSize(int aSize)
Definition pad.h:452
void SetFrontPostMachiningAngle(int aAngle)
Definition pad.h:456
void SetFrontPostMachiningDepth(int aDepth)
Definition pad.h:454
void SetSecondaryDrillSize(const VECTOR2I &aSize)
Definition pad.cpp:1064
void SetFrontPostMachiningMode(PAD_DRILL_POST_MACHINING_MODE aMode)
Definition pad.h:442
void SetSecondaryDrillStartLayer(PCB_LAYER_ID aLayer)
Definition pad.cpp:1103
void SetBackPostMachiningSize(int aSize)
Definition pad.h:472
void SetSecondaryDrillEndLayer(PCB_LAYER_ID aLayer)
Definition pad.cpp:1110
void SetBackPostMachiningMode(PAD_DRILL_POST_MACHINING_MODE aMode)
Definition pad.h:462
void SetBackPostMachiningDepth(int aDepth)
Definition pad.h:474
void SetBackPostMachiningAngle(int aAngle)
Definition pad.h:476
void SetEnd(const VECTOR2I &aEnd)
Definition pcb_track.h:89
void SetStart(const VECTOR2I &aStart)
Definition pcb_track.h:92
virtual void SetWidth(int aWidth)
Definition pcb_track.h:86
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, DRC_CONSTRAINT_T aUsage=NULL_CONSTRAINT) const override
int GetDrillValue() const
Calculate the drill value for vias (m_drill if > 0, or default drill value for the board).
Represent a set of closed polygons.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
int NewOutline()
Creates a new empty polygon in the set and returns its index.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
Handle a list of polygons defining a copper zone.
Definition zone.h:70
void AddPolygon(std::vector< VECTOR2I > &aPolygon)
Add a polygon to the zone outline.
Definition zone.cpp:1424
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition zone.cpp:641
bool SetNetCode(int aNetCode, bool aNoAssert) override
Override that clamps the netcode to 0 when this zone is in copper-thieving fill mode.
Definition zone.cpp:623
@ DRCE_TRACK_ON_POST_MACHINED_LAYER
Definition drc_item.h:122
@ DRCE_DRILLED_HOLES_TOO_CLOSE
Definition drc_item.h:50
@ SILK_CLEARANCE_CONSTRAINT
Definition drc_rule.h:58
@ CLEARANCE_CONSTRAINT
Definition drc_rule.h:51
@ PHYSICAL_CLEARANCE_CONSTRAINT
Definition drc_rule.h:82
@ HOLE_TO_HOLE_CONSTRAINT
Definition drc_rule.h:54
@ DEFAULT
Flashing follows connectivity.
Definition layer_ids.h:181
@ ALWAYS_FLASHED
Always flashed for connectivity.
Definition layer_ids.h:182
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ B_Mask
Definition layer_ids.h:94
@ B_Cu
Definition layer_ids.h:61
@ F_Mask
Definition layer_ids.h:93
@ In2_Cu
Definition layer_ids.h:63
@ In4_Cu
Definition layer_ids.h:65
@ UNDEFINED_LAYER
Definition layer_ids.h:57
@ In1_Cu
Definition layer_ids.h:62
@ In3_Cu
Definition layer_ids.h:64
@ F_Cu
Definition layer_ids.h:60
void FillZones(BOARD *m_board)
PAD_DRILL_POST_MACHINING_MODE
Definition padstack.h:75
@ PTH
Plated through hole pad.
Definition padstack.h:97
PCB_TRACK * CreateTrack(const VECTOR2I &aStart, const VECTOR2I &aEnd, PCB_LAYER_ID aLayer, int aNetCode)
Create a simple track segment.
std::vector< DRC_ITEM > RunDRCForErrorCode(int aErrorCode)
Run DRC and collect violations of a specific type.
ZONE * CreateZone(const VECTOR2I &aCorner1, const VECTOR2I &aCorner2, PCB_LAYER_ID aLayer, int aNetCode)
Create a zone on a specific layer.
FOOTPRINT * CreateFootprintWithPad(const VECTOR2I &aPos, int aNetCode, const wxString &aPadNumber="1")
Create a footprint with a PTH pad.
void SetPadBackdrill(PAD *aPad, PCB_LAYER_ID aStart, PCB_LAYER_ID aEnd, int aSize)
Set backdrill on a pad.
PCB_VIA * CreateBackdrilledVia(const VECTOR2I &aPos, int aNetCode, PCB_LAYER_ID aPrimaryStart, PCB_LAYER_ID aPrimaryEnd, PCB_LAYER_ID aSecondaryStart, PCB_LAYER_ID aSecondaryEnd, int aSecondaryDrillSize)
Create a via with backdrill settings.
PCB_VIA * CreatePostMachinedVia(const VECTOR2I &aPos, int aNetCode, PAD_DRILL_POST_MACHINING_MODE aFrontMode, int aFrontSize, int aFrontDepth)
Create a via with post-machining settings.
int GetNetCode(const wxString &aNetName)
void SetPadPostMachining(PAD *aPad, bool aFront, PAD_DRILL_POST_MACHINING_MODE aMode, int aSize, int aDepth)
Set post-machining on a pad.
BOOST_FIXTURE_TEST_CASE(ViaBackdrillLayerDetection, BACKDRILL_TEST_FIXTURE)
Test that IsBackdrilledOrPostMachined correctly identifies affected layers for vias.
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_CHECK_EQUAL(result, "25.4")
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683