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* item );
77 void buildRTrees();
78
80 void testMaskBridges();
81
82 void testItemAgainstItems( BOARD_ITEM* aItem, const EDA_RECT& aItemBBox,
83 PCB_LAYER_ID aRefLayer, PCB_LAYER_ID aTargetLayer );
84 void testMaskItemAgainstZones( BOARD_ITEM* item, const EDA_RECT& 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
90private:
92
97
98 std::unique_ptr<DRC_RTREE> m_tesselatedTree;
99 std::unique_ptr<DRC_RTREE> m_itemTree;
100
101 std::unordered_map<PTR_PTR_LAYER_CACHE_KEY, int> m_checkedPairs;
102
103 // Shapes used to define solder mask apertures don't have nets, so we assign them the
104 // first object+net that bridges their aperture (after which any other nets will generate
105 // violations).
106 std::map< std::pair<BOARD_ITEM*, PCB_LAYER_ID>, std::pair<BOARD_ITEM*, int> > m_maskApertureNetMap;
107};
108
109
111{
112 ZONE* solderMask = m_board->m_SolderMask;
113
114 if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
115 {
116 ZONE* zone = static_cast<ZONE*>( item );
117
118 for( PCB_LAYER_ID layer : { F_Mask, B_Mask } )
119 {
120 if( zone->IsOnLayer( layer ) )
121 {
122 solderMask->GetFill( layer )->BooleanAdd( *zone->GetFilledPolysList( layer ),
124 }
125 }
126 }
127 else if( item->Type() == PCB_PAD_T )
128 {
129 for( PCB_LAYER_ID layer : { F_Mask, B_Mask } )
130 {
131 if( item->IsOnLayer( layer ) )
132 {
133 PAD* pad = static_cast<PAD*>( item );
134 int clearance = ( m_webWidth / 2 ) + pad->GetSolderMaskExpansion();
135
136 item->TransformShapeWithClearanceToPolygon( *solderMask->GetFill( layer ), layer,
137 clearance, m_maxError, ERROR_OUTSIDE );
138
139 m_itemTree->Insert( item, layer, m_largestClearance );
140 }
141 }
142 }
143 else if( item->Type() == PCB_VIA_T )
144 {
145 for( PCB_LAYER_ID layer : { F_Mask, B_Mask } )
146 {
147 if( item->IsOnLayer( layer ) )
148 {
149 PCB_VIA* via = static_cast<PCB_VIA*>( item );
150 int clearance = ( m_webWidth / 2 ) + via->GetSolderMaskExpansion();
151
152 via->TransformShapeWithClearanceToPolygon( *solderMask->GetFill( layer ), layer,
153 clearance, m_maxError, ERROR_OUTSIDE );
154
155 m_itemTree->Insert( item, layer, m_largestClearance );
156 }
157 }
158 }
159 else
160 {
161 for( PCB_LAYER_ID layer : { F_Mask, B_Mask } )
162 {
163 if( item->IsOnLayer( layer ) )
164 {
165 item->TransformShapeWithClearanceToPolygon( *solderMask->GetFill( layer ),
166 layer, m_webWidth / 2, m_maxError,
168
169 m_itemTree->Insert( item, layer, m_largestClearance );
170 }
171 }
172 }
173}
174
175
177{
178 ZONE* solderMask = m_board->m_SolderMask;
179 LSET layers = { 4, F_Mask, B_Mask, F_Cu, B_Cu };
180
181 const size_t progressDelta = 500;
182 int count = 0;
183 int ii = 0;
184
185 solderMask->GetFill( F_Mask )->RemoveAllContours();
186 solderMask->GetFill( B_Mask )->RemoveAllContours();
187
188 m_tesselatedTree = std::make_unique<DRC_RTREE>();
189 m_itemTree = std::make_unique<DRC_RTREE>();
190
192 [&]( BOARD_ITEM* item ) -> bool
193 {
194 ++count;
195 return true;
196 } );
197
199 [&]( BOARD_ITEM* item ) -> bool
200 {
201 if( !reportProgress( ii++, count, progressDelta ) )
202 return false;
203
204 addItemToRTrees( item );
205 return true;
206 } );
207
210
212
213 solderMask->GetFill( F_Mask )->Deflate( m_webWidth / 2, numSegs );
214 solderMask->GetFill( B_Mask )->Deflate( m_webWidth / 2, numSegs );
215
216 solderMask->SetFillFlag( F_Mask, true );
217 solderMask->SetFillFlag( B_Mask, true );
218 solderMask->SetIsFilled( true );
219
220 solderMask->CacheTriangulation();
221
222 m_tesselatedTree->Insert( solderMask, F_Mask );
223 m_tesselatedTree->Insert( solderMask, B_Mask );
224
225 m_checkedPairs.clear();
226}
227
228
230{
231 LSET silkLayers = { 2, F_SilkS, B_SilkS };
232
233 const size_t progressDelta = 250;
234 int count = 0;
235 int ii = 0;
236
238 [&]( BOARD_ITEM* item ) -> bool
239 {
240 ++count;
241 return true;
242 } );
243
245 [&]( BOARD_ITEM* item ) -> bool
246 {
248 return false;
249
250 if( !reportProgress( ii++, count, progressDelta ) )
251 return false;
252
253 if( isInvisibleText( item ) )
254 return true;
255
256 for( PCB_LAYER_ID layer : silkLayers.Seq() )
257 {
258 if( !item->IsOnLayer( layer ) )
259 continue;
260
261 EDA_RECT itemBBox = item->GetBoundingBox();
262 DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( SILK_CLEARANCE_CONSTRAINT,
263 item, nullptr, layer );
264 int clearance = constraint.GetValue().Min();
265 int actual;
266 VECTOR2I pos;
267
268 if( constraint.GetSeverity() == RPT_SEVERITY_IGNORE || clearance <= 0 )
269 return true;
270
271 std::shared_ptr<SHAPE> itemShape = item->GetEffectiveShape( layer );
272
273 if( m_tesselatedTree->QueryColliding( itemBBox, itemShape.get(), layer,
274 clearance, &actual, &pos ) )
275 {
276 auto drce = DRC_ITEM::Create( DRCE_SILK_CLEARANCE );
277 wxString msg;
278
279 msg.Printf( _( "(%s clearance %s; actual %s)" ),
280 constraint.GetName(),
281 MessageTextFromValue( userUnits(), clearance ),
282 MessageTextFromValue( userUnits(), actual ) );
283
284 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
285 drce->SetItems( item );
286 drce->SetViolatingRule( constraint.GetParentRule() );
287
288 reportViolation( drce, pos, layer );
289 }
290 }
291
292 return true;
293 } );
294}
295
296
298{
299 static const LSET saved( 2, F_Mask, B_Mask );
300
301 LSET maskLayers = aItem->GetLayerSet() & saved;
302 LSET otherLayers = aItem->GetLayerSet() & ~saved;
303
304 return maskLayers.count() > 0 && otherLayers.count() == 0;
305}
306
307
309{
310 if( aItem->Type() == PCB_PAD_T )
311 {
312 PAD* pad = static_cast<PAD*>( aItem );
313
314 if( pad->GetAttribute() == PAD_ATTRIB::NPTH
315 && ( pad->GetShape() == PAD_SHAPE::CIRCLE || pad->GetShape() == PAD_SHAPE::OVAL )
316 && pad->GetSize().x <= pad->GetDrillSize().x
317 && pad->GetSize().y <= pad->GetDrillSize().y )
318 {
319 return true;
320 }
321 }
322
323 return false;
324}
325
326
327// Simple mask apertures aren't associated with copper items, so they only constitute a bridge
328// when they expose other copper items having at least two distinct nets. We use a map to record
329// the first net exposed by each mask aperture (on each copper layer).
330
332 PCB_LAYER_ID aTestLayer, int aTestNet,
333 BOARD_ITEM** aCollidingItem )
334{
335 if( !IsCopperLayer( aTestLayer ) )
336 return false;
337
338 FOOTPRINT* fp = static_cast<FOOTPRINT*>( aMaskItem->GetParentFootprint() );
339
340 if( fp && ( fp->GetAttributes() & FP_ALLOW_SOLDERMASK_BRIDGES ) > 0 )
341 {
342 // Mask apertures in footprints which allow soldermask bridges are ignored entirely.
343 return false;
344 }
345
346 std::pair<BOARD_ITEM*, PCB_LAYER_ID> key = { aMaskItem, aTestLayer };
347
348 auto ii = m_maskApertureNetMap.find( key );
349
350 if( ii == m_maskApertureNetMap.end() )
351 {
352 m_maskApertureNetMap[ key ] = { aTestItem, aTestNet };
353
354 // First net; no bridge yet....
355 return false;
356 }
357
358 if( ii->second.second == aTestNet && aTestNet > 0 )
359 {
360 // Same net; still no bridge...
361 return false;
362 }
363
364 *aCollidingItem = ii->second.first;
365 return true;
366}
367
368
370 const EDA_RECT& aItemBBox,
371 PCB_LAYER_ID aRefLayer,
372 PCB_LAYER_ID aTargetLayer )
373{
374 int itemNet = -1;
375
376 if( aItem->IsConnected() )
377 itemNet = static_cast<BOARD_CONNECTED_ITEM*>( aItem )->GetNetCode();
378
380 PAD* pad = dynamic_cast<PAD*>( aItem );
381 PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem );
382 std::shared_ptr<SHAPE> itemShape = aItem->GetEffectiveShape( aRefLayer );
383
384 m_itemTree->QueryColliding( aItem, aRefLayer, aTargetLayer,
385 // Filter:
386 [&]( BOARD_ITEM* other ) -> bool
387 {
388 FOOTPRINT* itemFP = static_cast<FOOTPRINT*>( aItem->GetParentFootprint() );
389 PAD* otherPad = dynamic_cast<PAD*>( other );
390 int otherNet = -1;
391
392 if( other->IsConnected() )
393 otherNet = static_cast<BOARD_CONNECTED_ITEM*>( other )->GetNetCode();
394
395 if( otherNet > 0 && otherNet == itemNet )
396 return false;
397
398 if( isNullAperture( other ) )
399 return false;
400
401 if( itemFP && itemFP == other->GetParentFootprint() )
402 {
403 // Board-wide exclusion
405 return false;
406
407 // Footprint-specific exclusion
408 if( ( itemFP->GetAttributes() & FP_ALLOW_SOLDERMASK_BRIDGES ) > 0 )
409 return false;
410 }
411
412 if( pad && otherPad && pad->SameLogicalPadAs( otherPad ) )
413 {
414 return false;
415 }
416
417 BOARD_ITEM* a = aItem;
418 BOARD_ITEM* b = other;
419
420 // store canonical order so we don't collide in both directions
421 // (a:b and b:a)
422 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
423 std::swap( a, b );
424
425 if( m_checkedPairs.count( { a, b, aTargetLayer } ) )
426 {
427 return false;
428 }
429 else
430 {
431 m_checkedPairs[ { a, b, aTargetLayer } ] = 1;
432 return true;
433 }
434 },
435 // Visitor:
436 [&]( BOARD_ITEM* other ) -> bool
437 {
438 PAD* otherPad = dynamic_cast<PAD*>( other );
439 PCB_VIA* otherVia = dynamic_cast<PCB_VIA*>( other );
440 auto otherShape = other->GetEffectiveShape( aTargetLayer );
441 int otherNet = -1;
442
443 if( other->IsConnected() )
444 otherNet = static_cast<BOARD_CONNECTED_ITEM*>( other )->GetNetCode();
445
446 int actual;
447 VECTOR2I pos;
448 int clearance = 0;
449
450 if( aRefLayer == F_Mask || aRefLayer == B_Mask )
451 {
452 // Aperture-to-aperture must enforce web-min-width
453 clearance = m_webWidth;
454 }
455 else // ( aRefLayer == F_Cu || aRefLayer == B_Cu )
456 {
457 // Copper-to-aperture uses the solder-mask-to-copper-clearance
459 }
460
461 if( pad )
462 clearance += pad->GetSolderMaskExpansion();
463 else if( via )
464 clearance += via->GetSolderMaskExpansion();
465
466 if( otherPad )
467 clearance += otherPad->GetSolderMaskExpansion();
468 else if( otherVia )
469 clearance += otherVia->GetSolderMaskExpansion();
470
471 if( itemShape->Collide( otherShape.get(), clearance, &actual, &pos ) )
472 {
473 wxString msg;
474 BOARD_ITEM* colliding = nullptr;
475
476 if( aTargetLayer == F_Mask )
477 msg = _( "Front solder mask aperture bridges items with different nets" );
478 else
479 msg = _( "Rear solder mask aperture bridges items with different nets" );
480
481 // Simple mask apertures aren't associated with copper items, so they only
482 // constitute a bridge when they expose other copper items having at least
483 // two distinct nets.
484 if( isMaskAperture( aItem ) )
485 {
486 if( checkMaskAperture( aItem, other, aRefLayer, otherNet, &colliding ) )
487 {
489
490 drce->SetErrorMessage( msg );
491 drce->SetItems( aItem, colliding, other );
492 drce->SetViolatingRule( &m_bridgeRule );
493 reportViolation( drce, pos, aTargetLayer );
494 }
495 }
496 else if( isMaskAperture( other ) )
497 {
498 if( checkMaskAperture( other, aItem, aRefLayer, itemNet, &colliding ) )
499 {
501
502 drce->SetErrorMessage( msg );
503 drce->SetItems( other, colliding, aItem );
504 drce->SetViolatingRule( &m_bridgeRule );
505 reportViolation( drce, pos, aTargetLayer );
506 }
507 }
508 else
509 {
511
512 drce->SetErrorMessage( msg );
513 drce->SetItems( aItem, other );
514 drce->SetViolatingRule( &m_bridgeRule );
515 reportViolation( drce, pos, aTargetLayer );
516 }
517 }
518
519 return !m_drcEngine->IsCancelled();
520 },
522}
523
524
526 const EDA_RECT& aItemBBox,
527 PCB_LAYER_ID aMaskLayer,
528 PCB_LAYER_ID aTargetLayer )
529{
530 for( ZONE* zone : m_board->m_DRCCopperZones )
531 {
532 if( !zone->GetLayerSet().test( aTargetLayer ) )
533 continue;
534
535 int zoneNet = zone->GetNetCode();
536
537 if( aItem->IsConnected() )
538 {
539 BOARD_CONNECTED_ITEM* connectedItem = static_cast<BOARD_CONNECTED_ITEM*>( aItem );
540
541 if( zoneNet == connectedItem->GetNetCode() && zoneNet > 0 )
542 continue;
543 }
544
545 if( aItem->GetBoundingBox().Intersects( zone->GetCachedBoundingBox() ) )
546 {
547 DRC_RTREE* zoneTree = m_board->m_CopperZoneRTreeCache[ zone ].get();
549 int actual;
550 VECTOR2I pos;
551
552 std::shared_ptr<SHAPE> itemShape = aItem->GetEffectiveShape( aMaskLayer );
553
554 if( aItem->Type() == PCB_PAD_T )
555 {
556 PAD* pad = static_cast<PAD*>( aItem );
557
558 clearance += pad->GetSolderMaskExpansion();
559 }
560 else if( aItem->Type() == PCB_VIA_T )
561 {
562 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
563
564 clearance += via->GetSolderMaskExpansion();
565 }
566
567 if( zoneTree && zoneTree->QueryColliding( aItemBBox, itemShape.get(), aTargetLayer,
568 clearance, &actual, &pos ) )
569 {
570 wxString msg;
571 BOARD_ITEM* colliding = nullptr;
572
573 if( aMaskLayer == F_Mask )
574 msg = _( "Front solder mask aperture bridges items with different nets" );
575 else
576 msg = _( "Rear solder mask aperture bridges items with different nets" );
577
578 // Simple mask apertures aren't associated with copper items, so they only
579 // constitute a bridge when they expose other copper items having at least
580 // two distinct nets.
581 if( isMaskAperture( aItem ) && zoneNet >= 0 )
582 {
583 if( checkMaskAperture( aItem, zone, aTargetLayer, zoneNet, &colliding ) )
584 {
586
587 drce->SetErrorMessage( msg );
588 drce->SetItems( aItem, colliding, zone );
589 drce->SetViolatingRule( &m_bridgeRule );
590 reportViolation( drce, pos, aTargetLayer );
591 }
592 }
593 else
594 {
596
597 drce->SetErrorMessage( msg );
598 drce->SetItems( aItem, zone );
599 drce->SetViolatingRule( &m_bridgeRule );
600 reportViolation( drce, pos, aTargetLayer );
601 }
602 }
603 }
604
605 if( m_drcEngine->IsCancelled() )
606 return;
607 }
608}
609
610
612{
613 LSET copperAndMaskLayers = { 4, F_Mask, B_Mask, F_Cu, B_Cu };
614
615 const size_t progressDelta = 250;
616 int count = 0;
617 int ii = 0;
618
619 forEachGeometryItem( s_allBasicItemsButZones, copperAndMaskLayers,
620 [&]( BOARD_ITEM* item ) -> bool
621 {
622 ++count;
623 return true;
624 } );
625
626 forEachGeometryItem( s_allBasicItemsButZones, copperAndMaskLayers,
627 [&]( BOARD_ITEM* item ) -> bool
628 {
630 return false;
631
632 if( !reportProgress( ii++, count, progressDelta ) )
633 return false;
634
635 EDA_RECT itemBBox = item->GetBoundingBox();
636
637 if( item->IsOnLayer( F_Mask ) && !isNullAperture( item ) )
638 {
639 // Test for aperture-to-aperture collisions
640 testItemAgainstItems( item, itemBBox, F_Mask, F_Mask );
641
642 // Test for aperture-to-zone collisions
643 testMaskItemAgainstZones( item, itemBBox, F_Mask, F_Cu );
644 }
645 else if( item->IsOnLayer( F_Cu ) )
646 {
647 // Test for copper-item-to-aperture collisions
648 testItemAgainstItems( item, itemBBox, F_Cu, F_Mask );
649 }
650
651 if( item->IsOnLayer( B_Mask ) && !isNullAperture( item ) )
652 {
653 // Test for aperture-to-aperture collisions
654 testItemAgainstItems( item, itemBBox, B_Mask, B_Mask );
655
656 // Test for aperture-to-zone collisions
657 testMaskItemAgainstZones( item, itemBBox, B_Mask, B_Cu );
658 }
659 else if( item->IsOnLayer( B_Cu ) )
660 {
661 // Test for copper-item-to-aperture collisions
662 testItemAgainstItems( item, itemBBox, B_Cu, B_Mask );
663 }
664
665 return true;
666 } );
667}
668
669
671{
674 {
675 reportAux( wxT( "Solder mask violations ignored. Tests not run." ) );
676 return true; // continue with other tests
677 }
678
683
684 for( FOOTPRINT* footprint : m_board->Footprints() )
685 {
686 for( PAD* pad : footprint->Pads() )
687 m_largestClearance = std::max( m_largestClearance, pad->GetSolderMaskExpansion() );
688 }
689
690 // Order is important here: m_webWidth must be added in before m_largestCourtyardClearance is maxed
691 // with the various SILK_CLEARANCE_CONSTRAINTS.
693
694 DRC_CONSTRAINT worstClearanceConstraint;
695
696 if( m_drcEngine->QueryWorstConstraint( SILK_CLEARANCE_CONSTRAINT, worstClearanceConstraint ) )
697 m_largestClearance = std::max( m_largestClearance, worstClearanceConstraint.m_Value.Min() );
698
699 reportAux( wxT( "Worst clearance : %d nm" ), m_largestClearance );
700
701 if( !reportPhase( _( "Building solder mask..." ) ) )
702 return false; // DRC cancelled
703
704 m_checkedPairs.clear();
705 m_maskApertureNetMap.clear();
706
707 buildRTrees();
708
709 if( !reportPhase( _( "Checking solder mask to silk clearance..." ) ) )
710 return false; // DRC cancelled
711
713
714 if( !reportPhase( _( "Checking solder mask web integrity..." ) ) )
715 return false; // DRC cancelled
716
718
720
721 return !m_drcEngine->IsCancelled();
722}
723
724
725namespace detail
726{
728}
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:53
virtual bool IsConnected() const
Returns information if the object is derived from BOARD_CONNECTED_ITEM.
Definition: board_item.h:108
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Test to see if this object is on the given layer.
Definition: board_item.h:229
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:197
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:37
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:175
BOARD_ITEM_CONTAINER * GetParentFootprint() const
Definition: board_item.cpp:217
virtual void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, PCB_LAYER_ID aLayer, int aClearanceValue, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const
Convert the item shape to a closed polygon.
Definition: board_item.cpp:172
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:240
std::vector< ZONE * > m_DRCCopperZones
Definition: board.h:1133
FOOTPRINTS & Footprints()
Definition: board.h:282
ZONE * m_SolderMask
Definition: board.h:1136
std::unordered_map< ZONE *, std::unique_ptr< DRC_RTREE > > m_CopperZoneRTreeCache
Definition: board.h:1128
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:619
MINOPTMAX< int > m_Value
Definition: drc_rule.h:170
BOARD * GetBoard() const
Definition: drc_engine.h:88
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:324
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:110
void testItemAgainstItems(BOARD_ITEM *aItem, const EDA_RECT &aItemBBox, PCB_LAYER_ID aRefLayer, PCB_LAYER_ID aTargetLayer)
virtual const wxString GetName() const override
bool checkMaskAperture(BOARD_ITEM *aMaskItem, BOARD_ITEM *aTestItem, PCB_LAYER_ID aTestLayer, int aTestNet, BOARD_ITEM **aCollidingItem)
std::unique_ptr< DRC_RTREE > m_tesselatedTree
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
std::map< std::pair< BOARD_ITEM *, PCB_LAYER_ID >, std::pair< BOARD_ITEM *, int > > m_maskApertureNetMap
virtual const wxString GetDescription() const override
std::unordered_map< PTR_PTR_LAYER_CACHE_KEY, int > m_checkedPairs
void testMaskItemAgainstZones(BOARD_ITEM *item, const EDA_RECT &itemBBox, PCB_LAYER_ID refLayer, PCB_LAYER_ID targetLayer)
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 reportAux(wxString fmt,...)
virtual void reportViolation(std::shared_ptr< DRC_ITEM > &item, const VECTOR2I &aMarkerPos, PCB_LAYER_ID aMarkerLayer)
static std::vector< KICAD_T > s_allBasicItems
DRC_ENGINE * m_drcEngine
bool isInvisibleText(const BOARD_ITEM *aItem) const
virtual void reportRuleStatistics()
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:112
virtual const EDA_RECT GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition: eda_item.cpp:75
Handle the component boundary box.
Definition: eda_rect.h:44
bool Intersects(const EDA_RECT &aRect) const
Test for a common area between rectangles.
Definition: eda_rect.cpp:150
int GetAttributes() const
Definition: footprint.h:246
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:529
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:59
int GetSolderMaskExpansion() const
Definition: pad.cpp:774
int GetSolderMaskExpansion() const
Definition: pcb_track.cpp:404
void Deflate(int aAmount, int aCircleSegmentsCount, CORNER_STRATEGY aCornerStrategy=ROUND_ALL_CORNERS)
void BooleanAdd(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset difference For aFastMode meaning, see function booleanOp.
void Simplify(POLYGON_MODE aFastMode)
Handle a list of polygons defining a copper zone.
Definition: zone.h:58
const EDA_RECT GetCachedBoundingBox() const
ONLY TO BE USED BY CLIENTS WHICH SET UP THE CACHE!
Definition: zone.h:134
const std::shared_ptr< SHAPE_POLY_SET > & GetFilledPolysList(PCB_LAYER_ID aLayer) const
Definition: zone.h:603
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:954
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: zone.cpp:282
void SetFillFlag(PCB_LAYER_ID aLayer, bool aFlag)
Definition: zone.h:239
SHAPE_POLY_SET * GetFill(PCB_LAYER_ID aLayer)
Definition: zone.h:609
void SetIsFilled(bool isFilled)
Definition: zone.h:242
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Test to see if this object is on the given layer.
Definition: zone.cpp:307
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:52
bool isMaskAperture(BOARD_ITEM *aItem)
bool isNullAperture(BOARD_ITEM *aItem)
#define _(s)
static constexpr EDA_ANGLE & FULL_CIRCLE
Definition: eda_angle.h:421
@ FP_ALLOW_SOLDERMASK_BRIDGES
Definition: footprint.h:74
@ ERROR_OUTSIDE
int GetArcToSegmentCount(int aRadius, int aErrorMax, const EDA_ANGLE &aArcAngle)
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:822
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:104
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:114
@ PCB_FP_ZONE_T
class ZONE, managed by a footprint
Definition: typeinfo.h:102
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:89