KiCad PCB EDA Suite
Loading...
Searching...
No Matches
drc_test_provider_copper_clearance.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-2024 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>
25#include <math_for_graphics.h>
27#include <footprint.h>
28#include <layer_range.h>
29#include <pcb_shape.h>
30#include <pad.h>
31#include <pcb_track.h>
32#include <core/thread_pool.h>
33#include <zone.h>
34
35#include <geometry/seg.h>
38
39#include <drc/drc_engine.h>
40#include <drc/drc_rtree.h>
41#include <drc/drc_item.h>
42#include <drc/drc_rule.h>
45#include <pcb_dimension.h>
46
47#include <future>
48
49/*
50 Copper clearance test. Checks all copper items (pads, vias, tracks, drawings, zones) for their
51 electrical clearance.
52
53 Errors generated:
54 - DRCE_CLEARANCE
55 - DRCE_HOLE_CLEARANCE
56 - DRCE_TRACKS_CROSSING
57 - DRCE_ZONES_INTERSECT
58 - DRCE_SHORTING_ITEMS
59*/
60
62{
63public:
66 m_drcEpsilon( 0 )
67 {
68 }
69
71 {
72 }
73
74 virtual bool Run() override;
75
76 virtual const wxString GetName() const override
77 {
78 return wxT( "clearance" );
79 };
80
81 virtual const wxString GetDescription() const override
82 {
83 return wxT( "Tests copper item clearance" );
84 }
85
86private:
96 PCB_LAYER_ID layer, BOARD_ITEM* other );
97
99
100 void testPadAgainstItem( PAD* pad, SHAPE* padShape, PCB_LAYER_ID layer, BOARD_ITEM* other );
101
102 void testPadClearances();
103
105
106 void testZonesToZones();
107
108 void testItemAgainstZone( BOARD_ITEM* aItem, ZONE* aZone, PCB_LAYER_ID aLayer );
109
110 void testKnockoutTextAgainstZone( BOARD_ITEM* aText, NETINFO_ITEM** aInheritedNet, ZONE* aZone );
111
112 typedef struct checked
113 {
115 : layers(), has_error( false ) {}
116
118 : layers( { aLayer } ), has_error( false ) {}
119
123
124private:
126};
127
128
130{
132
133 if( m_board->m_DRCMaxClearance <= 0 )
134 {
135 reportAux( wxT( "No Clearance constraints found. Tests not run." ) );
136 return true; // continue with other tests
137 }
138
140
142 {
143 if( !reportPhase( _( "Checking track & via clearances..." ) ) )
144 return false; // DRC cancelled
145
147 }
149 {
150 if( !reportPhase( _( "Checking hole clearances..." ) ) )
151 return false; // DRC cancelled
152
154 }
155
157 {
158 if( !reportPhase( _( "Checking pad clearances..." ) ) )
159 return false; // DRC cancelled
160
162 }
165 {
166 if( !reportPhase( _( "Checking pads..." ) ) )
167 return false; // DRC cancelled
168
170 }
171
173 {
174 if( !reportPhase( _( "Checking copper graphic clearances..." ) ) )
175 return false; // DRC cancelled
176
178 }
179
181 {
182 if( !reportPhase( _( "Checking copper zone clearances..." ) ) )
183 return false; // DRC cancelled
184
186 }
188 {
189 if( !reportPhase( _( "Checking zones..." ) ) )
190 return false; // DRC cancelled
191
193 }
194
196
197 return !m_drcEngine->IsCancelled();
198}
199
200
202 SHAPE* itemShape,
203 PCB_LAYER_ID layer,
204 BOARD_ITEM* other )
205{
206 bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE );
209 DRC_CONSTRAINT constraint;
210 int clearance = -1;
211 int actual;
212 VECTOR2I pos;
213 bool has_error = false;
214 int otherNet = 0;
215
216 if( BOARD_CONNECTED_ITEM* connectedItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( other ) )
217 otherNet = connectedItem->GetNetCode();
218
219 std::shared_ptr<SHAPE> otherShape = other->GetEffectiveShape( layer );
220
221 if( other->Type() == PCB_PAD_T )
222 {
223 PAD* pad = static_cast<PAD*>( other );
224
225 if( pad->GetAttribute() == PAD_ATTRIB::NPTH && !pad->FlashLayer( layer ) )
226 testClearance = testShorting = false;
227 }
228
229 if( testClearance || testShorting )
230 {
231 constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, item, other, layer );
232 clearance = constraint.GetValue().Min();
233 }
234
235 if( constraint.GetSeverity() != RPT_SEVERITY_IGNORE && clearance > 0 )
236 {
237 // Special processing for track:track intersections
238 if( item->Type() == PCB_TRACE_T && other->Type() == PCB_TRACE_T )
239 {
240 PCB_TRACK* track = static_cast<PCB_TRACK*>( item );
241 PCB_TRACK* otherTrack = static_cast<PCB_TRACK*>( other );
242
243 SEG trackSeg( track->GetStart(), track->GetEnd() );
244 SEG otherSeg( otherTrack->GetStart(), otherTrack->GetEnd() );
245
246 if( OPT_VECTOR2I intersection = trackSeg.Intersect( otherSeg ) )
247 {
248 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TRACKS_CROSSING );
249 drcItem->SetItems( item, other );
250 drcItem->SetViolatingRule( constraint.GetParentRule() );
251
252 reportViolation( drcItem, *intersection, layer );
253
254 return false;
255 }
256 }
257
258 if( itemShape->Collide( otherShape.get(), clearance - m_drcEpsilon, &actual, &pos ) )
259 {
260 if( m_drcEngine->IsNetTieExclusion( item->GetNetCode(), layer, pos, other ) )
261 {
262 // Collision occurred as track was entering a pad marked as a net-tie. We
263 // allow these.
264 }
265 else if( actual == 0 && otherNet && testShorting )
266 {
267 std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_SHORTING_ITEMS );
268 wxString msg;
269
270 msg.Printf( _( "(nets %s and %s)" ), item->GetNetname(),
271 static_cast<BOARD_CONNECTED_ITEM*>( other )->GetNetname() );
272
273 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
274 drce->SetItems( item, other );
275
276 reportViolation( drce, pos, layer );
277 has_error = true;
278
280 return false;
281 }
282 else if( testClearance )
283 {
284 std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CLEARANCE );
285 wxString msg = formatMsg( _( "(%s clearance %s; actual %s)" ),
286 constraint.GetName(),
287 clearance,
288 actual );
289
290 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
291 drce->SetItems( item, other );
292 drce->SetViolatingRule( constraint.GetParentRule() );
293
294 ReportAndShowPathCuToCu( drce, pos, layer, item, other, layer, actual );
295 has_error = true;
296
298 return false;
299 }
300 }
301 }
302
303 if( testHoles && ( item->HasHole() || other->HasHole() ) )
304 {
305 std::array<BOARD_ITEM*, 2> a{ item, other };
306 std::array<BOARD_ITEM*, 2> b{ other, item };
307 std::array<SHAPE*, 2> a_shape{ itemShape, otherShape.get() };
308
309 for( size_t ii = 0; ii < 2; ++ii )
310 {
311 std::shared_ptr<SHAPE_SEGMENT> holeShape;
312
313 // We only test a track item here against an item with a hole.
314 // If either case is not valid, simply move on
315 if( !( dynamic_cast<PCB_TRACK*>( a[ii] ) ) || !b[ii]->HasHole() )
316 {
317 continue;
318 }
319 if( b[ii]->Type() == PCB_VIA_T )
320 {
321 if( b[ii]->GetLayerSet().Contains( layer ) )
322 holeShape = b[ii]->GetEffectiveHoleShape();
323 }
324 else
325 {
326 holeShape = b[ii]->GetEffectiveHoleShape();
327 }
328
329 constraint = m_drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, b[ii], a[ii], layer );
330 clearance = constraint.GetValue().Min();
331
332 // Test for hole to item clearance even if clearance is 0, because the item cannot be
333 // inside (or intersect) the hole.
334 if( constraint.GetSeverity() != RPT_SEVERITY_IGNORE )
335 {
336 if( a_shape[ii]->Collide( holeShape.get(), std::max( 0, clearance - m_drcEpsilon ),
337 &actual, &pos ) )
338 {
339 std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
340 wxString msg = formatMsg( clearance ? _( "(%s clearance %s; actual %s)" )
341 : _( "(%s clearance %s; actual < 0)" ),
342 constraint.GetName(),
343 clearance,
344 actual );
345
346 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
347 drce->SetItems( a[ii], b[ii] );
348 drce->SetViolatingRule( constraint.GetParentRule() );
349
350 ReportAndShowPathCuToCu( drce, pos, layer, a[ii], b[ii], layer, actual );
351 return false;
352 }
353 }
354 }
355 }
356
357 return !has_error;
358}
359
360
362 PCB_LAYER_ID aLayer )
363{
364 if( !aZone->GetLayerSet().test( aLayer ) )
365 return;
366
367 if( aZone->GetNetCode() && aItem->IsConnected() )
368 {
369 if( aZone->GetNetCode() == static_cast<BOARD_CONNECTED_ITEM*>( aItem )->GetNetCode() )
370 return;
371 }
372
373 BOX2I itemBBox = aItem->GetBoundingBox();
374 BOX2I worstCaseBBox = itemBBox;
375
376 worstCaseBBox.Inflate( m_board->m_DRCMaxClearance );
377
378 if( !worstCaseBBox.Intersects( aZone->GetBoundingBox() ) )
379 return;
380
381 FOOTPRINT* parentFP = aItem->GetParentFootprint();
382
383 // Ignore graphic items which implement a net-tie to the zone's net on the layer being tested.
384 if( parentFP && parentFP->IsNetTie() && dynamic_cast<PCB_SHAPE*>( aItem ) )
385 {
386 std::set<PAD*> allowedNetTiePads;
387
388 for( PAD* pad : parentFP->Pads() )
389 {
390 if( pad->GetNetCode() == aZone->GetNetCode() && aZone->GetNetCode() != 0 )
391 {
392 if( pad->IsOnLayer( aLayer ) )
393 allowedNetTiePads.insert( pad );
394
395 for( PAD* other : parentFP->GetNetTiePads( pad ) )
396 {
397 if( other->IsOnLayer( aLayer ) )
398 allowedNetTiePads.insert( other );
399 }
400 }
401 }
402
403 if( !allowedNetTiePads.empty() )
404 {
405 std::shared_ptr<SHAPE> itemShape = aItem->GetEffectiveShape();
406
407 for( PAD* pad : allowedNetTiePads )
408 {
409 if( pad->GetBoundingBox().Intersects( itemBBox )
410 && pad->GetEffectiveShape( aLayer )->Collide( itemShape.get() ) )
411 {
412 return;
413 }
414 }
415 }
416 }
417
418 bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE );
420
421 if( !testClearance && !testHoles )
422 return;
423
424 DRC_RTREE* zoneTree = m_board->m_CopperZoneRTreeCache[ aZone ].get();
425
426 if( !zoneTree )
427 return;
428
429 DRC_CONSTRAINT constraint;
430 int clearance = -1;
431 int actual;
432 VECTOR2I pos;
433
434 if( aItem->Type() == PCB_PAD_T )
435 {
436 PAD* pad = static_cast<PAD*>( aItem );
437 bool flashedPad = pad->FlashLayer( aLayer );
438 bool platedHole = pad->HasHole() && pad->GetAttribute() == PAD_ATTRIB::PTH;
439
440 if( !flashedPad && !platedHole )
441 testClearance = false;
442 }
443
444 if( testClearance )
445 {
446 constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, aItem, aZone, aLayer );
447 clearance = constraint.GetValue().Min();
448 }
449
450 if( constraint.GetSeverity() != RPT_SEVERITY_IGNORE && clearance > 0 )
451 {
452 std::shared_ptr<SHAPE> itemShape = aItem->GetEffectiveShape( aLayer, FLASHING::DEFAULT );
453
454 if( zoneTree->QueryColliding( itemBBox, itemShape.get(), aLayer,
455 std::max( 0, clearance - m_drcEpsilon ), &actual, &pos ) )
456 {
457 std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CLEARANCE );
458 wxString msg = formatMsg( _( "(%s clearance %s; actual %s)" ),
459 constraint.GetName(),
460 clearance,
461 actual );
462
463 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
464 drce->SetItems( aItem, aZone );
465 drce->SetViolatingRule( constraint.GetParentRule() );
466 ReportAndShowPathCuToCu( drce, pos, aLayer, aItem, aZone, aLayer, actual );
467 }
468 }
469
470 if( testHoles && aItem->HasHole() )
471 {
472 std::shared_ptr<SHAPE_SEGMENT> holeShape;
473
474 if( aItem->Type() == PCB_VIA_T )
475 {
476 if( aItem->GetLayerSet().Contains( aLayer ) )
477 holeShape = aItem->GetEffectiveHoleShape();
478 }
479 else
480 {
481 holeShape = aItem->GetEffectiveHoleShape();
482 }
483
484 if( holeShape )
485 {
486 constraint = m_drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, aItem, aZone, aLayer );
487 clearance = constraint.GetValue().Min();
488
489 if( constraint.GetSeverity() != RPT_SEVERITY_IGNORE && clearance > 0 )
490 {
491 if( zoneTree->QueryColliding( itemBBox, holeShape.get(), aLayer,
492 std::max( 0, clearance - m_drcEpsilon ),
493 &actual, &pos ) )
494 {
495 std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
496 wxString msg = formatMsg( _( "(%s clearance %s; actual %s)" ),
497 constraint.GetName(),
498 clearance,
499 actual );
500
501 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
502 drce->SetItems( aItem, aZone );
503 drce->SetViolatingRule( constraint.GetParentRule() );
504 ReportAndShowPathCuToCu( drce, pos, aLayer, aItem, aZone, aLayer, actual );
505 }
506 }
507 }
508 }
509}
510
511
512/*
513 * We have to special-case knockout text as it's most often knocked-out of a zone, so it's
514 * presumed to collide with one. However, if it collides with more than one, and they have
515 * different nets, then we have a short.
516 */
518 NETINFO_ITEM** aInheritedNet,
519 ZONE* aZone )
520{
521 bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE );
523
524 if( !testClearance && !testShorts )
525 return;
526
527 PCB_LAYER_ID layer = aText->GetLayer();
528
529 if( !aZone->GetLayerSet().test( layer ) )
530 return;
531
532 BOX2I itemBBox = aText->GetBoundingBox();
533 BOX2I worstCaseBBox = itemBBox;
534
535 worstCaseBBox.Inflate( m_board->m_DRCMaxClearance );
536
537 if( !worstCaseBBox.Intersects( aZone->GetBoundingBox() ) )
538 return;
539
540 DRC_RTREE* zoneTree = m_board->m_CopperZoneRTreeCache[ aZone ].get();
541
542 if( !zoneTree )
543 return;
544
545 std::shared_ptr<SHAPE> itemShape = aText->GetEffectiveShape( layer, FLASHING::DEFAULT );
546
547 if( *aInheritedNet == nullptr )
548 {
549 if( zoneTree->QueryColliding( itemBBox, itemShape.get(), layer ) )
550 *aInheritedNet = aZone->GetNet();
551 }
552
553 if( *aInheritedNet == aZone->GetNet() )
554 return;
555
556 DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, aText, aZone, layer );
557 int clearance = constraint.GetValue().Min();
558 int actual;
559 VECTOR2I pos;
560
561 if( constraint.GetSeverity() != RPT_SEVERITY_IGNORE && clearance >= 0 )
562 {
563 if( zoneTree->QueryColliding( itemBBox, itemShape.get(), layer,
564 std::max( 0, clearance - m_drcEpsilon ), &actual, &pos ) )
565 {
566 std::shared_ptr<DRC_ITEM> drce;
567 wxString msg;
568
569 if( testShorts && actual == 0 && *aInheritedNet )
570 {
572 msg.Printf( _( "(nets %s and %s)" ),
573 ( *aInheritedNet )->GetNetname(),
574 aZone->GetNetname() );
575 }
576 else
577 {
579 msg = formatMsg( _( "(%s clearance %s; actual %s)" ),
580 constraint.GetName(),
581 clearance,
582 actual );
583 }
584
585 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
586 drce->SetItems( aText, aZone );
587 drce->SetViolatingRule( constraint.GetParentRule() );
588 ReportAndShowPathCuToCu( drce, pos, layer, aText, aZone, layer, actual );
589 }
590 }
591}
592
593
595{
596 std::map<BOARD_ITEM*, int> freePadsUsageMap;
597 std::unordered_map<PTR_PTR_CACHE_KEY, layers_checked> checkedPairs;
598 std::mutex checkedPairsMutex;
599 std::mutex freePadsUsageMapMutex;
600 std::atomic<size_t> done( 0 );
601 size_t count = m_board->Tracks().size();
602
603 reportAux( wxT( "Testing %d tracks & vias..." ), count );
604
605 LSET boardCopperLayers = LSET::AllCuMask( m_board->GetCopperLayerCount() );
606
607 auto testTrack = [&]( const int start_idx, const int end_idx )
608 {
609 for( int trackIdx = start_idx; trackIdx < end_idx; ++trackIdx )
610 {
611 PCB_TRACK* track = m_board->Tracks()[trackIdx];
612
613 for( PCB_LAYER_ID layer : LSET( track->GetLayerSet() & boardCopperLayers ).Seq() )
614 {
615 std::shared_ptr<SHAPE> trackShape = track->GetEffectiveShape( layer );
616
617 m_board->m_CopperItemRTreeCache->QueryColliding( track, layer, layer,
618 // Filter:
619 [&]( BOARD_ITEM* other ) -> bool
620 {
621 auto otherCItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( other );
622
623 if( otherCItem && otherCItem->GetNetCode() == track->GetNetCode() )
624 return false;
625
626 BOARD_ITEM* a = track;
627 BOARD_ITEM* b = other;
628
629 // store canonical order so we don't collide in both directions
630 // (a:b and b:a)
631 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
632 std::swap( a, b );
633
634 std::lock_guard<std::mutex> lock( checkedPairsMutex );
635 auto it = checkedPairs.find( { a, b } );
636
637 if( it != checkedPairs.end() && ( it->second.layers.test( layer )
638 || ( it->second.has_error && !m_drcEngine->GetReportAllTrackErrors() ) ) )
639 {
640 return false;
641 }
642 else
643 {
644 checkedPairs[ { a, b } ].layers.set( layer );
645 return true;
646 }
647 },
648 // Visitor:
649 [&]( BOARD_ITEM* other ) -> bool
650 {
651 if( m_drcEngine->IsCancelled() )
652 return false;
653
654 if( other->Type() == PCB_PAD_T && static_cast<PAD*>( other )->IsFreePad() )
655 {
656 if( other->GetEffectiveShape( layer )->Collide( trackShape.get() ) )
657 {
658 std::lock_guard<std::mutex> lock( freePadsUsageMapMutex );
659 auto it = freePadsUsageMap.find( other );
660
661 if( it == freePadsUsageMap.end() )
662 {
663 freePadsUsageMap[ other ] = track->GetNetCode();
664 return true; // Continue colliding tests
665 }
666 else if( it->second == track->GetNetCode() )
667 {
668 return true; // Continue colliding tests
669 }
670 }
671 }
672
673 BOARD_ITEM* a = track;
674 BOARD_ITEM* b = other;
675
676 // store canonical order so we don't collide in both directions
677 // (a:b and b:a)
678 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
679 std::swap( a, b );
680
681 // If we get an error, mark the pair as having a clearance error already
682 if( !testSingleLayerItemAgainstItem( track, trackShape.get(), layer, other ) )
683 {
684 std::lock_guard<std::mutex> lock( checkedPairsMutex );
685 auto it = checkedPairs.find( { a, b } );
686
687 if( it != checkedPairs.end() )
688 it->second.has_error = true;
689
691 return false; // We're done with this track
692 }
693
694 return !m_drcEngine->IsCancelled();
695 },
697
698 for( ZONE* zone : m_board->m_DRCCopperZones )
699 {
700 testItemAgainstZone( track, zone, layer );
701
702 if( m_drcEngine->IsCancelled() )
703 break;
704 }
705 }
706
707 done.fetch_add( 1 );
708 }
709 };
710
712
713 tp.push_loop( m_board->Tracks().size(), testTrack );
714
715 while( done < count )
716 {
717 reportProgress( done, count );
718
719 if( m_drcEngine->IsCancelled() )
720 {
721 tp.wait_for_tasks();
722 break;
723 }
724
725 std::this_thread::sleep_for( std::chrono::milliseconds( 250 ) );
726 }
727}
728
729
731 PCB_LAYER_ID aLayer,
732 BOARD_ITEM* other )
733{
734 bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE );
737
738 // Disable some tests for net-tie objects in a footprint
739 if( other->GetParent() == pad->GetParent() )
740 {
741 FOOTPRINT* fp = pad->GetParentFootprint();
742 std::map<wxString, int> padToNetTieGroupMap = fp->MapPadNumbersToNetTieGroups();
743 int padGroupIdx = padToNetTieGroupMap[ pad->GetNumber() ];
744
745 if( other->Type() == PCB_PAD_T )
746 {
747 PAD* otherPad = static_cast<PAD*>( other );
748
749 if( padGroupIdx >= 0 && padGroupIdx == padToNetTieGroupMap[ otherPad->GetNumber() ] )
750 testClearance = testShorting = false;
751
752 if( pad->SameLogicalPadAs( otherPad ) )
753 testHoles = false;
754 }
755
756 if( other->Type() == PCB_SHAPE_T && padGroupIdx >= 0 )
757 testClearance = testShorting = false;
758 }
759
760 PAD* otherPad = nullptr;
761 PCB_VIA* otherVia = nullptr;
762
763 if( other->Type() == PCB_PAD_T )
764 otherPad = static_cast<PAD*>( other );
765
766 if( other->Type() == PCB_VIA_T )
767 otherVia = static_cast<PCB_VIA*>( other );
768
769 if( !IsCopperLayer( aLayer ) )
770 testClearance = testShorting = false;
771
772 // A NPTH has no cylinder, but it may still have pads on some layers
773 if( pad->GetAttribute() == PAD_ATTRIB::NPTH && !pad->FlashLayer( aLayer ) )
774 testClearance = testShorting = false;
775
776 if( otherPad && otherPad->GetAttribute() == PAD_ATTRIB::NPTH && !otherPad->FlashLayer( aLayer ) )
777 testClearance = testShorting = false;
778
779 // Track clearances are tested in testTrackClearances()
780 if( dynamic_cast<PCB_TRACK*>( other) )
781 testClearance = testShorting = false;
782
783 int padNet = pad->GetNetCode();
784 int otherNet = 0;
785
786 if( BOARD_CONNECTED_ITEM* connectedItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( other ) )
787 otherNet = connectedItem->GetNetCode();
788
789 // Other objects of the same (defined) net get a waiver on clearance and hole tests
790 if( otherNet && otherNet == padNet )
791 {
792 testClearance = testShorting = false;
793 testHoles = false;
794 }
795
796 if( !( pad->GetDrillSize().x > 0 )
797 && !( otherPad && otherPad->GetDrillSize().x > 0 )
798 && !( otherVia && otherVia->GetDrill() > 0 ) )
799 {
800 testHoles = false;
801 }
802
803 if( !testClearance && !testShorting && !testHoles )
804 return;
805
806 std::shared_ptr<SHAPE> otherShape = other->GetEffectiveShape( aLayer );
807 DRC_CONSTRAINT constraint;
808 int clearance = 0;
809 int actual = 0;
810 VECTOR2I pos;
811
812 if( otherPad && pad->SameLogicalPadAs( otherPad ) )
813 {
814 // If pads are equivalent (ie: from the same footprint with the same pad number)...
815 // ... and have "real" nets...
816 // then they must be the same net
817 if( testShorting )
818 {
819 if( pad->GetNetCode() == 0 || pad->GetNetCode() == otherPad->GetNetCode() )
820 return;
821
822 if( pad->GetShortNetname().StartsWith( wxS( "unconnected-(" ) )
823 && otherPad->GetShortNetname().StartsWith( wxS( "unconnected-(" ) ) )
824 {
825 return;
826 }
827
828 std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_SHORTING_ITEMS );
829 wxString msg;
830
831 msg.Printf( _( "(nets %s and %s)" ),
832 pad->GetNetname(),
833 otherPad->GetNetname() );
834
835 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
836 drce->SetItems( pad, otherPad );
837
838 reportViolation( drce, otherPad->GetPosition(), aLayer );
839 }
840
841 return;
842 }
843
844 if( testClearance || testShorting )
845 {
846 constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, pad, other, aLayer );
847 clearance = constraint.GetValue().Min();
848
849 if( constraint.GetSeverity() != RPT_SEVERITY_IGNORE && clearance > 0 )
850 {
851 if( padShape->Collide( otherShape.get(), std::max( 0, clearance - m_drcEpsilon ),
852 &actual, &pos ) )
853 {
854 if( m_drcEngine->IsNetTieExclusion( pad->GetNetCode(), aLayer, pos, other ) )
855 {
856 // Pads connected to pads of a net-tie footprint are allowed to collide
857 // with the net-tie footprint's graphics.
858 }
859 else if( actual == 0 && otherNet && testShorting )
860 {
861 std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_SHORTING_ITEMS );
862 wxString msg;
863
864 msg.Printf( _( "(nets %s and %s)" ),
865 pad->GetNetname(),
866 static_cast<BOARD_CONNECTED_ITEM*>( other )->GetNetname() );
867
868 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
869 drce->SetItems( pad, other );
870
871 reportViolation( drce, pos, aLayer );
872 testHoles = false; // No need for multiple violations
873 }
874 else if( testClearance )
875 {
876 std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CLEARANCE );
877 wxString msg = formatMsg( _( "(%s clearance %s; actual %s)" ),
878 constraint.GetName(),
879 clearance,
880 actual );
881
882 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
883 drce->SetItems( pad, other );
884 drce->SetViolatingRule( constraint.GetParentRule() );
885 ReportAndShowPathCuToCu( drce, pos, aLayer, pad, other, aLayer, actual );
886 testHoles = false; // No need for multiple violations
887 }
888 }
889 }
890 }
891
892 if( testHoles )
893 {
894 constraint = m_drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, pad, other, aLayer );
895 clearance = constraint.GetValue().Min();
896
897 if( constraint.GetSeverity() == RPT_SEVERITY_IGNORE )
898 testHoles = false;
899 }
900
901 if( testHoles && otherPad && pad->FlashLayer( aLayer ) && otherPad->HasHole() )
902 {
903 if( clearance > 0 && padShape->Collide( otherPad->GetEffectiveHoleShape().get(),
904 std::max( 0, clearance - m_drcEpsilon ),
905 &actual, &pos ) )
906 {
907 std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
908 wxString msg = formatMsg( _( "(%s clearance %s; actual %s)" ),
909 constraint.GetName(),
910 clearance,
911 actual );
912
913 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
914 drce->SetItems( pad, other );
915 drce->SetViolatingRule( constraint.GetParentRule() );
916 ReportAndShowPathCuToCu( drce, pos, aLayer, pad, other, aLayer, actual );
917 testHoles = false; // No need for multiple violations
918 }
919 }
920
921 if( testHoles && otherPad && otherPad->FlashLayer( aLayer ) && pad->HasHole() )
922 {
923 if( clearance > 0 && otherShape->Collide( pad->GetEffectiveHoleShape().get(),
924 std::max( 0, clearance - m_drcEpsilon ),
925 &actual, &pos ) )
926 {
927 std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
928 wxString msg = formatMsg( _( "(%s clearance %s; actual %s)" ),
929 constraint.GetName(),
930 clearance,
931 actual );
932
933 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
934 drce->SetItems( pad, other );
935 drce->SetViolatingRule( constraint.GetParentRule() );
936
937 reportViolation( drce, pos, aLayer );
938 testHoles = false; // No need for multiple violations
939 }
940 }
941
942 if( testHoles && otherVia && otherVia->IsOnLayer( aLayer ) )
943 {
944 if( clearance > 0 && padShape->Collide( otherVia->GetEffectiveHoleShape().get(),
945 std::max( 0, clearance - m_drcEpsilon ),
946 &actual, &pos ) )
947 {
948 std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
949 wxString msg = formatMsg( _( "(%s clearance %s; actual %s)" ),
950 constraint.GetName(),
951 clearance,
952 actual );
953
954 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
955 drce->SetItems( pad, otherVia );
956 drce->SetViolatingRule( constraint.GetParentRule() );
957 ReportAndShowPathCuToCu( drce, pos, aLayer, pad, otherVia, aLayer, actual );
958 }
959 }
960}
961
962
964{
966 size_t count = 0;
967 std::atomic<size_t> done( 1 );
968
969 for( FOOTPRINT* footprint : m_board->Footprints() )
970 count += footprint->Pads().size();
971
972 reportAux( wxT( "Testing %d pads..." ), count );
973
974 std::unordered_map<PTR_PTR_CACHE_KEY, int> checkedPairs;
975
976 LSET boardCopperLayers = LSET::AllCuMask( m_board->GetCopperLayerCount() );
977
978 std::future<void> retn = tp.submit(
979 [&]()
980 {
981 for( FOOTPRINT* footprint : m_board->Footprints() )
982 {
983 for( PAD* pad : footprint->Pads() )
984 {
985 for( PCB_LAYER_ID layer : LSET( pad->GetLayerSet() & boardCopperLayers ).Seq() )
986 {
987 if( m_drcEngine->IsCancelled() )
988 return;
989
990 std::shared_ptr<SHAPE> padShape = pad->GetEffectiveShape( layer );
991
992 m_board->m_CopperItemRTreeCache->QueryColliding( pad, layer, layer,
993 // Filter:
994 [&]( BOARD_ITEM* other ) -> bool
995 {
996 BOARD_ITEM* a = pad;
997 BOARD_ITEM* b = other;
998
999 // store canonical order so we don't collide in both
1000 // directions (a:b and b:a)
1001 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
1002 std::swap( a, b );
1003
1004 if( checkedPairs.find( { a, b } ) != checkedPairs.end() )
1005 {
1006 return false;
1007 }
1008 else
1009 {
1010 checkedPairs[ { a, b } ] = 1;
1011 return true;
1012 }
1013 },
1014 // Visitor
1015 [&]( BOARD_ITEM* other ) -> bool
1016 {
1017 testPadAgainstItem( pad, padShape.get(), layer, other );
1018
1019 return !m_drcEngine->IsCancelled();
1020 },
1021 m_board->m_DRCMaxClearance );
1022
1023 for( ZONE* zone : m_board->m_DRCCopperZones )
1024 {
1025 testItemAgainstZone( pad, zone, layer );
1026
1027 if( m_drcEngine->IsCancelled() )
1028 return;
1029 }
1030 }
1031
1032 done.fetch_add( 1 );
1033 }
1034 }
1035 } );
1036
1037 std::future_status status = retn.wait_for( std::chrono::milliseconds( 250 ) );
1038
1039 while( status != std::future_status::ready )
1040 {
1041 reportProgress( done, count );
1042 status = retn.wait_for( std::chrono::milliseconds( 250 ) );
1043 }
1044}
1045
1046
1048{
1050 size_t count = m_board->Drawings().size();
1051 std::atomic<size_t> done( 1 );
1052
1053 for( FOOTPRINT* footprint : m_board->Footprints() )
1054 count += footprint->GraphicalItems().size();
1055
1056 reportAux( wxT( "Testing %d graphics..." ), count );
1057
1058 auto isKnockoutText =
1059 []( BOARD_ITEM* item )
1060 {
1061 return item->Type() == PCB_TEXT_T && static_cast<PCB_TEXT*>( item )->IsKnockout();
1062 };
1063
1064 auto testGraphicAgainstZone =
1065 [&]( BOARD_ITEM* item )
1066 {
1067 if( item->Type() == PCB_REFERENCE_IMAGE_T )
1068 return;
1069
1070 if( !IsCopperLayer( item->GetLayer() ) )
1071 return;
1072
1073 // Knockout text is most often knocked-out of a zone, so it's presumed to
1074 // collide with one. However, if it collides with more than one, and they
1075 // have different nets, then we have a short.
1076 NETINFO_ITEM* inheritedNet = nullptr;
1077
1078 for( ZONE* zone : m_board->m_DRCCopperZones )
1079 {
1080 if( isKnockoutText( item ) )
1081 testKnockoutTextAgainstZone( item, &inheritedNet, zone );
1082 else
1083 testItemAgainstZone( item, zone, item->GetLayer() );
1084
1085 if( m_drcEngine->IsCancelled() )
1086 return;
1087 }
1088 };
1089
1090 std::unordered_map<PTR_PTR_CACHE_KEY, layers_checked> checkedPairs;
1091
1092 auto testCopperGraphic =
1093 [&]( PCB_SHAPE* aShape )
1094 {
1095 PCB_LAYER_ID layer = aShape->GetLayer();
1096
1097 m_board->m_CopperItemRTreeCache->QueryColliding( aShape, layer, layer,
1098 // Filter:
1099 [&]( BOARD_ITEM* other ) -> bool
1100 {
1101 auto otherCItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( other );
1102
1103 if( otherCItem && otherCItem->GetNetCode() == aShape->GetNetCode() )
1104 return false;
1105
1106 // Pads and tracks handled separately
1107 if( other->Type() == PCB_PAD_T || other->Type() == PCB_ARC_T ||
1108 other->Type() == PCB_TRACE_T || other->Type() == PCB_VIA_T )
1109 {
1110 return false;
1111 }
1112
1113 BOARD_ITEM* a = aShape;
1114 BOARD_ITEM* b = other;
1115
1116 // store canonical order so we don't collide in both directions
1117 // (a:b and b:a)
1118 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
1119 std::swap( a, b );
1120
1121 auto it = checkedPairs.find( { a, b } );
1122
1123 if( it != checkedPairs.end() && it->second.layers.test( layer ) )
1124 {
1125 return false;
1126 }
1127 else
1128 {
1129 checkedPairs[ { a, b } ].layers.set( layer );
1130 return true;
1131 }
1132 },
1133 // Visitor:
1134 [&]( BOARD_ITEM* other ) -> bool
1135 {
1136 BOARD_ITEM* a = aShape;
1137 BOARD_ITEM* b = other;
1138
1139 // store canonical order so we don't collide in both directions
1140 // (a:b and b:a)
1141 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
1142 std::swap( a, b );
1143
1144 auto it = checkedPairs.find( { a, b } );
1145
1146 if( !testSingleLayerItemAgainstItem( aShape,
1147 aShape->GetEffectiveShape().get(),
1148 layer, other ) )
1149 {
1150 if( it != checkedPairs.end() )
1151 it->second.has_error = true;
1152 }
1153
1154 return !m_drcEngine->IsCancelled();
1155 },
1157 };
1158
1159 std::future<void> retn = tp.submit(
1160 [&]()
1161 {
1162 for( BOARD_ITEM* item : m_board->Drawings() )
1163 {
1164 testGraphicAgainstZone( item );
1165
1166 if( item->Type() == PCB_SHAPE_T && item->IsOnCopperLayer() )
1167 testCopperGraphic( static_cast<PCB_SHAPE*>( item ) );
1168
1169 done.fetch_add( 1 );
1170
1171 if( m_drcEngine->IsCancelled() )
1172 break;
1173 }
1174
1175 for( FOOTPRINT* footprint : m_board->Footprints() )
1176 {
1177 for( BOARD_ITEM* item : footprint->GraphicalItems() )
1178 {
1179 testGraphicAgainstZone( item );
1180
1181 done.fetch_add( 1 );
1182
1183 if( m_drcEngine->IsCancelled() )
1184 break;
1185 }
1186 }
1187 } );
1188
1189 std::future_status status = retn.wait_for( std::chrono::milliseconds( 250 ) );
1190
1191 while( status != std::future_status::ready )
1192 {
1193 reportProgress( done, count );
1194 status = retn.wait_for( std::chrono::milliseconds( 250 ) );
1195 }
1196}
1197
1198
1200{
1201 bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE );
1202 bool testIntersects = !m_drcEngine->IsErrorLimitExceeded( DRCE_ZONES_INTERSECT );
1203 DRC_CONSTRAINT constraint;
1204
1205 std::vector<std::map<PCB_LAYER_ID, std::vector<SEG>>> poly_segments;
1206 poly_segments.resize( m_board->m_DRCCopperZones.size() );
1207
1208 // Contains the index for zoneA, zoneB, the conflict point, the actual clearance, the
1209 // required clearance, and the layer
1210 using report_data = std::tuple<int, int, VECTOR2I, int, int, PCB_LAYER_ID>;
1211
1212 std::vector<std::future<report_data>> futures;
1214 std::atomic<size_t> done( 1 );
1215
1216 auto checkZones =
1217 [this, testClearance, testIntersects, &poly_segments, &done]
1218 ( int zoneA, int zoneB, int clearance, PCB_LAYER_ID layer ) -> report_data
1219 {
1220 // Iterate through all the segments of refSmoothedPoly
1221 std::map<VECTOR2I, int> conflictPoints;
1222
1223 std::vector<SEG>& refSegments = poly_segments[zoneA][layer];
1224 std::vector<SEG>& testSegments = poly_segments[zoneB][layer];
1225 bool reported = false;
1226 auto invalid_result = std::make_tuple( -1, -1, VECTOR2I(), 0, 0, F_Cu );
1227
1228 for( SEG& refSegment : refSegments )
1229 {
1230 int ax1 = refSegment.A.x;
1231 int ay1 = refSegment.A.y;
1232 int ax2 = refSegment.B.x;
1233 int ay2 = refSegment.B.y;
1234
1235 // Iterate through all the segments in smoothed_polys[ia2]
1236 for( SEG& testSegment : testSegments )
1237 {
1238 // Build test segment
1239 VECTOR2I pt;
1240
1241 int bx1 = testSegment.A.x;
1242 int by1 = testSegment.A.y;
1243 int bx2 = testSegment.B.x;
1244 int by2 = testSegment.B.y;
1245
1246 // We have ensured that the 'A' segment starts before the 'B' segment,
1247 // so if the 'A' segment ends before the 'B' segment starts, we can skip
1248 // to the next 'A'
1249 if( ax2 < bx1 )
1250 break;
1251
1252 int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2, 0,
1253 ax1, ay1, ax2, ay2, 0,
1254 clearance, &pt.x, &pt.y );
1255
1256 if( d < clearance )
1257 {
1258 if( d == 0 && testIntersects )
1259 reported = true;
1260 else if( testClearance )
1261 reported = true;
1262
1263 if( reported )
1264 {
1265 done.fetch_add( 1 );
1266 return std::make_tuple( zoneA, zoneB, pt, d, clearance, layer );
1267 }
1268 }
1269
1270 if( m_drcEngine->IsCancelled() )
1271 return invalid_result;
1272 }
1273 }
1274
1275 done.fetch_add( 1 );
1276 return invalid_result;
1277 };
1278
1279
1281 {
1282 int zone2zoneClearance;
1283
1284 // Skip over layers not used on the current board
1285 if( !m_board->IsLayerEnabled( layer ) )
1286 continue;
1287
1288 for( size_t ii = 0; ii < m_board->m_DRCCopperZones.size(); ii++ )
1289 {
1290 if( m_board->m_DRCCopperZones[ii]->IsOnLayer( layer ) )
1291 {
1292 SHAPE_POLY_SET poly = *m_board->m_DRCCopperZones[ii]->GetFilledPolysList( layer );
1293 std::vector<SEG>& zone_layer_poly_segs = poly_segments[ii][layer];
1294
1295 poly.BuildBBoxCaches();
1296 zone_layer_poly_segs.reserve( poly.FullPointCount() );
1297
1298 for( auto it = poly.IterateSegmentsWithHoles(); it; it++ )
1299 {
1300 SEG seg = *it;
1301
1302 if( seg.A.x > seg.B.x )
1303 seg.Reverse();
1304
1305 zone_layer_poly_segs.push_back( seg );
1306 }
1307
1308 std::sort( zone_layer_poly_segs.begin(), zone_layer_poly_segs.end() );
1309 }
1310 }
1311
1312 std::vector<std::pair<int, int>> zonePairs;
1313
1314 for( size_t ia = 0; ia < m_board->m_DRCCopperZones.size(); ia++ )
1315 {
1316 ZONE* zoneA = m_board->m_DRCCopperZones[ia];
1317
1318 if( !zoneA->IsOnLayer( layer ) )
1319 continue;
1320
1321 for( size_t ia2 = ia + 1; ia2 < m_board->m_DRCCopperZones.size(); ia2++ )
1322 {
1323 ZONE* zoneB = m_board->m_DRCCopperZones[ia2];
1324
1325 // test for same layer
1326 if( !zoneB->IsOnLayer( layer ) )
1327 continue;
1328
1329 // Test for same net
1330 if( zoneA->GetNetCode() == zoneB->GetNetCode() && zoneA->GetNetCode() >= 0 )
1331 continue;
1332
1333 // rule areas may overlap at will
1334 if( zoneA->GetIsRuleArea() || zoneB->GetIsRuleArea() )
1335 continue;
1336
1337 // Examine a candidate zone: compare zoneB to zoneA
1338 SHAPE_POLY_SET* polyA = m_board->m_DRCCopperZones[ia]->GetFill( layer );
1339 SHAPE_POLY_SET* polyB = m_board->m_DRCCopperZones[ia2]->GetFill( layer );
1340
1341 if( !polyA->BBoxFromCaches().Intersects( polyB->BBoxFromCaches() ) )
1342 continue;
1343
1344 // Get clearance used in zone to zone test.
1345 constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, zoneA, zoneB, layer );
1346 zone2zoneClearance = constraint.GetValue().Min();
1347
1348 if( constraint.GetSeverity() == RPT_SEVERITY_IGNORE || zone2zoneClearance <= 0 )
1349 continue;
1350
1351 futures.push_back( tp.submit( checkZones, ia, ia2, zone2zoneClearance, layer ) );
1352 }
1353 }
1354 }
1355
1356 size_t count = futures.size();
1357
1358 for( auto& task : futures )
1359 {
1360 if( !task.valid() )
1361 continue;
1362
1363 std::future_status result;
1364
1365 while( true )
1366 {
1367 result = task.wait_for( std::chrono::milliseconds( 250 ) );
1368
1369 reportProgress( done, count );
1370
1371 if( m_drcEngine->IsCancelled() )
1372 break;
1373
1374 if( result == std::future_status::ready )
1375 {
1376 report_data data = task.get();
1377 int zoneA_idx = std::get<0>( data );
1378 int zoneB_idx = std::get<1>( data );
1379 VECTOR2I pt = std::get<2>( data );
1380 int actual = std::get<3>( data );
1381 int required = std::get<4>( data );
1382 PCB_LAYER_ID layer = std::get<5>( data );
1383
1384 if( zoneA_idx >= 0 )
1385 {
1386 ZONE* zoneA = m_board->m_DRCCopperZones[zoneA_idx];
1387 ZONE* zoneB = m_board->m_DRCCopperZones[zoneB_idx];
1388
1389 constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, zoneA, zoneB, layer );
1390 std::shared_ptr<DRC_ITEM> drce;
1391
1392 if( actual <= 0 && testIntersects )
1393 {
1395 }
1396 else if( testClearance )
1397 {
1399 wxString msg = formatMsg( _( "(%s clearance %s; actual %s)" ),
1400 constraint.GetName(),
1401 required,
1402 std::max( actual, 0 ) );
1403
1404 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
1405 }
1406
1407 if( drce )
1408 {
1409 drce->SetItems( zoneA, zoneB );
1410 drce->SetViolatingRule( constraint.GetParentRule() );
1411 ReportAndShowPathCuToCu( drce, pt, layer, zoneA, zoneB, layer, actual );
1412 }
1413 }
1414
1415 break;
1416 }
1417 }
1418 }
1419}
1420
1421
1422namespace detail
1423{
1425}
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
NETINFO_ITEM * GetNet() const
Return #NET_INFO object for a given item.
const wxString & GetShortNetname() const
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:79
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:237
virtual bool IsConnected() const
Returns information if the object is derived from BOARD_CONNECTED_ITEM.
Definition: board_item.h:133
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:279
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:299
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:257
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:215
virtual std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const
Definition: board_item.cpp:289
virtual bool HasHole() const
Definition: board_item.h:155
std::vector< ZONE * > m_DRCCopperZones
Definition: board.h:1305
bool IsLayerEnabled(PCB_LAYER_ID aLayer) const
A proxy function that calls the correspondent function in m_BoardSettings tests whether a given layer...
Definition: board.cpp:801
int GetCopperLayerCount() const
Definition: board.cpp:738
const FOOTPRINTS & Footprints() const
Definition: board.h:331
const TRACKS & Tracks() const
Definition: board.h:329
std::shared_ptr< DRC_RTREE > m_CopperItemRTreeCache
Definition: board.h:1299
int m_DRCMaxClearance
Definition: board.h:1306
std::unordered_map< ZONE *, std::unique_ptr< DRC_RTREE > > m_CopperZoneRTreeCache
Definition: board.h:1298
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:892
const DRAWINGS & Drawings() const
Definition: board.h:333
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:558
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition: box2.h:311
wxString GetName() const
Definition: drc_rule.h:160
SEVERITY GetSeverity() const
Definition: drc_rule.h:173
const MINOPTMAX< int > & GetValue() const
Definition: drc_rule.h:152
DRC_RULE * GetParentRule() const
Definition: drc_rule.h:156
BOARD * GetBoard() const
Definition: drc_engine.h:99
bool GetReportAllTrackErrors() const
Definition: drc_engine.h:190
bool IsErrorLimitExceeded(int error_code)
DRC_CONSTRAINT EvalRules(DRC_CONSTRAINT_T aConstraintType, const BOARD_ITEM *a, const BOARD_ITEM *b, PCB_LAYER_ID aLayer, REPORTER *aReporter=nullptr)
Definition: drc_engine.cpp:679
bool IsCancelled() const
bool IsNetTieExclusion(int aTrackNetCode, PCB_LAYER_ID aTrackLayer, const VECTOR2I &aCollisionPos, BOARD_ITEM *aCollidingItem)
Check if the given collision between a track and another item occurs during the track's entry into a ...
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
Definition: drc_item.cpp:372
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:215
void ReportAndShowPathCuToCu(std::shared_ptr< DRC_ITEM > &aDrce, const VECTOR2I &aMarkerPos, int aMarkerLayer, const BOARD_ITEM *aItem1, const BOARD_ITEM *aItem2, PCB_LAYER_ID layer, int aDistance)
void testPadAgainstItem(PAD *pad, SHAPE *padShape, PCB_LAYER_ID layer, BOARD_ITEM *other)
struct DRC_TEST_PROVIDER_COPPER_CLEARANCE::checked layers_checked
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
void testItemAgainstZone(BOARD_ITEM *aItem, ZONE *aZone, PCB_LAYER_ID aLayer)
virtual const wxString GetDescription() const override
virtual const wxString GetName() const override
void testKnockoutTextAgainstZone(BOARD_ITEM *aText, NETINFO_ITEM **aInheritedNet, ZONE *aZone)
bool testSingleLayerItemAgainstItem(BOARD_CONNECTED_ITEM *item, SHAPE *itemShape, PCB_LAYER_ID layer, BOARD_ITEM *other)
Checks for track/via/hole <-> clearance.
wxString formatMsg(const wxString &aFormatString, const wxString &aSource, double aConstraint, double aActual)
virtual bool reportPhase(const wxString &aStageName)
virtual void reportViolation(std::shared_ptr< DRC_ITEM > &item, const VECTOR2I &aMarkerPos, int aMarkerLayer)
DRC_ENGINE * m_drcEngine
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:77
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
std::vector< PAD * > GetNetTiePads(PAD *aPad) const
Definition: footprint.cpp:3027
std::map< wxString, int > MapPadNumbersToNetTieGroups() const
Definition: footprint.cpp:2972
std::deque< PAD * > & Pads()
Definition: footprint.h:206
bool IsNetTie() const
Definition: footprint.h:297
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:36
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:676
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:410
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
Definition: lset.h:60
T Min() const
Definition: minoptmax.h:33
Handle the data for a net.
Definition: netinfo.h:56
Definition: pad.h:54
bool FlashLayer(int aLayer, bool aOnlyCheckIfPermitted=false) const
Check to see whether the pad should be flashed on the specific layer.
Definition: pad.cpp:340
const VECTOR2I & GetDrillSize() const
Definition: pad.h:307
PAD_ATTRIB GetAttribute() const
Definition: pad.h:442
const wxString & GetNumber() const
Definition: pad.h:134
VECTOR2I GetPosition() const override
Definition: pad.h:210
bool HasHole() const override
Definition: pad.h:104
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const override
Return a SHAPE_SEGMENT object representing the pad's hole.
Definition: pad.cpp:545
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pcb_track.cpp:1041
const VECTOR2I & GetStart() const
Definition: pcb_track.h:122
std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: pcb_track.cpp:1914
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:119
int GetDrill() const
Return the local drill setting for this PCB_VIA.
Definition: pcb_track.h:612
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const override
Definition: pcb_track.cpp:848
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
Definition: pcb_track.cpp:971
Definition: seg.h:42
VECTOR2I A
Definition: seg.h:49
VECTOR2I B
Definition: seg.h:50
OPT_VECTOR2I Intersect(const SEG &aSeg, bool aIgnoreEndpoints=false, bool aLines=false) const
Compute intersection point of segment (this) with segment aSeg.
Definition: seg.cpp:254
void Reverse()
Definition: seg.h:358
Represent a set of closed polygons.
int FullPointCount() const
Return the number of points in the shape poly set.
void BuildBBoxCaches() const
Construct BBoxCaches for Contains(), below.
SEGMENT_ITERATOR IterateSegmentsWithHoles()
Returns an iterator object, for all outlines in the set (with holes)
const BOX2I BBoxFromCaches() const
An abstract shape on 2D plane.
Definition: shape.h:126
virtual bool Collide(const VECTOR2I &aP, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const
Check if the boundary of shape (this) lies closer to the point aP than aClearance,...
Definition: shape.h:181
Handle a list of polygons defining a copper zone.
Definition: zone.h:73
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition: zone.h:721
const BOX2I GetBoundingBox() const override
Definition: zone.cpp:381
virtual PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: zone.cpp:260
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Test to see if this object is on the given layer.
Definition: zone.cpp:375
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: zone.h:130
The common library.
@ DRCE_HOLE_CLEARANCE
Definition: drc_item.h:54
@ DRCE_ZONES_INTERSECT
Definition: drc_item.h:47
@ DRCE_CLEARANCE
Definition: drc_item.h:43
@ DRCE_SHORTING_ITEMS
Definition: drc_item.h:40
@ DRCE_TRACKS_CROSSING
Definition: drc_item.h:45
@ CLEARANCE_CONSTRAINT
Definition: drc_rule.h:49
@ HOLE_CLEARANCE_CONSTRAINT
Definition: drc_rule.h:51
#define _(s)
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:531
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ B_Cu
Definition: layer_ids.h:65
@ F_Cu
Definition: layer_ids.h:64
static DRC_REGISTER_TEST_PROVIDER< DRC_TEST_PROVIDER_ANNULAR_WIDTH > dummy
@ RPT_SEVERITY_IGNORE
std::optional< VECTOR2I > OPT_VECTOR2I
Definition: seg.h:39
static bool Collide(const SHAPE_CIRCLE &aA, const SHAPE_CIRCLE &aB, int aClearance, int *aActual, VECTOR2I *aLocation, VECTOR2I *aMTV)
static thread_pool * tp
Definition: thread_pool.cpp:30
BS::thread_pool thread_pool
Definition: thread_pool.h:30
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
Definition: thread_pool.cpp:32
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:88
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:92
@ PCB_REFERENCE_IMAGE_T
class PCB_REFERENCE_IMAGE, bitmap on a layer
Definition: typeinfo.h:89
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:98
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:691