KiCad PCB EDA Suite
drc_test_provider_solder_mask.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 (C) 2004-2022 KiCad Developers.
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 <common.h>
27#include <footprint.h>
28#include <pad.h>
29#include <pcb_track.h>
30#include <zone.h>
31#include <geometry/seg.h>
32#include <drc/drc_engine.h>
33#include <drc/drc_item.h>
34#include <drc/drc_rule.h>
36#include <drc/drc_rtree.h>
37
38/*
39 Solder mask tests. Checks for silkscreen which is clipped by mask openings and for bridges
40 between mask apertures with different nets.
41 Errors generated:
42 - DRCE_SILK_CLEARANCE
43 - DRCE_SOLDERMASK_BRIDGE
44*/
45
47{
48public:
50 m_board( nullptr ),
51 m_webWidth( 0 ),
52 m_maxError( 0 ),
54 {
55 m_bridgeRule.m_Name = _( "board setup solder mask min width" );
56 }
57
59 {
60 }
61
62 virtual bool Run() override;
63
64 virtual const wxString GetName() const override
65 {
66 return wxT( "solder_mask_issues" );
67 };
68
69 virtual const wxString GetDescription() const override
70 {
71 return wxT( "Tests for silkscreen being clipped by solder mask and copper being exposed "
72 "by mask apertures of other nets" );
73 }
74
75private:
76 void addItemToRTrees( BOARD_ITEM* aItem );
77 void buildRTrees();
78
80 void testMaskBridges();
81
82 void testItemAgainstItems( BOARD_ITEM* aItem, const BOX2I& aItemBBox,
83 PCB_LAYER_ID aRefLayer, PCB_LAYER_ID aTargetLayer );
84 void testMaskItemAgainstZones( BOARD_ITEM* item, const BOX2I& itemBBox,
85 PCB_LAYER_ID refLayer, PCB_LAYER_ID targetLayer );
86
87 bool checkMaskAperture( BOARD_ITEM* aMaskItem, BOARD_ITEM* aTestItem, PCB_LAYER_ID aTestLayer,
88 int aTestNet, BOARD_ITEM** aCollidingItem );
89
90 bool checkItemMask( BOARD_ITEM* aMaskItem, int aTestNet );
91
92private:
94
99
100 std::unique_ptr<DRC_RTREE> m_fullSolderMaskRTree;
101 std::unique_ptr<DRC_RTREE> m_itemTree;
102
103 std::unordered_map<PTR_PTR_CACHE_KEY, LSET> m_checkedPairs;
104
105 // Shapes used to define solder mask apertures don't have nets, so we assign them the
106 // first object+net that bridges their aperture (after which any other nets will generate
107 // violations).
108 std::unordered_map<PTR_LAYER_CACHE_KEY, std::pair<BOARD_ITEM*, int>> m_maskApertureNetMap;
109};
110
111
113{
114 ZONE* solderMask = m_board->m_SolderMask;
115
116 if( aItem->Type() == PCB_ZONE_T || aItem->Type() == PCB_FP_ZONE_T )
117 {
118 ZONE* zone = static_cast<ZONE*>( aItem );
119
120 for( PCB_LAYER_ID layer : { F_Mask, B_Mask } )
121 {
122 if( zone->IsOnLayer( layer ) )
123 {
124 solderMask->GetFill( layer )->BooleanAdd( *zone->GetFilledPolysList( layer ),
126 }
127 }
128 }
129 else if( aItem->Type() == PCB_PAD_T )
130 {
131 for( PCB_LAYER_ID layer : { F_Mask, B_Mask } )
132 {
133 if( aItem->IsOnLayer( layer ) )
134 {
135 PAD* pad = static_cast<PAD*>( aItem );
136 int clearance = ( m_webWidth / 2 ) + pad->GetSolderMaskExpansion();
137
138 aItem->TransformShapeToPolygon( *solderMask->GetFill( layer ), layer, clearance,
140
141 m_itemTree->Insert( aItem, layer, m_largestClearance );
142 }
143 }
144 }
145 else if( aItem->Type() == PCB_VIA_T )
146 {
147 for( PCB_LAYER_ID layer : { F_Mask, B_Mask } )
148 {
149 if( aItem->IsOnLayer( layer ) )
150 {
151 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
152 int clearance = ( m_webWidth / 2 ) + via->GetSolderMaskExpansion();
153
154 via->TransformShapeToPolygon( *solderMask->GetFill( layer ), layer, clearance,
156
157 m_itemTree->Insert( aItem, layer, m_largestClearance );
158 }
159 }
160 }
161 else
162 {
163 for( PCB_LAYER_ID layer : { F_Mask, B_Mask } )
164 {
165 if( aItem->IsOnLayer( layer ) )
166 {
167 aItem->TransformShapeToPolygon( *solderMask->GetFill( layer ), layer,
169
170 m_itemTree->Insert( aItem, layer, m_largestClearance );
171 }
172 }
173 }
174}
175
176
178{
179 ZONE* solderMask = m_board->m_SolderMask;
180 LSET layers = { 4, F_Mask, B_Mask, F_Cu, B_Cu };
181
182 const size_t progressDelta = 500;
183 int count = 0;
184 int ii = 0;
185
186 solderMask->GetFill( F_Mask )->RemoveAllContours();
187 solderMask->GetFill( B_Mask )->RemoveAllContours();
188
189 m_fullSolderMaskRTree = std::make_unique<DRC_RTREE>();
190 m_itemTree = std::make_unique<DRC_RTREE>();
191
193 [&]( BOARD_ITEM* item ) -> bool
194 {
195 ++count;
196 return true;
197 } );
198
200 [&]( BOARD_ITEM* item ) -> bool
201 {
202 if( !reportProgress( ii++, count, progressDelta ) )
203 return false;
204
205 addItemToRTrees( item );
206 return true;
207 } );
208
211
213
214 solderMask->GetFill( F_Mask )->Deflate( m_webWidth / 2, numSegs );
215 solderMask->GetFill( B_Mask )->Deflate( m_webWidth / 2, numSegs );
216
217 solderMask->SetFillFlag( F_Mask, true );
218 solderMask->SetFillFlag( B_Mask, true );
219 solderMask->SetIsFilled( true );
220
221 solderMask->CacheTriangulation();
222
223 m_fullSolderMaskRTree->Insert( solderMask, F_Mask );
224 m_fullSolderMaskRTree->Insert( solderMask, B_Mask );
225
226 m_checkedPairs.clear();
227}
228
229
231{
232 LSET silkLayers = { 2, F_SilkS, B_SilkS };
233
234 const size_t progressDelta = 250;
235 int count = 0;
236 int ii = 0;
237
239 [&]( BOARD_ITEM* item ) -> bool
240 {
241 ++count;
242 return true;
243 } );
244
246 [&]( BOARD_ITEM* item ) -> bool
247 {
249 return false;
250
251 if( !reportProgress( ii++, count, progressDelta ) )
252 return false;
253
254 if( isInvisibleText( item ) )
255 return true;
256
257 for( PCB_LAYER_ID layer : silkLayers.Seq() )
258 {
259 if( !item->IsOnLayer( layer ) )
260 continue;
261
262 BOX2I itemBBox = item->GetBoundingBox();
263 DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( SILK_CLEARANCE_CONSTRAINT,
264 item, nullptr, layer );
265 int clearance = constraint.GetValue().Min();
266 int actual;
267 VECTOR2I pos;
268
269 if( constraint.GetSeverity() == RPT_SEVERITY_IGNORE || clearance <= 0 )
270 return true;
271
272 std::shared_ptr<SHAPE> itemShape = item->GetEffectiveShape( layer );
273
274 if( m_fullSolderMaskRTree->QueryColliding( itemBBox, itemShape.get(), layer,
275 clearance, &actual, &pos ) )
276 {
277 auto drce = DRC_ITEM::Create( DRCE_SILK_CLEARANCE );
278 wxString msg = formatMsg( _( "(%s clearance %s; actual %s)" ),
279 constraint.GetName(),
280 clearance,
281 actual );
282
283 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
284 drce->SetItems( item );
285 drce->SetViolatingRule( constraint.GetParentRule() );
286
287 reportViolation( drce, pos, layer );
288 }
289 }
290
291 return true;
292 } );
293}
294
295
297{
298 if( aItem->Type() == PCB_PAD_T )
299 {
300 PAD* pad = static_cast<PAD*>( aItem );
301
302 if( pad->GetAttribute() == PAD_ATTRIB::NPTH
303 && ( pad->GetShape() == PAD_SHAPE::CIRCLE || pad->GetShape() == PAD_SHAPE::OVAL )
304 && pad->GetSize().x <= pad->GetDrillSize().x
305 && pad->GetSize().y <= pad->GetDrillSize().y )
306 {
307 return true;
308 }
309 }
310
311 return false;
312}
313
314
315// Simple mask apertures aren't associated with copper items, so they only constitute a bridge
316// when they expose other copper items having at least two distinct nets. We use a map to record
317// the first net exposed by each mask aperture (on each copper layer).
318//
319// Note that this algorithm is also used for free pads.
320
322{
323 if( aItem->Type() == PCB_PAD_T && static_cast<PAD*>( aItem )->IsFreePad() )
324 return true;
325
326 static const LSET saved( 2, F_Mask, B_Mask );
327
328 LSET maskLayers = aItem->GetLayerSet() & saved;
329 LSET otherLayers = aItem->GetLayerSet() & ~saved;
330
331 return maskLayers.count() > 0 && otherLayers.count() == 0;
332}
333
334
336 PCB_LAYER_ID aTestLayer, int aTestNet,
337 BOARD_ITEM** aCollidingItem )
338{
339 if( aTestLayer == F_Mask && !aTestItem->IsOnLayer( F_Cu ) )
340 return false;
341
342 if( aTestLayer == B_Mask && !aTestItem->IsOnLayer( B_Cu ) )
343 return false;
344
345 FOOTPRINT* fp = static_cast<FOOTPRINT*>( aMaskItem->GetParentFootprint() );
346
347 if( fp && ( fp->GetAttributes() & FP_ALLOW_SOLDERMASK_BRIDGES ) > 0 )
348 {
349 // Mask apertures in footprints which allow soldermask bridges are ignored entirely.
350 return false;
351 }
352
353 PTR_LAYER_CACHE_KEY key = { aMaskItem, aTestLayer };
354
355 auto ii = m_maskApertureNetMap.find( key );
356
357 if( ii == m_maskApertureNetMap.end() )
358 {
359 m_maskApertureNetMap[ key ] = { aTestItem, aTestNet };
360
361 // First net; no bridge yet....
362 return false;
363 }
364
365 if( ii->second.second == aTestNet && aTestNet > 0 )
366 {
367 // Same net; still no bridge...
368 return false;
369 }
370
371 *aCollidingItem = ii->second.first;
372 return true;
373}
374
375
377{
378 FOOTPRINT* fp = static_cast<FOOTPRINT*>( aMaskItem->GetParentFootprint() );
379
380 wxCHECK( fp, false );
381
382 if( ( fp->GetAttributes() & FP_ALLOW_SOLDERMASK_BRIDGES ) > 0 )
383 {
384 // If we're allowing bridges then we're allowing bridges. Nothing to check.
385 return false;
386 }
387
388 // Graphic items are used to implement net-ties between pads of a group within a net-tie
389 // footprint. They must be allowed to intrude into their pad's mask aperture.
390 if( aTestNet < 0 && aMaskItem->Type() == PCB_PAD_T && fp->IsNetTie() )
391 {
392 std::map<wxString, int> padNumberToGroupIdxMap = fp->MapPadNumbersToNetTieGroups();
393
394 if( padNumberToGroupIdxMap[ static_cast<PAD*>( aMaskItem )->GetNumber() ] >= 0 )
395 return false;
396 }
397
398 return true;
399}
400
401
403 PCB_LAYER_ID aRefLayer,
404 PCB_LAYER_ID aTargetLayer )
405{
406 int itemNet = -1;
407
408 if( aItem->IsConnected() )
409 itemNet = static_cast<BOARD_CONNECTED_ITEM*>( aItem )->GetNetCode();
410
412 PAD* pad = dynamic_cast<PAD*>( aItem );
413 PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem );
414 std::shared_ptr<SHAPE> itemShape = aItem->GetEffectiveShape( aRefLayer );
415
416 m_itemTree->QueryColliding( aItem, aRefLayer, aTargetLayer,
417 // Filter:
418 [&]( BOARD_ITEM* other ) -> bool
419 {
420 FOOTPRINT* itemFP = static_cast<FOOTPRINT*>( aItem->GetParentFootprint() );
421 PAD* otherPad = dynamic_cast<PAD*>( other );
422 int otherNet = -1;
423
424 if( other->IsConnected() )
425 otherNet = static_cast<BOARD_CONNECTED_ITEM*>( other )->GetNetCode();
426
427 if( otherNet > 0 && otherNet == itemNet )
428 return false;
429
430 if( isNullAperture( other ) )
431 return false;
432
433 if( itemFP && itemFP == other->GetParentFootprint() )
434 {
435 // Board-wide exclusion
437 return false;
438
439 // Footprint-specific exclusion
440 if( ( itemFP->GetAttributes() & FP_ALLOW_SOLDERMASK_BRIDGES ) > 0 )
441 return false;
442 }
443
444 if( pad && otherPad && ( pad->SameLogicalPadAs( otherPad )
445 || pad->SharesNetTieGroup( otherPad ) ) )
446 {
447 return false;
448 }
449
450 BOARD_ITEM* a = aItem;
451 BOARD_ITEM* b = other;
452
453 // store canonical order so we don't collide in both directions (a:b and b:a)
454 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
455 std::swap( a, b );
456
457 auto it = m_checkedPairs.find( { a, b } );
458
459 if( it != m_checkedPairs.end() && it->second.test( aTargetLayer ) )
460 {
461 return false;
462 }
463 else
464 {
465 m_checkedPairs[ { a, b } ].set( aTargetLayer );
466 return true;
467 }
468 },
469 // Visitor:
470 [&]( BOARD_ITEM* other ) -> bool
471 {
472 PAD* otherPad = dynamic_cast<PAD*>( other );
473 PCB_VIA* otherVia = dynamic_cast<PCB_VIA*>( other );
474 auto otherShape = other->GetEffectiveShape( aTargetLayer );
475 int otherNet = -1;
476
477 if( other->IsConnected() )
478 otherNet = static_cast<BOARD_CONNECTED_ITEM*>( other )->GetNetCode();
479
480 int actual;
481 VECTOR2I pos;
482 int clearance = 0;
483
484 if( aRefLayer == F_Mask || aRefLayer == B_Mask )
485 {
486 // Aperture-to-aperture must enforce web-min-width
487 clearance = m_webWidth;
488 }
489 else // ( aRefLayer == F_Cu || aRefLayer == B_Cu )
490 {
491 // Copper-to-aperture uses the solder-mask-to-copper-clearance
493 }
494
495 if( pad )
496 clearance += pad->GetSolderMaskExpansion();
497 else if( via && !via->IsTented() )
498 clearance += via->GetSolderMaskExpansion();
499
500 if( otherPad )
501 clearance += otherPad->GetSolderMaskExpansion();
502 else if( otherVia && !otherVia->IsTented() )
503 clearance += otherVia->GetSolderMaskExpansion();
504
505 if( itemShape->Collide( otherShape.get(), clearance, &actual, &pos ) )
506 {
507 wxString msg;
508 BOARD_ITEM* colliding = nullptr;
509
510 if( aTargetLayer == F_Mask )
511 msg = _( "Front solder mask aperture bridges items with different nets" );
512 else
513 msg = _( "Rear solder mask aperture bridges items with different nets" );
514
515 // Simple mask apertures aren't associated with copper items, so they only
516 // constitute a bridge when they expose other copper items having at least
517 // two distinct nets.
518 if( isMaskAperture( aItem ) )
519 {
520 if( checkMaskAperture( aItem, other, aRefLayer, otherNet, &colliding ) )
521 {
523
524 drce->SetErrorMessage( msg );
525 drce->SetItems( aItem, colliding, other );
526 drce->SetViolatingRule( &m_bridgeRule );
527 reportViolation( drce, pos, aTargetLayer );
528 }
529 }
530 else if( isMaskAperture( other ) )
531 {
532 if( checkMaskAperture( other, aItem, aRefLayer, itemNet, &colliding ) )
533 {
535
536 drce->SetErrorMessage( msg );
537 drce->SetItems( other, colliding, aItem );
538 drce->SetViolatingRule( &m_bridgeRule );
539 reportViolation( drce, pos, aTargetLayer );
540 }
541 }
542 else if( checkItemMask( other, itemNet ) )
543 {
545
546 drce->SetErrorMessage( msg );
547 drce->SetItems( aItem, other );
548 drce->SetViolatingRule( &m_bridgeRule );
549 reportViolation( drce, pos, aTargetLayer );
550 }
551 }
552
553 return !m_drcEngine->IsCancelled();
554 },
556}
557
558
560 const BOX2I& aItemBBox,
561 PCB_LAYER_ID aMaskLayer,
562 PCB_LAYER_ID aTargetLayer )
563{
564 for( ZONE* zone : m_board->m_DRCCopperZones )
565 {
566 if( !zone->GetLayerSet().test( aTargetLayer ) )
567 continue;
568
569 int zoneNet = zone->GetNetCode();
570
571 if( aItem->IsConnected() )
572 {
573 BOARD_CONNECTED_ITEM* connectedItem = static_cast<BOARD_CONNECTED_ITEM*>( aItem );
574
575 if( zoneNet == connectedItem->GetNetCode() && zoneNet > 0 )
576 continue;
577 }
578
579 BOX2I inflatedBBox( aItemBBox );
581
582 if( aItem->Type() == PCB_PAD_T )
583 clearance += static_cast<PAD*>( aItem )->GetSolderMaskExpansion();
584 else if( aItem->Type() == PCB_VIA_T )
585 clearance += static_cast<PCB_VIA*>( aItem )->GetSolderMaskExpansion();
586
587 inflatedBBox.Inflate( clearance );
588
589 if( !inflatedBBox.Intersects( zone->GetBoundingBox() ) )
590 continue;
591
592 DRC_RTREE* zoneTree = m_board->m_CopperZoneRTreeCache[ zone ].get();
593 int actual;
594 VECTOR2I pos;
595
596 std::shared_ptr<SHAPE> itemShape = aItem->GetEffectiveShape( aMaskLayer );
597
598 if( zoneTree && zoneTree->QueryColliding( aItemBBox, itemShape.get(), aTargetLayer,
599 clearance, &actual, &pos ) )
600 {
601 wxString msg;
602 BOARD_ITEM* colliding = nullptr;
603
604 if( aMaskLayer == F_Mask )
605 msg = _( "Front solder mask aperture bridges items with different nets" );
606 else
607 msg = _( "Rear solder mask aperture bridges items with different nets" );
608
609 // Simple mask apertures aren't associated with copper items, so they only constitute
610 // a bridge when they expose other copper items having at least two distinct nets.
611 if( isMaskAperture( aItem ) && zoneNet >= 0 )
612 {
613 if( checkMaskAperture( aItem, zone, aTargetLayer, zoneNet, &colliding ) )
614 {
616
617 drce->SetErrorMessage( msg );
618 drce->SetItems( aItem, colliding, zone );
619 drce->SetViolatingRule( &m_bridgeRule );
620 reportViolation( drce, pos, aTargetLayer );
621 }
622 }
623 else
624 {
626
627 drce->SetErrorMessage( msg );
628 drce->SetItems( aItem, zone );
629 drce->SetViolatingRule( &m_bridgeRule );
630 reportViolation( drce, pos, aTargetLayer );
631 }
632 }
633
634 if( m_drcEngine->IsCancelled() )
635 return;
636 }
637}
638
639
641{
642 LSET copperAndMaskLayers = { 4, F_Mask, B_Mask, F_Cu, B_Cu };
643
644 const size_t progressDelta = 250;
645 int count = 0;
646 int ii = 0;
647
648 forEachGeometryItem( s_allBasicItemsButZones, copperAndMaskLayers,
649 [&]( BOARD_ITEM* item ) -> bool
650 {
651 ++count;
652 return true;
653 } );
654
655 forEachGeometryItem( s_allBasicItemsButZones, copperAndMaskLayers,
656 [&]( BOARD_ITEM* item ) -> bool
657 {
659 return false;
660
661 if( !reportProgress( ii++, count, progressDelta ) )
662 return false;
663
664 BOX2I itemBBox = item->GetBoundingBox();
665
666 if( item->IsOnLayer( F_Mask ) && !isNullAperture( item ) )
667 {
668 // Test for aperture-to-aperture collisions
669 testItemAgainstItems( item, itemBBox, F_Mask, F_Mask );
670
671 // Test for aperture-to-zone collisions
672 testMaskItemAgainstZones( item, itemBBox, F_Mask, F_Cu );
673 }
674 else if( item->IsOnLayer( F_Cu ) )
675 {
676 // Test for copper-item-to-aperture collisions
677 testItemAgainstItems( item, itemBBox, F_Cu, F_Mask );
678 }
679
680 if( item->IsOnLayer( B_Mask ) && !isNullAperture( item ) )
681 {
682 // Test for aperture-to-aperture collisions
683 testItemAgainstItems( item, itemBBox, B_Mask, B_Mask );
684
685 // Test for aperture-to-zone collisions
686 testMaskItemAgainstZones( item, itemBBox, B_Mask, B_Cu );
687 }
688 else if( item->IsOnLayer( B_Cu ) )
689 {
690 // Test for copper-item-to-aperture collisions
691 testItemAgainstItems( item, itemBBox, B_Cu, B_Mask );
692 }
693
694 return true;
695 } );
696}
697
698
700{
703 {
704 reportAux( wxT( "Solder mask violations ignored. Tests not run." ) );
705 return true; // continue with other tests
706 }
707
712
713 for( FOOTPRINT* footprint : m_board->Footprints() )
714 {
715 for( PAD* pad : footprint->Pads() )
716 m_largestClearance = std::max( m_largestClearance, pad->GetSolderMaskExpansion() );
717 }
718
719 // Order is important here: m_webWidth must be added in before m_largestCourtyardClearance is
720 // maxed with the various SILK_CLEARANCE_CONSTRAINTS.
722
723 DRC_CONSTRAINT worstClearanceConstraint;
724
725 if( m_drcEngine->QueryWorstConstraint( SILK_CLEARANCE_CONSTRAINT, worstClearanceConstraint ) )
726 m_largestClearance = std::max( m_largestClearance, worstClearanceConstraint.m_Value.Min() );
727
728 reportAux( wxT( "Worst clearance : %d nm" ), m_largestClearance );
729
730 if( !reportPhase( _( "Building solder mask..." ) ) )
731 return false; // DRC cancelled
732
733 m_checkedPairs.clear();
734 m_maskApertureNetMap.clear();
735
736 buildRTrees();
737
738 if( !reportPhase( _( "Checking solder mask to silk clearance..." ) ) )
739 return false; // DRC cancelled
740
742
743 if( !reportPhase( _( "Checking solder mask web integrity..." ) ) )
744 return false; // DRC cancelled
745
747
749
750 return !m_drcEngine->IsCancelled();
751}
752
753
754namespace detail
755{
757}
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
Container for design settings for a BOARD object.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:70
virtual bool IsConnected() const
Returns information if the object is derived from BOARD_CONNECTED_ITEM.
Definition: board_item.h:127
virtual void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const
Convert the item shape to a closed polygon.
Definition: board_item.cpp:196
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: board_item.cpp:219
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:43
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:197
BOARD_ITEM_CONTAINER * GetParentFootprint() const
Definition: board_item.cpp:239
virtual bool IsOnLayer(PCB_LAYER_ID aLayer, bool aIncludeCourtyards=false) const
Test to see if this object is on the given layer.
Definition: board_item.h:257
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:269
std::vector< ZONE * > m_DRCCopperZones
Definition: board.h:1170
FOOTPRINTS & Footprints()
Definition: board.h:311
ZONE * m_SolderMask
Definition: board.h:1173
std::unordered_map< ZONE *, std::unique_ptr< DRC_RTREE > > m_CopperZoneRTreeCache
Definition: board.h:1164
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:704
bool Intersects(const BOX2< Vec > &aRect) const
Definition: box2.h:269
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:506
MINOPTMAX< int > m_Value
Definition: drc_rule.h:172
BOARD * GetBoard() const
Definition: drc_engine.h:89
bool IsErrorLimitExceeded(int error_code)
bool IsCancelled() const
bool QueryWorstConstraint(DRC_CONSTRAINT_T aRuleId, DRC_CONSTRAINT &aConstraint)
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
Definition: drc_item.cpp:325
Implement an R-tree for fast spatial and layer indexing of connectable items.
Definition: drc_rtree.h:48
int QueryColliding(BOARD_ITEM *aRefItem, PCB_LAYER_ID aRefLayer, PCB_LAYER_ID aTargetLayer, std::function< bool(BOARD_ITEM *)> aFilter=nullptr, std::function< bool(BOARD_ITEM *)> aVisitor=nullptr, int aClearance=0) const
This is a fast test which essentially does bounding-box overlap given a worst-case clearance.
Definition: drc_rtree.h:211
wxString m_Name
Definition: drc_rule.h:112
virtual const wxString GetName() const override
void testMaskItemAgainstZones(BOARD_ITEM *item, const BOX2I &itemBBox, PCB_LAYER_ID refLayer, PCB_LAYER_ID targetLayer)
bool checkMaskAperture(BOARD_ITEM *aMaskItem, BOARD_ITEM *aTestItem, PCB_LAYER_ID aTestLayer, int aTestNet, BOARD_ITEM **aCollidingItem)
std::unique_ptr< DRC_RTREE > m_fullSolderMaskRTree
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
virtual const wxString GetDescription() const override
std::unordered_map< PTR_PTR_CACHE_KEY, LSET > m_checkedPairs
bool checkItemMask(BOARD_ITEM *aMaskItem, int aTestNet)
std::unordered_map< PTR_LAYER_CACHE_KEY, std::pair< BOARD_ITEM *, int > > m_maskApertureNetMap
void testItemAgainstItems(BOARD_ITEM *aItem, const BOX2I &aItemBBox, PCB_LAYER_ID aRefLayer, PCB_LAYER_ID aTargetLayer)
Represent a DRC "provider" which runs some DRC functions over a BOARD and spits out #DRC_ITEMs and po...
static std::vector< KICAD_T > s_allBasicItemsButZones
virtual bool reportPhase(const wxString &aStageName)
int forEachGeometryItem(const std::vector< KICAD_T > &aTypes, LSET aLayers, const std::function< bool(BOARD_ITEM *)> &aFunc)
virtual bool reportProgress(int aCount, int aSize, int aDelta)
virtual void reportViolation(std::shared_ptr< DRC_ITEM > &item, const VECTOR2I &aMarkerPos, int aMarkerLayer)
virtual void reportAux(wxString fmt,...)
static std::vector< KICAD_T > s_allBasicItems
DRC_ENGINE * m_drcEngine
bool isInvisibleText(const BOARD_ITEM *aItem) const
virtual void reportRuleStatistics()
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition: eda_item.cpp:74
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
std::map< wxString, int > MapPadNumbersToNetTieGroups() const
Definition: footprint.cpp:2302
int GetAttributes() const
Definition: footprint.h:250
bool IsNetTie() const
Definition: footprint.h:257
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:532
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:411
T Min() const
Definition: minoptmax.h:33
Definition: pad.h:60
int GetSolderMaskExpansion() const
Definition: pad.cpp:834
bool IsFreePad() const
Definition: pad.cpp:189
bool IsTented() const override
Definition: pcb_track.cpp:463
int GetSolderMaskExpansion() const
Definition: pcb_track.cpp:474
void BooleanAdd(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset difference For aFastMode meaning, see function booleanOp.
void Deflate(int aAmount, int aCircleSegmentsCount, CORNER_STRATEGY aCornerStrategy=CHAMFER_ALL_CORNERS)
void Simplify(POLYGON_MODE aFastMode)
Handle a list of polygons defining a copper zone.
Definition: zone.h:57
virtual bool IsOnLayer(PCB_LAYER_ID, bool aIncludeCourtyards=false) const override
Test to see if this object is on the given layer.
Definition: zone.cpp:323
const std::shared_ptr< SHAPE_POLY_SET > & GetFilledPolysList(PCB_LAYER_ID aLayer) const
Definition: zone.h:608
void CacheTriangulation(PCB_LAYER_ID aLayer=UNDEFINED_LAYER)
Create a list of triangles that "fill" the solid areas used for instance to draw these solid areas on...
Definition: zone.cpp:1011
const BOX2I GetBoundingBox() const override
Definition: zone.cpp:329
void SetFillFlag(PCB_LAYER_ID aLayer, bool aFlag)
Definition: zone.h:240
SHAPE_POLY_SET * GetFill(PCB_LAYER_ID aLayer)
Definition: zone.h:614
void SetIsFilled(bool isFilled)
Definition: zone.h:243
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: zone.h:122
The common library.
@ DRCE_SOLDERMASK_BRIDGE
Definition: drc_item.h:85
@ DRCE_SILK_CLEARANCE
Definition: drc_item.h:88
@ SILK_CLEARANCE_CONSTRAINT
Definition: drc_rule.h:53
bool isMaskAperture(BOARD_ITEM *aItem)
bool isNullAperture(BOARD_ITEM *aItem)
#define _(s)
static constexpr EDA_ANGLE & FULL_CIRCLE
Definition: eda_angle.h:427
@ FP_ALLOW_SOLDERMASK_BRIDGES
Definition: footprint.h:74
@ ERROR_OUTSIDE
int GetArcToSegmentCount(int aRadius, int aErrorMax, const EDA_ANGLE &aArcAngle)
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:59
@ B_Mask
Definition: layer_ids.h:106
@ B_Cu
Definition: layer_ids.h:95
@ F_Mask
Definition: layer_ids.h:107
@ F_SilkS
Definition: layer_ids.h:104
@ B_SilkS
Definition: layer_ids.h:103
@ F_Cu
Definition: layer_ids.h:64
static DRC_REGISTER_TEST_PROVIDER< DRC_TEST_PROVIDER_ANNULAR_WIDTH > dummy
@ NPTH
like PAD_PTH, but not plated
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:102
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:112
@ PCB_FP_ZONE_T
class ZONE, managed by a footprint
Definition: typeinfo.h:100
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87