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