KiCad PCB EDA Suite
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-2020 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 <board.h>
26 #include <board_design_settings.h>
27 #include <footprint.h>
28 #include <pcb_shape.h>
29 #include <pad.h>
30 #include <pcb_track.h>
31 #include <zone.h>
32 
33 #include <geometry/seg.h>
35 #include <geometry/shape_rect.h>
36 #include <geometry/shape_segment.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 /*
46  Copper clearance test. Checks all copper items (pads, vias, tracks, drawings, zones) for their electrical clearance.
47  Errors generated:
48  - DRCE_CLEARANCE
49  - DRCE_TRACKS_CROSSING
50  - DRCE_ZONES_INTERSECT
51  - DRCE_SHORTING_ITEMS
52 */
53 
55 {
56 public:
59  m_drcEpsilon( 0 )
60  {
61  }
62 
64  {
65  }
66 
67  virtual bool Run() override;
68 
69  virtual const wxString GetName() const override
70  {
71  return "clearance";
72  };
73 
74  virtual const wxString GetDescription() const override
75  {
76  return "Tests copper item clearance";
77  }
78 
79  virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
80 
81  int GetNumPhases() const override;
82 
83 private:
84  bool testTrackAgainstItem( PCB_TRACK* track, SHAPE* trackShape, PCB_LAYER_ID layer,
85  BOARD_ITEM* other );
86 
87  void testTrackClearances();
88 
89  bool testPadAgainstItem( PAD* pad, SHAPE* padShape, PCB_LAYER_ID layer, BOARD_ITEM* other );
90 
91  void testPadClearances();
92 
93  void testZones();
94 
95  void testItemAgainstZones( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer );
96 
97 private:
100 
101  std::vector<ZONE*> m_zones;
102 };
103 
104 
106 {
108  DRC_CONSTRAINT worstConstraint;
109 
110  if( m_drcEngine->QueryWorstConstraint( CLEARANCE_CONSTRAINT, worstConstraint ) )
111  m_largestClearance = worstConstraint.GetValue().Min();
112 
114  m_largestClearance = std::max( m_largestClearance, worstConstraint.GetValue().Min() );
115 
116  if( m_largestClearance <= 0 )
117  {
118  reportAux( "No Clearance constraints found. Tests not run." );
119  return true; // continue with other tests
120  }
121 
123 
124  m_zones.clear();
125 
126  for( ZONE* zone : m_board->Zones() )
127  {
128  if( !zone->GetIsRuleArea() )
129  {
130  m_zones.push_back( zone );
131  m_largestClearance = std::max( m_largestClearance, zone->GetLocalClearance() );
132  }
133  }
134 
135  for( FOOTPRINT* footprint : m_board->Footprints() )
136  {
137  for( PAD* pad : footprint->Pads() )
138  m_largestClearance = std::max( m_largestClearance, pad->GetLocalClearance() );
139 
140  for( ZONE* zone : footprint->Zones() )
141  {
142  if( !zone->GetIsRuleArea() )
143  {
144  m_zones.push_back( zone );
145  m_largestClearance = std::max( m_largestClearance, zone->GetLocalClearance() );
146  }
147  }
148  }
149 
150  reportAux( "Worst clearance : %d nm", m_largestClearance );
151 
152  // This is the number of tests between 2 calls to the progress bar
153  size_t delta = 50;
154  size_t count = 0;
155  size_t ii = 0;
156 
158 
159  auto countItems =
160  [&]( BOARD_ITEM* item ) -> bool
161  {
162  ++count;
163  return true;
164  };
165 
166  auto addToCopperTree =
167  [&]( BOARD_ITEM* item ) -> bool
168  {
169  if( !reportProgress( ii++, count, delta ) )
170  return false;
171 
172  LSET layers = item->GetLayerSet();
173 
174  // Special-case pad holes which pierce all the copper layers
175  if( item->Type() == PCB_PAD_T )
176  {
177  PAD* pad = static_cast<PAD*>( item );
178 
179  if( pad->GetDrillSizeX() > 0 && pad->GetDrillSizeY() > 0 )
180  layers |= LSET::AllCuMask();
181  }
182 
183  for( PCB_LAYER_ID layer : layers.Seq() )
184  {
185  if( IsCopperLayer( layer ) )
186  m_copperTree.Insert( item, layer, m_largestClearance );
187  }
188 
189  return true;
190  };
191 
192  if( !reportPhase( _( "Gathering copper items..." ) ) )
193  return false; // DRC cancelled
194 
195  static const std::vector<KICAD_T> itemTypes = {
199  };
200 
201  forEachGeometryItem( itemTypes, LSET::AllCuMask(), countItems );
202  forEachGeometryItem( itemTypes, LSET::AllCuMask(), addToCopperTree );
203 
204  reportAux( "Testing %d copper items and %d zones...", count, m_zones.size() );
205 
207  {
208  if( !reportPhase( _( "Checking track & via clearances..." ) ) )
209  return false; // DRC cancelled
210 
212  }
214  {
215  if( !reportPhase( _( "Checking hole clearances..." ) ) )
216  return false; // DRC cancelled
217 
219  }
220 
222  {
223  if( !reportPhase( _( "Checking pad clearances..." ) ) )
224  return false; // DRC cancelled
225 
227  }
230  {
231  if( !reportPhase( _( "Checking pads..." ) ) )
232  return false; // DRC cancelled
233 
235  }
236 
238  {
239  if( !reportPhase( _( "Checking copper zone clearances..." ) ) )
240  return false; // DRC cancelled
241 
242  testZones();
243  }
245  {
246  if( !reportPhase( _( "Checking zones..." ) ) )
247  return false; // DRC cancelled
248 
249  testZones();
250  }
251 
253 
254  return true;
255 }
256 
257 
259  PCB_LAYER_ID layer,
260  BOARD_ITEM* other )
261 {
262  bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE );
264  DRC_CONSTRAINT constraint;
265  int clearance = -1;
266  int actual;
267  VECTOR2I pos;
268 
269  if( other->Type() == PCB_PAD_T )
270  {
271  PAD* pad = static_cast<PAD*>( other );
272 
273  if( pad->GetAttribute() == PAD_ATTRIB::NPTH && !pad->FlashLayer( layer ) )
274  testClearance = false;
275  }
276 
277  if( testClearance )
278  {
279  constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, track, other, layer );
280  clearance = constraint.GetValue().Min();
281  }
282 
283  if( clearance >= 0 )
284  {
285  // Special processing for track:track intersections
286  if( track->Type() == PCB_TRACE_T && other->Type() == PCB_TRACE_T )
287  {
288  SEG trackSeg( track->GetStart(), track->GetEnd() );
289  SEG otherSeg( track->GetStart(), track->GetEnd() );
290 
291  if( OPT_VECTOR2I intersection = trackSeg.Intersect( otherSeg ) )
292  {
293  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TRACKS_CROSSING );
294  drcItem->SetItems( track, other );
295  drcItem->SetViolatingRule( constraint.GetParentRule() );
296 
297  reportViolation( drcItem, (wxPoint) intersection.get() );
298 
300  }
301  }
302 
303  std::shared_ptr<SHAPE> otherShape = DRC_ENGINE::GetShape( other, layer );
304 
305  if( trackShape->Collide( otherShape.get(), clearance - m_drcEpsilon, &actual, &pos ) )
306  {
307  std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CLEARANCE );
308 
309  m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
310  constraint.GetName(),
311  MessageTextFromValue( userUnits(), clearance ),
312  MessageTextFromValue( userUnits(), actual ) );
313 
314  drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
315  drce->SetItems( track, other );
316  drce->SetViolatingRule( constraint.GetParentRule() );
317 
318  reportViolation( drce, (wxPoint) pos );
319 
321  return false;
322  }
323  }
324 
325  if( testHoles && ( other->Type() == PCB_VIA_T || other->Type() == PCB_PAD_T ) )
326  {
327  std::unique_ptr<SHAPE_SEGMENT> holeShape;
328 
329  if( other->Type() == PCB_VIA_T )
330  {
331  PCB_VIA* via = static_cast<PCB_VIA*>( other );
332  pos = via->GetPosition();
333 
334  if( via->GetLayerSet().Contains( layer ) )
335  holeShape.reset( new SHAPE_SEGMENT( pos, pos, via->GetDrill() ) );
336  }
337  else if( other->Type() == PCB_PAD_T )
338  {
339  PAD* pad = static_cast<PAD*>( other );
340 
341  if( pad->GetDrillSize().x )
342  holeShape.reset( new SHAPE_SEGMENT( *pad->GetEffectiveHoleShape() ) );
343  }
344 
345  if( holeShape )
346  {
347  constraint = m_drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, other, track,
348  track->GetLayer() );
349  clearance = constraint.GetValue().Min();
350 
351  if( clearance >= 0 && trackShape->Collide( holeShape.get(),
352  std::max( 0, clearance - m_drcEpsilon ),
353  &actual, &pos ) )
354  {
355  std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
356 
357  m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
358  constraint.GetName(),
359  MessageTextFromValue( userUnits(), clearance ),
360  MessageTextFromValue( userUnits(), actual ) );
361 
362  drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
363  drce->SetItems( track, other );
364  drce->SetViolatingRule( constraint.GetParentRule() );
365 
366  reportViolation( drce, (wxPoint) pos );
367 
369  return false;
370  }
371  }
372  }
373 
374  return true;
375 }
376 
377 
379  PCB_LAYER_ID aLayer )
380 {
381  for( ZONE* zone : m_zones )
382  {
384  break;
385 
386  if( !zone->GetLayerSet().test( aLayer ) )
387  continue;
388 
389  if( zone->GetNetCode() && aItem->IsConnected() )
390  {
391  if( zone->GetNetCode() == static_cast<BOARD_CONNECTED_ITEM*>( aItem )->GetNetCode() )
392  continue;
393  }
394 
395  if( aItem->GetBoundingBox().Intersects( zone->GetCachedBoundingBox() ) )
396  {
397  auto constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, aItem, zone, aLayer );
398  int clearance = constraint.GetValue().Min();
399 
400  if( clearance < 0 )
401  continue;
402 
403  int actual;
404  VECTOR2I pos;
405  DRC_RTREE* zoneTree = m_board->m_CopperZoneRTrees[ zone ].get();
406  EDA_RECT itemBBox = aItem->GetBoundingBox();
407  std::shared_ptr<SHAPE> itemShape = aItem->GetEffectiveShape( aLayer );
408 
409  if( aItem->Type() == PCB_PAD_T )
410  {
411  PAD* pad = static_cast<PAD*>( aItem );
412 
413  if( !pad->FlashLayer( aLayer ) )
414  {
415  if( pad->GetDrillSize().x == 0 && pad->GetDrillSize().y == 0 )
416  continue;
417 
418  const SHAPE_SEGMENT* hole = pad->GetEffectiveHoleShape();
419  int size = hole->GetWidth();
420 
421  // Note: drill size represents finish size, which means the actual hole
422  // size is the plating thickness larger.
423  if( pad->GetAttribute() == PAD_ATTRIB::PTH )
425 
426  itemShape = std::make_shared<SHAPE_SEGMENT>( hole->GetSeg(), size );
427  }
428  }
429 
430  if( zoneTree->QueryColliding( itemBBox, itemShape.get(), aLayer,
431  clearance - m_drcEpsilon, &actual, &pos ) )
432  {
433  std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CLEARANCE );
434 
435  m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
436  constraint.GetName(),
437  MessageTextFromValue( userUnits(), clearance ),
438  MessageTextFromValue( userUnits(), actual ) );
439 
440  drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
441  drce->SetItems( aItem, zone );
442  drce->SetViolatingRule( constraint.GetParentRule() );
443 
444  reportViolation( drce, (wxPoint) pos );
445  }
446  }
447  }
448 }
449 
450 
452 {
453  // This is the number of tests between 2 calls to the progress bar
454  const int delta = 100;
455  int ii = 0;
456 
457  reportAux( "Testing %d tracks & vias...", m_board->Tracks().size() );
458 
459  std::map< std::pair<BOARD_ITEM*, BOARD_ITEM*>, int> checkedPairs;
460 
461  for( PCB_TRACK* track : m_board->Tracks() )
462  {
463  if( !reportProgress( ii++, m_board->Tracks().size(), delta ) )
464  break;
465 
466  for( PCB_LAYER_ID layer : track->GetLayerSet().Seq() )
467  {
468  std::shared_ptr<SHAPE> trackShape = track->GetEffectiveShape( layer );
469 
470  m_copperTree.QueryColliding( track, layer, layer,
471  // Filter:
472  [&]( BOARD_ITEM* other ) -> bool
473  {
474  // It would really be better to know what particular nets a nettie
475  // should allow, but for now it is what it is.
476  if( DRC_ENGINE::IsNetTie( other ) )
477  return false;
478 
479  auto otherCItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( other );
480 
481  if( otherCItem && otherCItem->GetNetCode() == track->GetNetCode() )
482  return false;
483 
484  BOARD_ITEM* a = track;
485  BOARD_ITEM* b = other;
486 
487  // store canonical order so we don't collide in both directions
488  // (a:b and b:a)
489  if( static_cast<void*>( a ) > static_cast<void*>( b ) )
490  std::swap( a, b );
491 
492  if( checkedPairs.count( { a, b } ) )
493  {
494  return false;
495  }
496  else
497  {
498  checkedPairs[ { a, b } ] = 1;
499  return true;
500  }
501  },
502  // Visitor:
503  [&]( BOARD_ITEM* other ) -> bool
504  {
505  return testTrackAgainstItem( track, trackShape.get(), layer, other );
506  },
508 
509  testItemAgainstZones( track, layer );
510  }
511  }
512 }
513 
514 
516  PCB_LAYER_ID layer,
517  BOARD_ITEM* other )
518 {
519  bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE );
520  bool testShorting = !m_drcEngine->IsErrorLimitExceeded( DRCE_SHORTING_ITEMS );
522 
523  // Disable some tests *within* a single footprint
524  if( other->GetParent() == pad->GetParent() )
525  {
526  FOOTPRINT* fp = static_cast<FOOTPRINT*>( pad->GetParent() );
527 
528  // Graphic items are allowed to act as net-ties within their own footprint
529  if( fp->IsNetTie() && ( other->Type() == PCB_FP_SHAPE_T || other->Type() == PCB_PAD_T ) )
530  testClearance = false;
531 
532  // No hole testing within a footprint
533  testHoles = false;
534  }
535 
536  // A NPTH has no cylinder, but it may still have pads on some layers
537  if( pad->GetAttribute() == PAD_ATTRIB::NPTH && !pad->FlashLayer( layer ) )
538  testClearance = false;
539 
540  if( !IsCopperLayer( layer ) )
541  testClearance = false;
542 
543  // Track clearances are tested in testTrackClearances()
544  if( dynamic_cast<PCB_TRACK*>( other) )
545  testClearance = false;
546 
547  if( !testClearance && !testShorting && !testHoles )
548  return false;
549 
550  std::shared_ptr<SHAPE> otherShape = DRC_ENGINE::GetShape( other, layer );
551  DRC_CONSTRAINT constraint;
552  int clearance;
553  int actual;
554  VECTOR2I pos;
555 
556  if( other->Type() == PCB_PAD_T )
557  {
558  PAD* otherPad = static_cast<PAD*>( other );
559 
560  // If pads are equivalent (ie: from the same footprint with the same pad number)...
561  if( pad->SameLogicalPadAs( otherPad ) )
562  {
563  // ...and have nets, then they must be the same net
564  if( pad->GetNetCode() && otherPad->GetNetCode()
565  && pad->GetNetCode() != otherPad->GetNetCode()
566  && testShorting )
567  {
568  std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_SHORTING_ITEMS );
569 
570  m_msg.Printf( _( "(nets %s and %s)" ),
571  pad->GetNetname(),
572  otherPad->GetNetname() );
573 
574  drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
575  drce->SetItems( pad, otherPad );
576 
577  reportViolation( drce, otherPad->GetPosition() );
578  }
579 
580  return true;
581  }
582 
583  if( testHoles && pad->FlashLayer( layer ) && otherPad->GetDrillSize().x )
584  {
585  constraint = m_drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, pad, otherPad, layer );
586  clearance = constraint.GetValue().Min();
587 
588  if( clearance >= 0 && padShape->Collide( otherPad->GetEffectiveHoleShape(),
589  std::max( 0, clearance - m_drcEpsilon ),
590  &actual, &pos ) )
591  {
592  std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
593 
594  m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
595  constraint.GetName(),
596  MessageTextFromValue( userUnits(), clearance ),
597  MessageTextFromValue( userUnits(), actual ) );
598 
599  drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
600  drce->SetItems( pad, other );
601  drce->SetViolatingRule( constraint.GetParentRule() );
602 
603  reportViolation( drce, (wxPoint) pos );
604  }
605  }
606 
607  if( testHoles && otherPad->FlashLayer( layer ) && pad->GetDrillSize().x )
608  {
609  constraint = m_drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, pad, otherPad, layer );
610  clearance = constraint.GetValue().Min();
611 
612  if( clearance >= 0 && otherShape->Collide( pad->GetEffectiveHoleShape(),
613  std::max( 0, clearance - m_drcEpsilon ),
614  &actual, &pos ) )
615  {
616  std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
617 
618  m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
619  constraint.GetName(),
620  MessageTextFromValue( userUnits(), clearance ),
621  MessageTextFromValue( userUnits(), actual ) );
622 
623  drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
624  drce->SetItems( pad, other );
625  drce->SetViolatingRule( constraint.GetParentRule() );
626 
627  reportViolation( drce, (wxPoint) pos );
628  }
629  }
630 
631  // Pads of the same (defined) net get a waiver on clearance tests
632  if( pad->GetNetCode() && otherPad->GetNetCode() == pad->GetNetCode() )
633  testClearance = false;
634 
635  if( otherPad->GetAttribute() == PAD_ATTRIB::NPTH && !otherPad->FlashLayer( layer ) )
636  testClearance = false;
637  }
638 
639  if( testClearance )
640  {
641  constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, pad, other, layer );
642  clearance = constraint.GetValue().Min();
643 
644  if( clearance > 0 && padShape->Collide( otherShape.get(),
645  std::max( 0, clearance - m_drcEpsilon ),
646  &actual, &pos ) )
647  {
648  std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CLEARANCE );
649 
650  m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
651  constraint.GetName(),
652  MessageTextFromValue( userUnits(), clearance ),
653  MessageTextFromValue( userUnits(), actual ) );
654 
655  drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
656  drce->SetItems( pad, other );
657  drce->SetViolatingRule( constraint.GetParentRule() );
658 
659  reportViolation( drce, (wxPoint) pos );
660  }
661  }
662 
663  return true;
664 }
665 
666 
668 {
669  const int delta = 50; // This is the number of tests between 2 calls to the progress bar
670 
671  size_t count = 0;
672 
673  for( FOOTPRINT* footprint : m_board->Footprints() )
674  count += footprint->Pads().size();
675 
676  reportAux( "Testing %d pads...", count );
677 
678  int ii = 0;
679  std::map< std::pair<BOARD_ITEM*, BOARD_ITEM*>, int> checkedPairs;
680 
681  for( FOOTPRINT* footprint : m_board->Footprints() )
682  {
683  for( PAD* pad : footprint->Pads() )
684  {
685  if( !reportProgress( ii++, count, delta ) )
686  break;
687 
688  for( PCB_LAYER_ID layer : pad->GetLayerSet().Seq() )
689  {
690  std::shared_ptr<SHAPE> padShape = DRC_ENGINE::GetShape( pad, layer );
691 
692  m_copperTree.QueryColliding( pad, layer, layer,
693  // Filter:
694  [&]( BOARD_ITEM* other ) -> bool
695  {
696  BOARD_ITEM* a = pad;
697  BOARD_ITEM* b = other;
698 
699  // store canonical order so we don't collide in both directions
700  // (a:b and b:a)
701  if( static_cast<void*>( a ) > static_cast<void*>( b ) )
702  std::swap( a, b );
703 
704  if( checkedPairs.count( { a, b } ) )
705  {
706  return false;
707  }
708  else
709  {
710  checkedPairs[ { a, b } ] = 1;
711  return true;
712  }
713  },
714  // Visitor
715  [&]( BOARD_ITEM* other ) -> bool
716  {
717  return testPadAgainstItem( pad, padShape.get(), layer, other );
718  },
720 
721  testItemAgainstZones( pad, layer );
722  }
723  }
724  }
725 }
726 
727 
729 {
730  const int delta = 50; // This is the number of tests between 2 calls to the progress bar
731 
732  SHAPE_POLY_SET buffer;
733  SHAPE_POLY_SET* boardOutline = nullptr;
734 
735  if( m_board->GetBoardPolygonOutlines( buffer ) )
736  boardOutline = &buffer;
737 
738  for( int layer_id = F_Cu; layer_id <= B_Cu; ++layer_id )
739  {
740  PCB_LAYER_ID layer = static_cast<PCB_LAYER_ID>( layer_id );
741  std::vector<SHAPE_POLY_SET> smoothed_polys;
742  smoothed_polys.resize( m_zones.size() );
743 
744  // Skip over layers not used on the current board
745  if( !m_board->IsLayerEnabled( layer ) )
746  continue;
747 
748  for( size_t ii = 0; ii < m_zones.size(); ii++ )
749  {
750  if( m_zones[ii]->IsOnLayer( layer ) )
751  m_zones[ii]->BuildSmoothedPoly( smoothed_polys[ii], layer, boardOutline );
752  }
753 
754  // iterate through all areas
755  for( size_t ia = 0; ia < m_zones.size(); ia++ )
756  {
757  if( !reportProgress( layer_id * m_zones.size() + ia, B_Cu * m_zones.size(), delta ) )
758  break;
759 
760  ZONE* zoneRef = m_zones[ia];
761 
762  if( !zoneRef->IsOnLayer( layer ) )
763  continue;
764 
765  // If we are testing a single zone, then iterate through all other zones
766  // Otherwise, we have already tested the zone combination
767  for( size_t ia2 = ia + 1; ia2 < m_zones.size(); ia2++ )
768  {
769  ZONE* zoneToTest = m_zones[ia2];
770 
771  if( zoneRef == zoneToTest )
772  continue;
773 
774  // test for same layer
775  if( !zoneToTest->IsOnLayer( layer ) )
776  continue;
777 
778  // Test for same net
779  if( zoneRef->GetNetCode() == zoneToTest->GetNetCode() && zoneRef->GetNetCode() >= 0 )
780  continue;
781 
782  // test for different priorities
783  if( zoneRef->GetPriority() != zoneToTest->GetPriority() )
784  continue;
785 
786  // rule areas may overlap at will
787  if( zoneRef->GetIsRuleArea() || zoneToTest->GetIsRuleArea() )
788  continue;
789 
790  // Examine a candidate zone: compare zoneToTest to zoneRef
791 
792  // Get clearance used in zone to zone test.
793  auto constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, zoneRef, zoneToTest,
794  layer );
795  int zone2zoneClearance = constraint.GetValue().Min();
796 
797  // test for some corners of zoneRef inside zoneToTest
798  for( auto iterator = smoothed_polys[ia].IterateWithHoles(); iterator; iterator++ )
799  {
800  VECTOR2I currentVertex = *iterator;
801  wxPoint pt( currentVertex.x, currentVertex.y );
802 
803  if( smoothed_polys[ia2].Contains( currentVertex ) )
804  {
805  std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_ZONES_INTERSECT );
806  drce->SetItems( zoneRef, zoneToTest );
807  drce->SetViolatingRule( constraint.GetParentRule() );
808 
809  reportViolation( drce, pt );
810  }
811  }
812 
813  // test for some corners of zoneToTest inside zoneRef
814  for( auto iterator = smoothed_polys[ia2].IterateWithHoles(); iterator; iterator++ )
815  {
816  VECTOR2I currentVertex = *iterator;
817  wxPoint pt( currentVertex.x, currentVertex.y );
818 
819  if( smoothed_polys[ia].Contains( currentVertex ) )
820  {
821  std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_ZONES_INTERSECT );
822  drce->SetItems( zoneToTest, zoneRef );
823  drce->SetViolatingRule( constraint.GetParentRule() );
824 
825  reportViolation( drce, pt );
826  }
827  }
828 
829  // Iterate through all the segments of refSmoothedPoly
830  std::map<wxPoint, int> conflictPoints;
831 
832  for( auto refIt = smoothed_polys[ia].IterateSegmentsWithHoles(); refIt; refIt++ )
833  {
834  // Build ref segment
835  SEG refSegment = *refIt;
836 
837  // Iterate through all the segments in smoothed_polys[ia2]
838  for( auto testIt = smoothed_polys[ia2].IterateSegmentsWithHoles(); testIt; testIt++ )
839  {
840  // Build test segment
841  SEG testSegment = *testIt;
842  wxPoint pt;
843 
844  int ax1, ay1, ax2, ay2;
845  ax1 = refSegment.A.x;
846  ay1 = refSegment.A.y;
847  ax2 = refSegment.B.x;
848  ay2 = refSegment.B.y;
849 
850  int bx1, by1, bx2, by2;
851  bx1 = testSegment.A.x;
852  by1 = testSegment.A.y;
853  bx2 = testSegment.B.x;
854  by2 = testSegment.B.y;
855 
856  int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2,
857  0,
858  ax1, ay1, ax2, ay2,
859  0,
860  zone2zoneClearance,
861  &pt.x, &pt.y );
862 
863  if( d < zone2zoneClearance )
864  {
865  if( conflictPoints.count( pt ) )
866  conflictPoints[ pt ] = std::min( conflictPoints[ pt ], d );
867  else
868  conflictPoints[ pt ] = d;
869  }
870  }
871  }
872 
873  for( const std::pair<const wxPoint, int>& conflict : conflictPoints )
874  {
875  int actual = conflict.second;
876  std::shared_ptr<DRC_ITEM> drce;
877 
878  if( actual <= 0 )
879  {
881  }
882  else
883  {
885 
886  m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
887  constraint.GetName(),
888  MessageTextFromValue( userUnits(), zone2zoneClearance ),
889  MessageTextFromValue( userUnits(), conflict.second ) );
890 
891  drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
892  }
893 
894  drce->SetItems( zoneRef, zoneToTest );
895  drce->SetViolatingRule( constraint.GetParentRule() );
896 
897  reportViolation( drce, conflict.first );
898  }
899  }
900  }
901  }
902 }
903 
904 
906 {
907  return 4;
908 }
909 
910 
912 {
914 }
915 
916 
917 namespace detail
918 {
920 }
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:750
wxString MessageTextFromValue(EDA_UNITS aUnits, int aValue, bool aAddUnitLabel, EDA_DATA_TYPE aType)
Convert a value to a string using double notation.
Definition: base_units.cpp:104
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition: typeinfo.h:100
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:101
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
Definition: drc_item.cpp:253
class FP_TEXT, text in a footprint
Definition: typeinfo.h:92
bool GetBoardPolygonOutlines(SHAPE_POLY_SET &aOutlines, OUTLINE_ERROR_HANDLER *aErrorHandler=nullptr)
Extract the board outlines and build a closed polygon from lines, arcs and circle items on edge cut l...
Definition: board.cpp:1898
ZONES & Zones()
Definition: board.h:239
const wxPoint & GetEnd() const
Definition: pcb_track.h:105
unsigned GetPriority() const
Definition: zone.h:123
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition: zone.h:734
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:80
static std::shared_ptr< SHAPE > GetShape(BOARD_ITEM *aItem, PCB_LAYER_ID aLayer)
virtual void reportViolation(std::shared_ptr< DRC_ITEM > &item, const wxPoint &aMarkerPos)
void testItemAgainstZones(BOARD_ITEM *aItem, PCB_LAYER_ID aLayer)
int GetHolePlatingThickness() const
Pad & via drills are finish size.
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:102
bool IsErrorLimitExceeded(int error_code)
class PCB_TEXT, text on a layer
Definition: typeinfo.h:91
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:97
virtual bool reportProgress(int aCount, int aSize, int aDelta)
const SHAPE_SEGMENT * GetEffectiveHoleShape() const
Return a SHAPE object representing the pad's hole.
Definition: pad.cpp:292
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Test to see if this object is on the given layer.
Definition: zone.cpp:316
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:93
class PAD, a pad in a footprint
Definition: typeinfo.h:89
T Min() const
Definition: minoptmax.h:33
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:491
static bool IsNetTie(BOARD_ITEM *aItem)
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
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:588
virtual void reportRuleStatistics()
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:165
wxString GetName() const
Definition: drc_rule.h:128
const SEG & GetSeg() const
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:95
Plated through hole pad.
static DRC_REGISTER_TEST_PROVIDER< DRC_TEST_PROVIDER_ANNULAR_WIDTH > dummy
DRC_RULE * GetParentRule() const
Definition: drc_rule.h:126
const wxSize & GetDrillSize() const
Definition: pad.h:239
like PAD_PTH, but not plated
PCB_LAYER_ID
A quick note on layer IDs:
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
bool FlashLayer(int aLayer) const
Check to see whether the pad should be flashed on the specific layer.
Definition: pad.cpp:209
LSET is a set of PCB_LAYER_IDs.
bool QueryWorstConstraint(DRC_CONSTRAINT_T aRuleId, DRC_CONSTRAINT &aConstraint)
OPT< VECTOR2I > OPT_VECTOR2I
Definition: seg.h:38
BOARD * GetBoard() const
Definition: drc_engine.h:88
virtual bool reportPhase(const wxString &aStageName)
Represent a set of closed polygons.
virtual std::set< DRC_CONSTRAINT_T > GetConstraintTypes() const override
FOOTPRINTS & Footprints()
Definition: board.h:233
bool GetReportAllTrackErrors() const
Definition: drc_engine.h:156
bool IsNetTie() const
Definition: footprint.h:234
void clear()
Remove all items from the RTree.
Definition: drc_rtree.h:120
#define _(s)
bool testPadAgainstItem(PAD *pad, SHAPE *padShape, PCB_LAYER_ID layer, BOARD_ITEM *other)
Handle a list of polygons defining a copper zone.
Definition: zone.h:57
An abstract shape on 2D plane.
Definition: shape.h:116
EDA_UNITS userUnits() const
DRC_CONSTRAINT EvalRules(DRC_CONSTRAINT_T aConstraintId, const BOARD_ITEM *a, const BOARD_ITEM *b, PCB_LAYER_ID aLayer, REPORTER *aReporter=nullptr)
Definition: drc_engine.cpp:762
class PCB_DIMENSION_BASE: abstract dimension meta-type
Definition: typeinfo.h:99
bool testTrackAgainstItem(PCB_TRACK *track, SHAPE *trackShape, PCB_LAYER_ID layer, BOARD_ITEM *other)
Definition: seg.h:40
virtual const wxString GetName() const override
int forEachGeometryItem(const std::vector< KICAD_T > &aTypes, LSET aLayers, const std::function< bool(BOARD_ITEM *)> &aFunc)
const MINOPTMAX< int > & GetValue() const
Definition: drc_rule.h:122
wxPoint GetPosition() const override
Definition: pad.h:174
PAD_ATTRIB GetAttribute() const
Definition: pad.h:368
DRC_ENGINE * m_drcEngine
VECTOR2I A
Definition: seg.h:48
Handle the component boundary box.
Definition: eda_rect.h:42
The common library.
void Insert(BOARD_ITEM *aItem, PCB_LAYER_ID aLayer, int aWorstClearance=0)
Insert an item into the tree on a particular layer with an optional worst clearance.
Definition: drc_rtree.h:86
bool Intersects(const EDA_RECT &aRect) const
Test for a common area between rectangles.
Definition: eda_rect.cpp:150
std::map< ZONE *, std::unique_ptr< DRC_RTREE > > m_CopperZoneRTrees
Definition: board.h:1088
bool IsCopperLayer(LAYER_NUM aLayerId)
Tests whether a layer is a copper layer.
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER) const
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: board_item.cpp:168
virtual bool IsConnected() const
Returns information if the object is derived from BOARD_CONNECTED_ITEM.
Definition: board_item.h:134
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition: typeinfo.h:103
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
virtual const EDA_RECT GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition: eda_item.cpp:75
virtual const wxString GetDescription() const override
Definition: pad.h:57
Implement an R-tree for fast spatial and layer indexing of connectable items.
Definition: drc_rtree.h:44
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:166
int GetWidth() const
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:90
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:171
TRACKS & Tracks()
Definition: board.h:230
virtual void reportAux(wxString fmt,...)
const wxPoint & GetStart() const
Definition: pcb_track.h:108
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:113
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:165
VECTOR2I B
Definition: seg.h:49