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