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-2022 KiCad Developers.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#include <common.h>
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 bool 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 // This is the number of tests between 2 calls to the progress bar
561 const int progressDelta = 100;
562
563 reportAux( wxT( "Testing %d tracks & vias..." ), m_board->Tracks().size() );
564
565 std::map<BOARD_ITEM*, int> freePadsUsageMap;
566 std::unordered_map<PTR_PTR_CACHE_KEY, layers_checked> checkedPairs;
567 std::mutex checkedPairsMutex;
568 std::mutex freePadsUsageMapMutex;
569 std::atomic<int> tracks_checked( 0 );
570
571 LSET boardCopperLayers = LSET::AllCuMask( m_board->GetCopperLayerCount() );
572
573 auto testTrack = [&]( const int start_idx, const int end_idx )
574 {
575 for( int trackIdx = start_idx; trackIdx < end_idx; ++trackIdx )
576 {
577 PCB_TRACK* track = m_board->Tracks()[trackIdx];
578
579 for( PCB_LAYER_ID layer : LSET( track->GetLayerSet() & boardCopperLayers ).Seq() )
580 {
581 std::shared_ptr<SHAPE> trackShape = track->GetEffectiveShape( layer );
582
583 m_board->m_CopperItemRTreeCache->QueryColliding( track, layer, layer,
584 // Filter:
585 [&]( BOARD_ITEM* other ) -> bool
586 {
587 auto otherCItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( other );
588
589 if( otherCItem && otherCItem->GetNetCode() == track->GetNetCode() )
590 return false;
591
592 BOARD_ITEM* a = track;
593 BOARD_ITEM* b = other;
594
595 // store canonical order so we don't collide in both directions
596 // (a:b and b:a)
597 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
598 std::swap( a, b );
599
600 std::lock_guard<std::mutex> lock( checkedPairsMutex );
601 auto it = checkedPairs.find( { a, b } );
602
603 if( it != checkedPairs.end() && ( it->second.layers.test( layer )
604 || ( it->second.has_error && !m_drcEngine->GetReportAllTrackErrors() ) ) )
605 {
606 return false;
607 }
608 else
609 {
610 checkedPairs[ { a, b } ].layers.set( layer );
611 return true;
612 }
613 },
614 // Visitor:
615 [&]( BOARD_ITEM* other ) -> bool
616 {
617 if( other->Type() == PCB_PAD_T && static_cast<PAD*>( other )->IsFreePad() )
618 {
619 if( other->GetEffectiveShape( layer )->Collide( trackShape.get() ) )
620 {
621 std::lock_guard<std::mutex> lock( freePadsUsageMapMutex );
622 auto it = freePadsUsageMap.find( other );
623
624 if( it == freePadsUsageMap.end() )
625 {
626 freePadsUsageMap[ other ] = track->GetNetCode();
627 return false;
628 }
629 else if( it->second == track->GetNetCode() )
630 {
631 return false;
632 }
633 }
634 }
635
636 BOARD_ITEM* a = track;
637 BOARD_ITEM* b = other;
638
639 // store canonical order so we don't collide in both directions
640 // (a:b and b:a)
641 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
642 std::swap( a, b );
643
644 // If we get an error, mark the pair as having a clearance error already
645 // Only continue if we are reporting all track errors
646 if( !testSingleLayerItemAgainstItem( track, trackShape.get(), layer,
647 other ) )
648 {
649 std::lock_guard<std::mutex> lock( checkedPairsMutex );
650 auto it = checkedPairs.find( { a, b } );
651
652 if( it != checkedPairs.end() )
653 it->second.has_error = true;
654
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 ++tracks_checked;
672 }
673 };
674
676
677 tp.push_loop( m_board->Tracks().size(), testTrack );
678
679 while( tracks_checked < static_cast<int>( m_board->Tracks().size() ) )
680 {
681 if( !reportProgress( tracks_checked, m_board->Tracks().size(), progressDelta ) )
682 {
683 tp.wait_for_tasks();
684 break;
685 }
686
687 std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
688 }
689}
690
691
693 PCB_LAYER_ID aLayer,
694 BOARD_ITEM* other )
695{
696 bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE );
699
700 // Disable some tests for net-tie objects in a footprint
701 if( other->GetParent() == pad->GetParent() )
702 {
703 FOOTPRINT* fp = pad->GetParentFootprint();
704 std::map<wxString, int> padToNetTieGroupMap = fp->MapPadNumbersToNetTieGroups();
705 int padGroupIdx = padToNetTieGroupMap[ pad->GetNumber() ];
706
707 if( other->Type() == PCB_PAD_T )
708 {
709 PAD* otherPad = static_cast<PAD*>( other );
710
711 if( padGroupIdx >= 0 && padGroupIdx == padToNetTieGroupMap[ otherPad->GetNumber() ] )
712 testClearance = testShorting = false;
713
714 if( pad->SameLogicalPadAs( otherPad ) )
715 testHoles = false;
716 }
717
718 if( other->Type() == PCB_SHAPE_T && padGroupIdx >= 0 )
719 testClearance = testShorting = false;
720 }
721
722 PAD* otherPad = nullptr;
723 PCB_VIA* otherVia = nullptr;
724
725 if( other->Type() == PCB_PAD_T )
726 otherPad = static_cast<PAD*>( other );
727
728 if( other->Type() == PCB_VIA_T )
729 otherVia = static_cast<PCB_VIA*>( other );
730
731 if( !IsCopperLayer( aLayer ) )
732 testClearance = testShorting = false;
733
734 // A NPTH has no cylinder, but it may still have pads on some layers
735 if( pad->GetAttribute() == PAD_ATTRIB::NPTH && !pad->FlashLayer( aLayer ) )
736 testClearance = testShorting = false;
737
738 if( otherPad && otherPad->GetAttribute() == PAD_ATTRIB::NPTH && !otherPad->FlashLayer( aLayer ) )
739 testClearance = testShorting = false;
740
741 // Track clearances are tested in testTrackClearances()
742 if( dynamic_cast<PCB_TRACK*>( other) )
743 testClearance = testShorting = false;
744
745 int padNet = pad->GetNetCode();
746 int otherNet = 0;
747
748 if( BOARD_CONNECTED_ITEM* connectedItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( other ) )
749 otherNet = connectedItem->GetNetCode();
750
751 // Other objects of the same (defined) net get a waiver on clearance and hole tests
752 if( otherNet && otherNet == padNet )
753 {
754 testClearance = testShorting = false;
755 testHoles = false;
756 }
757
758 if( !( pad->GetDrillSize().x > 0 )
759 && !( otherPad && otherPad->GetDrillSize().x > 0 )
760 && !( otherVia && otherVia->GetDrill() > 0 ) )
761 {
762 testHoles = false;
763 }
764
765 if( !testClearance && !testShorting && !testHoles )
766 return false;
767
768 std::shared_ptr<SHAPE> otherShape = other->GetEffectiveShape( aLayer );
769 DRC_CONSTRAINT constraint;
770 int clearance = 0;
771 int actual = 0;
772 VECTOR2I pos;
773
774 if( otherPad && pad->SameLogicalPadAs( otherPad ) )
775 {
776 // If pads are equivalent (ie: from the same footprint with the same pad number)...
777 // ... and have "real" nets...
778 // then they must be the same net
779 if( testShorting )
780 {
781 if( pad->GetNetCode() == 0 || pad->GetNetCode() == otherPad->GetNetCode() )
782 return !m_drcEngine->IsCancelled();
783
784 if( pad->GetShortNetname().StartsWith( wxS( "unconnected-(" ) )
785 && otherPad->GetShortNetname().StartsWith( wxS( "unconnected-(" ) ) )
786 {
787 return !m_drcEngine->IsCancelled();
788 }
789
790 std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_SHORTING_ITEMS );
791 wxString msg;
792
793 msg.Printf( _( "(nets %s and %s)" ),
794 pad->GetNetname(),
795 otherPad->GetNetname() );
796
797 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
798 drce->SetItems( pad, otherPad );
799
800 reportViolation( drce, otherPad->GetPosition(), aLayer );
801 }
802
803 return !m_drcEngine->IsCancelled();
804 }
805
806 if( testClearance || testShorting )
807 {
808 constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, pad, other, aLayer );
809 clearance = constraint.GetValue().Min();
810
811 if( constraint.GetSeverity() != RPT_SEVERITY_IGNORE && clearance > 0 )
812 {
813 if( padShape->Collide( otherShape.get(), std::max( 0, clearance - m_drcEpsilon ),
814 &actual, &pos ) )
815 {
816 if( m_drcEngine->IsNetTieExclusion( pad->GetNetCode(), aLayer, pos, other ) )
817 {
818 // Pads connected to pads of a net-tie footprint are allowed to collide
819 // with the net-tie footprint's graphics.
820 }
821 else if( actual == 0 && otherNet && testShorting )
822 {
823 std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_SHORTING_ITEMS );
824 wxString msg;
825
826 msg.Printf( _( "(nets %s and %s)" ),
827 pad->GetNetname(),
828 static_cast<BOARD_CONNECTED_ITEM*>( other )->GetNetname() );
829
830 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
831 drce->SetItems( pad, other );
832
833 reportViolation( drce, pos, aLayer );
834 testHoles = false; // No need for multiple violations
835 }
836 else if( testClearance )
837 {
838 std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CLEARANCE );
839 wxString msg = formatMsg( _( "(%s clearance %s; actual %s)" ),
840 constraint.GetName(),
841 clearance,
842 actual );
843
844 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
845 drce->SetItems( pad, other );
846 drce->SetViolatingRule( constraint.GetParentRule() );
847
848 reportViolation( drce, pos, aLayer );
849 testHoles = false; // No need for multiple violations
850 }
851 }
852 }
853 }
854
855 if( testHoles )
856 {
857 constraint = m_drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, pad, other, aLayer );
858 clearance = constraint.GetValue().Min();
859
860 if( constraint.GetSeverity() == RPT_SEVERITY_IGNORE )
861 testHoles = false;
862 }
863
864 if( testHoles && otherPad && pad->FlashLayer( aLayer ) && otherPad->HasHole() )
865 {
866 if( clearance > 0 && padShape->Collide( otherPad->GetEffectiveHoleShape().get(),
867 std::max( 0, clearance - m_drcEpsilon ),
868 &actual, &pos ) )
869 {
870 std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
871 wxString msg = formatMsg( _( "(%s clearance %s; actual %s)" ),
872 constraint.GetName(),
873 clearance,
874 actual );
875
876 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
877 drce->SetItems( pad, other );
878 drce->SetViolatingRule( constraint.GetParentRule() );
879
880 reportViolation( drce, pos, aLayer );
881 testHoles = false; // No need for multiple violations
882 }
883 }
884
885 if( testHoles && otherPad && otherPad->FlashLayer( aLayer ) && pad->HasHole() )
886 {
887 if( clearance > 0 && otherShape->Collide( pad->GetEffectiveHoleShape().get(),
888 std::max( 0, clearance - m_drcEpsilon ),
889 &actual, &pos ) )
890 {
891 std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
892 wxString msg = formatMsg( _( "(%s clearance %s; actual %s)" ),
893 constraint.GetName(),
894 clearance,
895 actual );
896
897 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
898 drce->SetItems( pad, other );
899 drce->SetViolatingRule( constraint.GetParentRule() );
900
901 reportViolation( drce, pos, aLayer );
902 testHoles = false; // No need for multiple violations
903 }
904 }
905
906 if( testHoles && otherVia && otherVia->IsOnLayer( aLayer ) )
907 {
908 if( clearance > 0 && padShape->Collide( otherVia->GetEffectiveHoleShape().get(),
909 std::max( 0, clearance - m_drcEpsilon ),
910 &actual, &pos ) )
911 {
912 std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
913 wxString msg = formatMsg( _( "(%s clearance %s; actual %s)" ),
914 constraint.GetName(),
915 clearance,
916 actual );
917
918 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
919 drce->SetItems( pad, otherVia );
920 drce->SetViolatingRule( constraint.GetParentRule() );
921
922 reportViolation( drce, pos, aLayer );
923 }
924 }
925
926 return !m_drcEngine->IsCancelled();
927}
928
929
931{
932 const int progressDelta = 100;
933 size_t count = 0;
934 int ii = 0;
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 for( FOOTPRINT* footprint : m_board->Footprints() )
946 {
947 for( PAD* pad : footprint->Pads() )
948 {
949 for( PCB_LAYER_ID layer : LSET( pad->GetLayerSet() & boardCopperLayers ).Seq() )
950 {
951 std::shared_ptr<SHAPE> padShape = pad->GetEffectiveShape( layer );
952
953 m_board->m_CopperItemRTreeCache->QueryColliding( pad, layer, layer,
954 // Filter:
955 [&]( BOARD_ITEM* other ) -> bool
956 {
957 BOARD_ITEM* a = pad;
958 BOARD_ITEM* b = other;
959
960 // store canonical order so we don't collide in both directions
961 // (a:b and b:a)
962 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
963 std::swap( a, b );
964
965 if( checkedPairs.find( { a, b } ) != checkedPairs.end() )
966 {
967 return false;
968 }
969 else
970 {
971 checkedPairs[ { a, b } ] = 1;
972 return true;
973 }
974 },
975 // Visitor
976 [&]( BOARD_ITEM* other ) -> bool
977 {
978 return testPadAgainstItem( pad, padShape.get(), layer, other );
979 },
981
982 for( ZONE* zone : m_board->m_DRCCopperZones )
983 {
984 testItemAgainstZone( pad, zone, layer );
985
986 if( m_drcEngine->IsCancelled() )
987 return;
988 }
989 }
990
991 if( !reportProgress( ii++, (int) count, progressDelta ) )
992 return;
993 }
994
995 if( m_drcEngine->IsCancelled() )
996 return;
997 }
998}
999
1000
1002{
1003 const int progressDelta = 100;
1004 size_t count = m_board->Drawings().size();
1005 int ii = 0;
1006
1007 for( FOOTPRINT* footprint : m_board->Footprints() )
1008 count += footprint->GraphicalItems().size();
1009
1010 reportAux( wxT( "Testing %d graphics..." ), count );
1011
1012 auto isKnockoutText =
1013 []( BOARD_ITEM* item )
1014 {
1015 return item->Type() == PCB_TEXT_T && static_cast<PCB_TEXT*>( item )->IsKnockout();
1016 };
1017
1018 auto testGraphicAgainstZone =
1019 [&]( BOARD_ITEM* item )
1020 {
1021 if( !IsCopperLayer( item->GetLayer() ) )
1022 return;
1023
1024 // Knockout text is most often knocked-out of a zone, so it's presumed to
1025 // collide with one. However, if it collides with more than one, and they
1026 // have different nets, then we have a short.
1027 NETINFO_ITEM* inheritedNet = nullptr;
1028
1029 for( ZONE* zone : m_board->m_DRCCopperZones )
1030 {
1031 if( isKnockoutText( item ) )
1032 testKnockoutTextAgainstZone( item, &inheritedNet, zone );
1033 else
1034 testItemAgainstZone( item, zone, item->GetLayer() );
1035
1036 if( m_drcEngine->IsCancelled() )
1037 return;
1038 }
1039 };
1040
1041 std::unordered_map<PTR_PTR_CACHE_KEY, layers_checked> checkedPairs;
1042
1043 auto testCopperGraphic =
1044 [&]( PCB_SHAPE* aShape )
1045 {
1046 PCB_LAYER_ID layer = aShape->GetLayer();
1047
1048 m_board->m_CopperItemRTreeCache->QueryColliding( aShape, layer, layer,
1049 // Filter:
1050 [&]( BOARD_ITEM* other ) -> bool
1051 {
1052 auto otherCItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( other );
1053
1054 if( otherCItem && otherCItem->GetNetCode() == aShape->GetNetCode() )
1055 return false;
1056
1057 // Pads and tracks handled separately
1058 if( other->Type() == PCB_PAD_T || other->Type() == PCB_ARC_T ||
1059 other->Type() == PCB_TRACE_T || other->Type() == PCB_VIA_T )
1060 {
1061 return false;
1062 }
1063
1064 BOARD_ITEM* a = aShape;
1065 BOARD_ITEM* b = other;
1066
1067 // store canonical order so we don't collide in both directions
1068 // (a:b and b:a)
1069 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
1070 std::swap( a, b );
1071
1072 auto it = checkedPairs.find( { a, b } );
1073
1074 if( it != checkedPairs.end() && it->second.layers.test( layer ) )
1075 {
1076 return false;
1077 }
1078 else
1079 {
1080 checkedPairs[ { a, b } ].layers.set( layer );
1081 return true;
1082 }
1083 },
1084 // Visitor:
1085 [&]( BOARD_ITEM* other ) -> bool
1086 {
1087 BOARD_ITEM* a = aShape;
1088 BOARD_ITEM* b = other;
1089
1090 // store canonical order so we don't collide in both directions
1091 // (a:b and b:a)
1092 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
1093 std::swap( a, b );
1094
1095 auto it = checkedPairs.find( { a, b } );
1096
1097 if( !testSingleLayerItemAgainstItem( aShape,
1098 aShape->GetEffectiveShape().get(),
1099 layer, other ) )
1100 {
1101 if( it != checkedPairs.end() )
1102 it->second.has_error = true;
1103 }
1104
1105 return !m_drcEngine->IsCancelled();
1106 },
1108 };
1109
1110 for( BOARD_ITEM* item : m_board->Drawings() )
1111 {
1112 testGraphicAgainstZone( item );
1113
1114 if( item->Type() == PCB_SHAPE_T && item->IsOnCopperLayer() )
1115 testCopperGraphic( static_cast<PCB_SHAPE*>( item ) );
1116
1117 if( !reportProgress( ii++, (int) count, progressDelta ) )
1118 return;
1119 }
1120
1121 for( FOOTPRINT* footprint : m_board->Footprints() )
1122 {
1123 for( BOARD_ITEM* item : footprint->GraphicalItems() )
1124 {
1125 testGraphicAgainstZone( item );
1126
1127 if( !reportProgress( ii++, (int) count, progressDelta ) )
1128 return;
1129 }
1130 }
1131}
1132
1133
1135{
1136 const int progressDelta = 50;
1137
1138 bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE );
1139 bool testIntersects = !m_drcEngine->IsErrorLimitExceeded( DRCE_ZONES_INTERSECT );
1140
1141 DRC_CONSTRAINT constraint;
1142 bool cancelled = false;
1143 std::vector<std::map<PCB_LAYER_ID, std::vector<SEG>>> poly_segments;
1144
1145 poly_segments.resize( m_board->m_DRCCopperZones.size() );
1146
1147 // Contains the index for zoneA, zoneB, the conflict point, the actual clearance, the required clearance, and the layer
1148 using report_data = std::tuple<int, int, VECTOR2I, int, int, PCB_LAYER_ID>;
1149 const int invalid_zone = -1;
1150
1151 std::vector<std::future<report_data>> futures;
1153
1154 auto checkZones = [testClearance, testIntersects, &poly_segments, &cancelled, invalid_zone]
1155 ( int zoneA, int zoneB,
1156 int zone2zoneClearance, PCB_LAYER_ID layer ) -> report_data
1157 {
1158 // Iterate through all the segments of refSmoothedPoly
1159 std::map<VECTOR2I, int> conflictPoints;
1160
1161 std::vector<SEG>& refSegments = poly_segments[zoneA][layer];
1162 std::vector<SEG>& testSegments = poly_segments[zoneB][layer];
1163 bool reported = false;
1164 auto invalid_result = std::make_tuple( invalid_zone, invalid_zone, VECTOR2I(), 0, 0, F_Cu );
1165
1166 for( SEG& refSegment : refSegments )
1167 {
1168 int ax1 = refSegment.A.x;
1169 int ay1 = refSegment.A.y;
1170 int ax2 = refSegment.B.x;
1171 int ay2 = refSegment.B.y;
1172
1173 // Iterate through all the segments in smoothed_polys[ia2]
1174 for( SEG& testSegment : testSegments )
1175 {
1176 // Build test segment
1177 VECTOR2I pt;
1178
1179 int bx1 = testSegment.A.x;
1180 int by1 = testSegment.A.y;
1181 int bx2 = testSegment.B.x;
1182 int by2 = testSegment.B.y;
1183
1184 // We have ensured that the A segment starts before the B segment, so if the
1185 // A segment ends before the B segment starts, we can skip to the next A
1186 if( ax2 < bx1 )
1187 break;
1188
1189 int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2, 0,
1190 ax1, ay1, ax2, ay2, 0,
1191 zone2zoneClearance, &pt.x, &pt.y );
1192
1193 if( d < zone2zoneClearance )
1194 {
1195 if( d == 0 && testIntersects )
1196 reported = true;
1197 else if( testClearance )
1198 reported = true;
1199
1200 if( reported )
1201 return std::make_tuple( zoneA, zoneB, pt, d, zone2zoneClearance, layer );
1202 }
1203
1204 if( cancelled )
1205 return invalid_result;
1206 }
1207 }
1208
1209 return invalid_result;
1210 };
1211
1212 for( int layer_id = F_Cu; layer_id <= B_Cu; ++layer_id )
1213 {
1214 PCB_LAYER_ID layer = static_cast<PCB_LAYER_ID>( layer_id );
1215 int zone2zoneClearance;
1216
1217 // Skip over layers not used on the current board
1218 if( !m_board->IsLayerEnabled( layer ) )
1219 continue;
1220
1221 for( size_t ii = 0; ii < m_board->m_DRCCopperZones.size(); ii++ )
1222 {
1223 if( m_board->m_DRCCopperZones[ii]->IsOnLayer( layer ) )
1224 {
1225 SHAPE_POLY_SET poly =
1226 *m_board->m_DRCCopperZones[ii]->GetFilledPolysList( layer );
1227 std::vector<SEG>& poly_segs = poly_segments[ii][layer];
1228
1230 poly.BuildBBoxCaches();
1231 poly_segs.reserve( poly.FullPointCount() );
1232
1233 for( auto it = poly.IterateSegmentsWithHoles(); it; it++ )
1234 {
1235 SEG seg = *it;
1236
1237 if( seg.A.x > seg.B.x )
1238 seg.Reverse();
1239
1240 poly_segs.push_back( seg );
1241 }
1242
1243 std::sort( poly_segs.begin(), poly_segs.end() );
1244 }
1245 }
1246
1247 std::vector<std::pair<int, int>> zonePairs;
1248
1249 for( size_t ia = 0; ia < m_board->m_DRCCopperZones.size(); ia++ )
1250 {
1251 if( !reportProgress( layer_id * m_board->m_DRCCopperZones.size() + ia,
1252 B_Cu * m_board->m_DRCCopperZones.size(), progressDelta ) )
1253 {
1254 return; // DRC cancelled
1255 }
1256
1257 ZONE* zoneA = m_board->m_DRCCopperZones[ia];
1258
1259 if( !zoneA->IsOnLayer( layer ) )
1260 continue;
1261
1262 for( size_t ia2 = ia + 1; ia2 < m_board->m_DRCCopperZones.size(); ia2++ )
1263 {
1264 ZONE* zoneB = m_board->m_DRCCopperZones[ia2];
1265
1266 // test for same layer
1267 if( !zoneB->IsOnLayer( layer ) )
1268 continue;
1269
1270 // Test for same net
1271 if( zoneA->GetNetCode() == zoneB->GetNetCode() && zoneA->GetNetCode() >= 0 )
1272 continue;
1273
1274 // rule areas may overlap at will
1275 if( zoneA->GetIsRuleArea() || zoneB->GetIsRuleArea() )
1276 continue;
1277
1278 // Examine a candidate zone: compare zoneB to zoneA
1279 SHAPE_POLY_SET* polyA = m_board->m_DRCCopperZones[ia]->GetFill( layer );
1280 SHAPE_POLY_SET* polyB = m_board->m_DRCCopperZones[ia2]->GetFill( layer );
1281
1282 if( !polyA->BBoxFromCaches().Intersects( polyB->BBoxFromCaches() ) )
1283 continue;
1284
1285 // Get clearance used in zone to zone test.
1286 constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, zoneA, zoneB, layer );
1287 zone2zoneClearance = constraint.GetValue().Min();
1288
1289 if( constraint.GetSeverity() == RPT_SEVERITY_IGNORE || zone2zoneClearance <= 0 )
1290 continue;
1291
1292 futures.push_back( tp.submit( checkZones, ia, ia2, zone2zoneClearance, layer ) );
1293 }
1294 }
1295 }
1296
1297 for( auto& task : futures )
1298 {
1299 if( !task.valid() )
1300 continue;
1301
1302 std::future_status result;
1303
1304 while( true )
1305 {
1306 result = task.wait_for( std::chrono::milliseconds( 200 ) );
1307
1308 if( m_drcEngine->IsCancelled() )
1309 {
1310 cancelled = true;
1311 break;
1312 }
1313
1314 if( result == std::future_status::ready )
1315 {
1316 report_data data = task.get();
1317 int zoneA_id = std::get<0>( data );
1318 int zoneB_id = std::get<1>( data );
1319 VECTOR2I pt = std::get<2>( data );
1320 int actual = std::get<3>( data );
1321 int required = std::get<4>( data );
1322 PCB_LAYER_ID layer = std::get<5>( data );
1323
1324 if( zoneA_id != invalid_zone )
1325 {
1326 ZONE* zoneA = m_board->m_DRCCopperZones[zoneA_id];
1327 ZONE* zoneB = m_board->m_DRCCopperZones[zoneB_id];
1328
1329 constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, zoneA, zoneB, layer );
1330 std::shared_ptr<DRC_ITEM> drce;
1331
1332 if( actual <= 0 && testIntersects )
1333 {
1335 }
1336 else if( testClearance )
1337 {
1339 wxString msg = formatMsg( _( "(%s clearance %s; actual %s)" ),
1340 constraint.GetName(),
1341 required,
1342 std::max( actual, 0 ) );
1343
1344 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
1345 }
1346
1347 if( drce )
1348 {
1349 drce->SetItems( zoneA, zoneB );
1350 drce->SetViolatingRule( constraint.GetParentRule() );
1351
1352 reportViolation( drce, pt, layer );
1353 }
1354 }
1355
1356 break;
1357 }
1358
1359 }
1360 }
1361}
1362
1363
1364namespace detail
1365{
1367}
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:204
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:227
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:209
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:182
virtual std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const
Definition: board_item.cpp:237
virtual bool HasHole() const
Definition: board_item.h:147
std::vector< ZONE * > m_DRCCopperZones
Definition: board.h:1204
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:640
FOOTPRINTS & Footprints()
Definition: board.h:313
int GetCopperLayerCount() const
Definition: board.cpp:590
TRACKS & Tracks()
Definition: board.h:310
DRAWINGS & Drawings()
Definition: board.h:316
std::shared_ptr< DRC_RTREE > m_CopperItemRTreeCache
Definition: board.h:1199
int m_DRCMaxClearance
Definition: board.h:1205
std::unordered_map< ZONE *, std::unique_ptr< DRC_RTREE > > m_CopperZoneRTreeCache
Definition: board.h:1198
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:731
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:666
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:325
Implement an R-tree for fast spatial and layer indexing of connectable items.
Definition: drc_rtree.h:48
int QueryColliding(BOARD_ITEM *aRefItem, PCB_LAYER_ID aRefLayer, PCB_LAYER_ID aTargetLayer, std::function< bool(BOARD_ITEM *)> aFilter=nullptr, std::function< bool(BOARD_ITEM *)> aVisitor=nullptr, int aClearance=0) const
This is a fast test which essentially does bounding-box overlap given a worst-case clearance.
Definition: drc_rtree.h:214
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
bool testPadAgainstItem(PAD *pad, SHAPE *padShape, PCB_LAYER_ID layer, BOARD_ITEM *other)
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.
virtual bool reportPhase(const wxString &aStageName)
virtual bool reportProgress(int aCount, int aSize, int aDelta)
virtual void reportViolation(std::shared_ptr< DRC_ITEM > &item, const VECTOR2I &aMarkerPos, int aMarkerLayer)
DRC_ENGINE * m_drcEngine
void reportAux(const wxString &aMsg)
wxString formatMsg(const wxString &aFormatString, const wxString &aSource, int aConstraint, int aActual)
virtual void reportRuleStatistics()
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition: eda_item.cpp:74
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
std::map< wxString, int > MapPadNumbersToNetTieGroups() const
Definition: footprint.cpp:2496
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:552
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:411
bool Contains(PCB_LAYER_ID aLayer)
See if the layer set contains a PCB layer.
Definition: layer_ids.h:622
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:773
T Min() const
Definition: minoptmax.h:33
Handle the data for a net.
Definition: netinfo.h:67
Definition: pad.h:58
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:253
PAD_ATTRIB GetAttribute() const
Definition: pad.h:372
const wxString & GetNumber() const
Definition: pad.h:130
VECTOR2I GetPosition() const override
Definition: pad.h:197
bool HasHole() const override
Definition: pad.h:105
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:1204
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:538
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const override
Definition: pcb_track.cpp:455
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
Definition: pcb_track.cpp:479
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.
void Fracture(POLYGON_MODE aFastMode)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
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:710
const BOX2I GetBoundingBox() const override
Definition: zone.cpp:354
virtual PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: zone.cpp:248
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Test to see if this object is on the given layer.
Definition: zone.cpp:348
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:847
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:94
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:91
@ 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:95
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:93
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588