KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 <pcb_text.h>
31#include <zone.h>
32#include <geometry/seg.h>
33#include <drc/drc_engine.h>
34#include <drc/drc_item.h>
35#include <drc/drc_rule.h>
37#include <drc/drc_rtree.h>
38
39/*
40 Solder mask tests. Checks for silkscreen which is clipped by mask openings and for bridges
41 between mask apertures with different nets.
42 Errors generated:
43 - DRCE_SILK_CLEARANCE
44 - DRCE_SOLDERMASK_BRIDGE
45*/
46
48{
49public:
51 m_board( nullptr ),
52 m_webWidth( 0 ),
53 m_maxError( 0 ),
55 {
56 m_bridgeRule.m_Name = _( "board setup solder mask min width" );
57 }
58
60 {
61 }
62
63 virtual bool Run() override;
64
65 virtual const wxString GetName() const override
66 {
67 return wxT( "solder_mask_issues" );
68 };
69
70 virtual const wxString GetDescription() const override
71 {
72 return wxT( "Tests for silkscreen being clipped by solder mask and copper being exposed "
73 "by mask apertures of other nets" );
74 }
75
76private:
77 void addItemToRTrees( BOARD_ITEM* aItem );
78 void buildRTrees();
79
81 void testMaskBridges();
82
83 void testItemAgainstItems( BOARD_ITEM* aItem, const BOX2I& aItemBBox,
84 PCB_LAYER_ID aRefLayer, PCB_LAYER_ID aTargetLayer );
85 void testMaskItemAgainstZones( BOARD_ITEM* item, const BOX2I& itemBBox,
86 PCB_LAYER_ID refLayer, PCB_LAYER_ID targetLayer );
87
88 bool checkMaskAperture( BOARD_ITEM* aMaskItem, BOARD_ITEM* aTestItem, PCB_LAYER_ID aTestLayer,
89 int aTestNet, BOARD_ITEM** aCollidingItem );
90
91 bool checkItemMask( BOARD_ITEM* aMaskItem, int aTestNet );
92
93private:
95
100
101 std::unique_ptr<DRC_RTREE> m_fullSolderMaskRTree;
102 std::unique_ptr<DRC_RTREE> m_itemTree;
103
104 std::unordered_map<PTR_PTR_CACHE_KEY, LSET> m_checkedPairs;
105
106 // Shapes used to define solder mask apertures don't have nets, so we assign them the
107 // first object+net that bridges their aperture (after which any other nets will generate
108 // violations).
109 std::unordered_map<PTR_LAYER_CACHE_KEY, std::pair<BOARD_ITEM*, int>> m_maskApertureNetMap;
110};
111
112
114{
115 ZONE* solderMask = m_board->m_SolderMaskBridges;
116
117 if( aItem->Type() == PCB_ZONE_T )
118 {
119 ZONE* zone = static_cast<ZONE*>( aItem );
120
121 for( PCB_LAYER_ID layer : { F_Mask, B_Mask } )
122 {
123 if( zone->IsOnLayer( layer ) )
124 {
125 solderMask->GetFill( layer )->BooleanAdd( *zone->GetFilledPolysList( layer ),
127 }
128 }
129 }
130 else if( aItem->Type() == PCB_PAD_T )
131 {
132 for( PCB_LAYER_ID layer : { F_Mask, B_Mask } )
133 {
134 if( aItem->IsOnLayer( layer ) )
135 {
136 PAD* pad = static_cast<PAD*>( aItem );
137 int clearance = ( m_webWidth / 2 ) + pad->GetSolderMaskExpansion();
138
139 aItem->TransformShapeToPolygon( *solderMask->GetFill( layer ), layer, clearance,
141
142 m_itemTree->Insert( aItem, layer, m_largestClearance );
143 }
144 }
145 }
146 else if( aItem->Type() == PCB_VIA_T )
147 {
148 for( PCB_LAYER_ID layer : { F_Mask, B_Mask } )
149 {
150 if( aItem->IsOnLayer( layer ) )
151 {
152 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
153 int clearance = ( m_webWidth / 2 ) + via->GetSolderMaskExpansion();
154
155 via->TransformShapeToPolygon( *solderMask->GetFill( layer ), layer, clearance,
157
158 m_itemTree->Insert( aItem, layer, m_largestClearance );
159 }
160 }
161 }
162 else if( aItem->Type() == PCB_FIELD_T || aItem->Type() == PCB_TEXT_T )
163 {
164 for( PCB_LAYER_ID layer : { F_Mask, B_Mask } )
165 {
166 if( aItem->IsOnLayer( layer ) )
167 {
168 const PCB_TEXT* text = static_cast<const PCB_TEXT*>( aItem );
169
170 text->TransformTextToPolySet( *solderMask->GetFill( layer ),
172
173 m_itemTree->Insert( aItem, layer, m_largestClearance );
174 }
175 }
176 }
177 else
178 {
179 for( PCB_LAYER_ID layer : { F_Mask, B_Mask } )
180 {
181 if( aItem->IsOnLayer( layer ) )
182 {
183 aItem->TransformShapeToPolygon( *solderMask->GetFill( layer ), layer,
185
186 m_itemTree->Insert( aItem, layer, m_largestClearance );
187 }
188 }
189 }
190}
191
192
194{
195 ZONE* solderMask = m_board->m_SolderMaskBridges;
196 LSET layers = { 4, F_Mask, B_Mask, F_Cu, B_Cu };
197
198 const size_t progressDelta = 500;
199 int count = 0;
200 int ii = 0;
201
202 solderMask->GetFill( F_Mask )->RemoveAllContours();
203 solderMask->GetFill( B_Mask )->RemoveAllContours();
204
205 m_fullSolderMaskRTree = std::make_unique<DRC_RTREE>();
206 m_itemTree = std::make_unique<DRC_RTREE>();
207
209 [&]( BOARD_ITEM* item ) -> bool
210 {
211 ++count;
212 return true;
213 } );
214
216 [&]( BOARD_ITEM* item ) -> bool
217 {
218 if( !reportProgress( ii++, count, progressDelta ) )
219 return false;
220
221 addItemToRTrees( item );
222 return true;
223 } );
224
227
228 solderMask->GetFill( F_Mask )->Deflate( m_webWidth / 2, CORNER_STRATEGY::CHAMFER_ALL_CORNERS,
229 m_maxError );
230 solderMask->GetFill( B_Mask )->Deflate( m_webWidth / 2, CORNER_STRATEGY::CHAMFER_ALL_CORNERS,
231 m_maxError );
232
233 solderMask->SetFillFlag( F_Mask, true );
234 solderMask->SetFillFlag( B_Mask, true );
235 solderMask->SetIsFilled( true );
236
237 solderMask->CacheTriangulation();
238
239 m_fullSolderMaskRTree->Insert( solderMask, F_Mask );
240 m_fullSolderMaskRTree->Insert( solderMask, B_Mask );
241
242 m_checkedPairs.clear();
243}
244
245
247{
248 LSET silkLayers = { 2, F_SilkS, B_SilkS };
249
250 const size_t progressDelta = 250;
251 int count = 0;
252 int ii = 0;
253
255 [&]( BOARD_ITEM* item ) -> bool
256 {
257 ++count;
258 return true;
259 } );
260
262 [&]( BOARD_ITEM* item ) -> bool
263 {
265 return false;
266
267 if( !reportProgress( ii++, count, progressDelta ) )
268 return false;
269
270 if( isInvisibleText( item ) )
271 return true;
272
273 for( PCB_LAYER_ID layer : silkLayers.Seq() )
274 {
275 if( !item->IsOnLayer( layer ) )
276 continue;
277
278 PCB_LAYER_ID maskLayer = layer == F_SilkS ? F_Mask : B_Mask;
279 BOX2I itemBBox = item->GetBoundingBox();
280 DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( SILK_CLEARANCE_CONSTRAINT,
281 item, nullptr, maskLayer );
282 int clearance = constraint.GetValue().Min();
283 int actual;
284 VECTOR2I pos;
285
286 if( constraint.GetSeverity() == RPT_SEVERITY_IGNORE || clearance < 0 )
287 return true;
288
289 std::shared_ptr<SHAPE> itemShape = item->GetEffectiveShape( layer );
290
291 if( m_fullSolderMaskRTree->QueryColliding( itemBBox, itemShape.get(), maskLayer,
292 clearance, &actual, &pos ) )
293 {
294 auto drce = DRC_ITEM::Create( DRCE_SILK_CLEARANCE );
295
296 if( clearance > 0 )
297 {
298 wxString msg = formatMsg( _( "(%s clearance %s; actual %s)" ),
299 constraint.GetName(),
300 clearance,
301 actual );
302
303 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
304 }
305
306 drce->SetItems( item );
307 drce->SetViolatingRule( constraint.GetParentRule() );
308
309 reportViolation( drce, pos, layer );
310 }
311 }
312
313 return true;
314 } );
315}
316
317
319{
320 if( aItem->Type() == PCB_PAD_T )
321 {
322 PAD* pad = static_cast<PAD*>( aItem );
323
324 if( pad->GetAttribute() == PAD_ATTRIB::NPTH
325 && ( pad->GetShape() == PAD_SHAPE::CIRCLE || pad->GetShape() == PAD_SHAPE::OVAL )
326 && pad->GetSize().x <= pad->GetDrillSize().x
327 && pad->GetSize().y <= pad->GetDrillSize().y )
328 {
329 return true;
330 }
331 }
332
333 return false;
334}
335
336
337// Simple mask apertures aren't associated with copper items, so they only constitute a bridge
338// when they expose other copper items having at least two distinct nets. We use a map to record
339// the first net exposed by each mask aperture (on each copper layer).
340//
341// Note that this algorithm is also used for free pads.
342
344{
345 if( aItem->Type() == PCB_PAD_T && static_cast<PAD*>( aItem )->IsFreePad() )
346 return true;
347
348 static const LSET saved( 2, F_Mask, B_Mask );
349
350 LSET maskLayers = aItem->GetLayerSet() & saved;
351 LSET copperLayers = ( aItem->GetLayerSet() & ~saved ) & LSET::AllCuMask();
352
353 return maskLayers.count() > 0 && copperLayers.count() == 0;
354}
355
356
358 PCB_LAYER_ID aTestLayer, int aTestNet,
359 BOARD_ITEM** aCollidingItem )
360{
361 if( aTestLayer == F_Mask && !aTestItem->IsOnLayer( F_Cu ) )
362 return false;
363
364 if( aTestLayer == B_Mask && !aTestItem->IsOnLayer( B_Cu ) )
365 return false;
366
367 FOOTPRINT* fp = aMaskItem->GetParentFootprint();
368
369 if( fp && ( fp->GetAttributes() & FP_ALLOW_SOLDERMASK_BRIDGES ) > 0 )
370 {
371 // Mask apertures in footprints which allow soldermask bridges are ignored entirely.
372 return false;
373 }
374
375 PTR_LAYER_CACHE_KEY key = { aMaskItem, aTestLayer };
376
377 auto ii = m_maskApertureNetMap.find( key );
378
379 if( ii == m_maskApertureNetMap.end() )
380 {
381 m_maskApertureNetMap[ key ] = { aTestItem, aTestNet };
382
383 // First net; no bridge yet....
384 return false;
385 }
386
387 if( ii->second.second == aTestNet && aTestNet > 0 )
388 {
389 // Same net; still no bridge...
390 return false;
391 }
392
393 if( fp && ii->second.first->Type() == PCB_PAD_T && aTestItem->Type() == PCB_PAD_T )
394 {
395 PAD* alreadyEncounteredPad = static_cast<PAD*>( ii->second.first );
396 PAD* thisPad = static_cast<PAD*>( aTestItem );
397
398 if( alreadyEncounteredPad->SharesNetTieGroup( thisPad ) )
399 return false;
400 }
401
402 *aCollidingItem = ii->second.first;
403 return true;
404}
405
406
408{
409 FOOTPRINT* fp = aMaskItem->GetParentFootprint();
410
411 wxCHECK( fp, false );
412
413 if( ( fp->GetAttributes() & FP_ALLOW_SOLDERMASK_BRIDGES ) > 0 )
414 {
415 // If we're allowing bridges then we're allowing bridges. Nothing to check.
416 return false;
417 }
418
419 // Graphic items are used to implement net-ties between pads of a group within a net-tie
420 // footprint. They must be allowed to intrude into their pad's mask aperture.
421 if( aTestNet < 0 && aMaskItem->Type() == PCB_PAD_T && fp->IsNetTie() )
422 {
423 std::map<wxString, int> padNumberToGroupIdxMap = fp->MapPadNumbersToNetTieGroups();
424
425 if( padNumberToGroupIdxMap[ static_cast<PAD*>( aMaskItem )->GetNumber() ] >= 0 )
426 return false;
427 }
428
429 return true;
430}
431
432
434 PCB_LAYER_ID aRefLayer,
435 PCB_LAYER_ID aTargetLayer )
436{
437 int itemNet = -1;
438
439 if( aItem->IsConnected() )
440 itemNet = static_cast<BOARD_CONNECTED_ITEM*>( aItem )->GetNetCode();
441
443 PAD* pad = dynamic_cast<PAD*>( aItem );
444 PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem );
445 std::shared_ptr<SHAPE> itemShape = aItem->GetEffectiveShape( aRefLayer );
446
447 m_itemTree->QueryColliding( aItem, aRefLayer, aTargetLayer,
448 // Filter:
449 [&]( BOARD_ITEM* other ) -> bool
450 {
451 FOOTPRINT* itemFP = aItem->GetParentFootprint();
452 PAD* otherPad = dynamic_cast<PAD*>( other );
453 int otherNet = -1;
454
455 if( other->IsConnected() )
456 otherNet = static_cast<BOARD_CONNECTED_ITEM*>( other )->GetNetCode();
457
458 if( otherNet > 0 && otherNet == itemNet )
459 return false;
460
461 if( isNullAperture( other ) )
462 return false;
463
464 if( itemFP && itemFP == other->GetParentFootprint() )
465 {
466 // Board-wide exclusion
468 return false;
469
470 // Footprint-specific exclusion
471 if( ( itemFP->GetAttributes() & FP_ALLOW_SOLDERMASK_BRIDGES ) > 0 )
472 return false;
473 }
474
475 if( pad && otherPad && ( pad->SameLogicalPadAs( otherPad )
476 || pad->SharesNetTieGroup( otherPad ) ) )
477 {
478 return false;
479 }
480
481 BOARD_ITEM* a = aItem;
482 BOARD_ITEM* b = other;
483
484 // store canonical order so we don't collide in both directions (a:b and b:a)
485 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
486 std::swap( a, b );
487
488 auto it = m_checkedPairs.find( { a, b } );
489
490 if( it != m_checkedPairs.end() && it->second.test( aTargetLayer ) )
491 {
492 return false;
493 }
494 else
495 {
496 m_checkedPairs[ { a, b } ].set( aTargetLayer );
497 return true;
498 }
499 },
500 // Visitor:
501 [&]( BOARD_ITEM* other ) -> bool
502 {
503 PAD* otherPad = dynamic_cast<PAD*>( other );
504 PCB_VIA* otherVia = dynamic_cast<PCB_VIA*>( other );
505 auto otherShape = other->GetEffectiveShape( aTargetLayer );
506 int otherNet = -1;
507
508 if( other->IsConnected() )
509 otherNet = static_cast<BOARD_CONNECTED_ITEM*>( other )->GetNetCode();
510
511 int actual;
512 VECTOR2I pos;
513 int clearance = 0;
514
515 if( aRefLayer == F_Mask || aRefLayer == B_Mask )
516 {
517 // Aperture-to-aperture must enforce web-min-width
518 clearance = m_webWidth;
519 }
520 else // ( aRefLayer == F_Cu || aRefLayer == B_Cu )
521 {
522 // Copper-to-aperture uses the solder-mask-to-copper-clearance
524 }
525
526 if( pad )
527 clearance += pad->GetSolderMaskExpansion();
528 else if( via && !via->IsTented() )
529 clearance += via->GetSolderMaskExpansion();
530
531 if( otherPad )
532 clearance += otherPad->GetSolderMaskExpansion();
533 else if( otherVia && !otherVia->IsTented() )
534 clearance += otherVia->GetSolderMaskExpansion();
535
536 if( itemShape->Collide( otherShape.get(), clearance, &actual, &pos ) )
537 {
538 wxString msg;
539 BOARD_ITEM* colliding = nullptr;
540
541 if( aTargetLayer == F_Mask )
542 msg = _( "Front solder mask aperture bridges items with different nets" );
543 else
544 msg = _( "Rear solder mask aperture bridges items with different nets" );
545
546 // Simple mask apertures aren't associated with copper items, so they only
547 // constitute a bridge when they expose other copper items having at least
548 // two distinct nets.
549 if( isMaskAperture( aItem ) )
550 {
551 if( checkMaskAperture( aItem, other, aRefLayer, otherNet, &colliding ) )
552 {
554
555 drce->SetErrorMessage( msg );
556 drce->SetItems( aItem, colliding, other );
557 drce->SetViolatingRule( &m_bridgeRule );
558 reportViolation( drce, pos, aTargetLayer );
559 }
560 }
561 else if( isMaskAperture( other ) )
562 {
563 if( checkMaskAperture( other, aItem, aRefLayer, itemNet, &colliding ) )
564 {
566
567 drce->SetErrorMessage( msg );
568 drce->SetItems( other, colliding, aItem );
569 drce->SetViolatingRule( &m_bridgeRule );
570 reportViolation( drce, pos, aTargetLayer );
571 }
572 }
573 else if( checkItemMask( other, itemNet ) )
574 {
576
577 drce->SetErrorMessage( msg );
578 drce->SetItems( aItem, other );
579 drce->SetViolatingRule( &m_bridgeRule );
580 reportViolation( drce, pos, aTargetLayer );
581 }
582 }
583
584 return !m_drcEngine->IsCancelled();
585 },
587}
588
589
591 const BOX2I& aItemBBox,
592 PCB_LAYER_ID aMaskLayer,
593 PCB_LAYER_ID aTargetLayer )
594{
595 for( ZONE* zone : m_board->m_DRCCopperZones )
596 {
597 if( !zone->GetLayerSet().test( aTargetLayer ) )
598 continue;
599
600 int zoneNet = zone->GetNetCode();
601
602 if( aItem->IsConnected() )
603 {
604 BOARD_CONNECTED_ITEM* connectedItem = static_cast<BOARD_CONNECTED_ITEM*>( aItem );
605
606 if( zoneNet == connectedItem->GetNetCode() && zoneNet > 0 )
607 continue;
608 }
609
610 BOX2I inflatedBBox( aItemBBox );
612
613 if( aItem->Type() == PCB_PAD_T )
614 clearance += static_cast<PAD*>( aItem )->GetSolderMaskExpansion();
615 else if( aItem->Type() == PCB_VIA_T )
616 clearance += static_cast<PCB_VIA*>( aItem )->GetSolderMaskExpansion();
617
618 inflatedBBox.Inflate( clearance );
619
620 if( !inflatedBBox.Intersects( zone->GetBoundingBox() ) )
621 continue;
622
623 DRC_RTREE* zoneTree = m_board->m_CopperZoneRTreeCache[ zone ].get();
624 int actual;
625 VECTOR2I pos;
626
627 std::shared_ptr<SHAPE> itemShape = aItem->GetEffectiveShape( aMaskLayer );
628
629 if( zoneTree && zoneTree->QueryColliding( aItemBBox, itemShape.get(), aTargetLayer,
630 clearance, &actual, &pos ) )
631 {
632 wxString msg;
633 BOARD_ITEM* colliding = nullptr;
634
635 if( aMaskLayer == F_Mask )
636 msg = _( "Front solder mask aperture bridges items with different nets" );
637 else
638 msg = _( "Rear solder mask aperture bridges items with different nets" );
639
640 // Simple mask apertures aren't associated with copper items, so they only constitute
641 // a bridge when they expose other copper items having at least two distinct nets.
642 if( isMaskAperture( aItem ) && zoneNet >= 0 )
643 {
644 if( checkMaskAperture( aItem, zone, aTargetLayer, zoneNet, &colliding ) )
645 {
647
648 drce->SetErrorMessage( msg );
649 drce->SetItems( aItem, colliding, zone );
650 drce->SetViolatingRule( &m_bridgeRule );
651 reportViolation( drce, pos, aTargetLayer );
652 }
653 }
654 else
655 {
657
658 drce->SetErrorMessage( msg );
659 drce->SetItems( aItem, zone );
660 drce->SetViolatingRule( &m_bridgeRule );
661 reportViolation( drce, pos, aTargetLayer );
662 }
663 }
664
665 if( m_drcEngine->IsCancelled() )
666 return;
667 }
668}
669
670
672{
673 LSET copperAndMaskLayers = { 4, F_Mask, B_Mask, F_Cu, B_Cu };
674
675 const size_t progressDelta = 250;
676 int count = 0;
677 int ii = 0;
678
679 forEachGeometryItem( s_allBasicItemsButZones, copperAndMaskLayers,
680 [&]( BOARD_ITEM* item ) -> bool
681 {
682 ++count;
683 return true;
684 } );
685
686 forEachGeometryItem( s_allBasicItemsButZones, copperAndMaskLayers,
687 [&]( BOARD_ITEM* item ) -> bool
688 {
690 return false;
691
692 if( !reportProgress( ii++, count, progressDelta ) )
693 return false;
694
695 BOX2I itemBBox = item->GetBoundingBox();
696
697 if( item->IsOnLayer( F_Mask ) && !isNullAperture( item ) )
698 {
699 // Test for aperture-to-aperture collisions
700 testItemAgainstItems( item, itemBBox, F_Mask, F_Mask );
701
702 // Test for aperture-to-zone collisions
703 testMaskItemAgainstZones( item, itemBBox, F_Mask, F_Cu );
704 }
705 else if( item->IsOnLayer( F_Cu ) )
706 {
707 // Test for copper-item-to-aperture collisions
708 testItemAgainstItems( item, itemBBox, F_Cu, F_Mask );
709 }
710
711 if( item->IsOnLayer( B_Mask ) && !isNullAperture( item ) )
712 {
713 // Test for aperture-to-aperture collisions
714 testItemAgainstItems( item, itemBBox, B_Mask, B_Mask );
715
716 // Test for aperture-to-zone collisions
717 testMaskItemAgainstZones( item, itemBBox, B_Mask, B_Cu );
718 }
719 else if( item->IsOnLayer( B_Cu ) )
720 {
721 // Test for copper-item-to-aperture collisions
722 testItemAgainstItems( item, itemBBox, B_Cu, B_Mask );
723 }
724
725 return true;
726 } );
727}
728
729
731{
734 {
735 reportAux( wxT( "Solder mask violations ignored. Tests not run." ) );
736 return true; // continue with other tests
737 }
738
743
744 for( FOOTPRINT* footprint : m_board->Footprints() )
745 {
746 for( PAD* pad : footprint->Pads() )
747 m_largestClearance = std::max( m_largestClearance, pad->GetSolderMaskExpansion() );
748 }
749
750 // Order is important here: m_webWidth must be added in before m_largestCourtyardClearance is
751 // maxed with the various SILK_CLEARANCE_CONSTRAINTS.
753
754 DRC_CONSTRAINT worstClearanceConstraint;
755
756 if( m_drcEngine->QueryWorstConstraint( SILK_CLEARANCE_CONSTRAINT, worstClearanceConstraint ) )
757 m_largestClearance = std::max( m_largestClearance, worstClearanceConstraint.m_Value.Min() );
758
759 reportAux( wxT( "Worst clearance : %d nm" ), m_largestClearance );
760
761 if( !reportPhase( _( "Building solder mask..." ) ) )
762 return false; // DRC cancelled
763
764 m_checkedPairs.clear();
765 m_maskApertureNetMap.clear();
766
767 buildRTrees();
768
769 if( !reportPhase( _( "Checking solder mask to silk clearance..." ) ) )
770 return false; // DRC cancelled
771
773
774 if( !reportPhase( _( "Checking solder mask web integrity..." ) ) )
775 return false; // DRC cancelled
776
778
780
781 return !m_drcEngine->IsCancelled();
782}
783
784
785namespace detail
786{
788}
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:77
virtual bool IsConnected() const
Returns information if the object is derived from BOARD_CONNECTED_ITEM.
Definition: board_item.h:134
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:205
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Test to see if this object is on the given layer.
Definition: board_item.h:291
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:228
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:46
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:248
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:231
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:282
ZONE * m_SolderMaskBridges
Definition: board.h:1278
std::vector< ZONE * > m_DRCCopperZones
Definition: board.h:1275
const FOOTPRINTS & Footprints() const
Definition: board.h:323
std::unordered_map< ZONE *, std::unique_ptr< DRC_RTREE > > m_CopperZoneRTreeCache
Definition: board.h:1269
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:797
bool Intersects(const BOX2< Vec > &aRect) const
Definition: box2.h:294
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:541
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:331
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:214
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_ITEM and posi...
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 void reportViolation(std::shared_ptr< DRC_ITEM > &item, const VECTOR2I &aMarkerPos, int aMarkerLayer)
static std::vector< KICAD_T > s_allBasicItems
DRC_ENGINE * m_drcEngine
bool isInvisibleText(const BOARD_ITEM *aItem) const
void reportAux(const wxString &aMsg)
virtual void reportRuleStatistics()
virtual bool reportProgress(size_t aCount, size_t aSize, size_t aDelta=1)
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:100
std::map< wxString, int > MapPadNumbersToNetTieGroups() const
Definition: footprint.cpp:2911
int GetAttributes() const
Definition: footprint.h:276
bool IsNetTie() const
Definition: footprint.h:283
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:575
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:418
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:863
T Min() const
Definition: minoptmax.h:33
Definition: pad.h:59
int GetSolderMaskExpansion() const
Definition: pad.cpp:1038
bool IsFreePad() const
Definition: pad.cpp:342
bool SharesNetTieGroup(const PAD *aOther) const
Definition: pad.cpp:319
bool IsTented() const override
Definition: pcb_track.cpp:840
int GetSolderMaskExpansion() const
Definition: pcb_track.cpp:849
void RemoveAllContours()
Remove all outlines & holes (clears) the polygon set.
void BooleanAdd(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset union For aFastMode meaning, see function booleanOp.
void Simplify(POLYGON_MODE aFastMode)
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFastMo...
void Deflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError)
Handle a list of polygons defining a copper zone.
Definition: zone.h:72
const std::shared_ptr< SHAPE_POLY_SET > & GetFilledPolysList(PCB_LAYER_ID aLayer) const
Definition: zone.h:615
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:1071
const BOX2I GetBoundingBox() const override
Definition: zone.cpp:343
void SetFillFlag(PCB_LAYER_ID aLayer, bool aFlag)
Definition: zone.h:258
SHAPE_POLY_SET * GetFill(PCB_LAYER_ID aLayer)
Definition: zone.h:621
void SetIsFilled(bool isFilled)
Definition: zone.h:261
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Test to see if this object is on the given layer.
Definition: zone.cpp:337
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: zone.h:129
The common library.
@ DRCE_SOLDERMASK_BRIDGE
Definition: drc_item.h:86
@ DRCE_SILK_CLEARANCE
Definition: drc_item.h:89
@ SILK_CLEARANCE_CONSTRAINT
Definition: drc_rule.h:53
bool isMaskAperture(BOARD_ITEM *aItem)
bool isNullAperture(BOARD_ITEM *aItem)
#define _(s)
@ FP_ALLOW_SOLDERMASK_BRIDGES
Definition: footprint.h:78
@ ERROR_OUTSIDE
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ 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 mechanical use only, no connection allowed
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:107
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:92
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition: typeinfo.h:90
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87