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  FOOTPRINT* padParent = static_cast<FOOTPRINT*>( pad->GetParent() );
504  bool isNetTie = padParent->IsNetTie();
505 
506  // Graphic items are allowed to act as net-ties within their own footprint
507  if( isNetTie
508  && ( other->Type() == PCB_FP_SHAPE_T || other->Type() == PCB_PAD_T )
509  && other->GetParent() == padParent )
510  {
511  testClearance = false;
512  }
513 
514  if( pad->GetAttribute() == PAD_ATTRIB_NPTH && !pad->FlashLayer( layer ) )
515  testClearance = false;
516 
517  if( !IsCopperLayer( layer ) )
518  testClearance = false;
519 
520  // Track clearances are tested in testTrackClearances()
521  if( dynamic_cast<TRACK*>( other) )
522  testClearance = false;
523 
524  if( !testClearance && !testShorting && !testHoles )
525  return false;
526 
527  std::shared_ptr<SHAPE> otherShape = DRC_ENGINE::GetShape( other, layer );
528  DRC_CONSTRAINT constraint;
529  int clearance;
530  int actual;
531  VECTOR2I pos;
532 
533  if( other->Type() == PCB_PAD_T )
534  {
535  PAD* otherPad = static_cast<PAD*>( other );
536 
537  // If pads are equivalent (ie: from the same footprint with the same pad number)...
538  if( pad->SameLogicalPadAs( otherPad ) )
539  {
540  // ...and have nets, then they must be the same net
541  if( pad->GetNetCode() && otherPad->GetNetCode()
542  && pad->GetNetCode() != otherPad->GetNetCode()
543  && testShorting )
544  {
545  std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_SHORTING_ITEMS );
546 
547  m_msg.Printf( _( "(nets %s and %s)" ),
548  pad->GetNetname(),
549  otherPad->GetNetname() );
550 
551  drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
552  drce->SetItems( pad, otherPad );
553 
554  reportViolation( drce, otherPad->GetPosition() );
555  }
556 
557  return true;
558  }
559 
560  if( testHoles && pad->FlashLayer( layer ) && otherPad->GetDrillSize().x )
561  {
562  constraint = m_drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, pad, otherPad, layer );
563  clearance = constraint.GetValue().Min();
564 
565  if( clearance >= 0 && padShape->Collide( otherPad->GetEffectiveHoleShape(),
566  std::max( 0, clearance - m_drcEpsilon ),
567  &actual, &pos ) )
568  {
569  std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
570 
571  m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
572  constraint.GetName(),
573  MessageTextFromValue( userUnits(), clearance ),
574  MessageTextFromValue( userUnits(), actual ) );
575 
576  drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
577  drce->SetItems( pad, other );
578  drce->SetViolatingRule( constraint.GetParentRule() );
579 
580  reportViolation( drce, (wxPoint) pos );
581  }
582  }
583 
584  if( testHoles && otherPad->FlashLayer( layer ) && pad->GetDrillSize().x )
585  {
586  constraint = m_drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, pad, otherPad, layer );
587  clearance = constraint.GetValue().Min();
588 
589  if( clearance >= 0 && otherShape->Collide( pad->GetEffectiveHoleShape(),
590  std::max( 0, clearance - m_drcEpsilon ),
591  &actual, &pos ) )
592  {
593  std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
594 
595  m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
596  constraint.GetName(),
597  MessageTextFromValue( userUnits(), clearance ),
598  MessageTextFromValue( userUnits(), actual ) );
599 
600  drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
601  drce->SetItems( pad, other );
602  drce->SetViolatingRule( constraint.GetParentRule() );
603 
604  reportViolation( drce, (wxPoint) pos );
605  }
606  }
607 
608  // Pads of the same (defined) net get a waiver on clearance tests
609  if( pad->GetNetCode() && otherPad->GetNetCode() == pad->GetNetCode() )
610  testClearance = false;
611 
612  if( otherPad->GetAttribute() == PAD_ATTRIB_NPTH && !otherPad->FlashLayer( layer ) )
613  testClearance = false;
614  }
615 
616  if( testClearance )
617  {
618  constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, pad, other, layer );
619  clearance = constraint.GetValue().Min();
620 
621  if( clearance > 0 && padShape->Collide( otherShape.get(),
622  std::max( 0, clearance - m_drcEpsilon ),
623  &actual, &pos ) )
624  {
625  std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CLEARANCE );
626 
627  m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
628  constraint.GetName(),
629  MessageTextFromValue( userUnits(), clearance ),
630  MessageTextFromValue( userUnits(), actual ) );
631 
632  drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
633  drce->SetItems( pad, other );
634  drce->SetViolatingRule( constraint.GetParentRule() );
635 
636  reportViolation( drce, (wxPoint) pos );
637  }
638  }
639 
640  return true;
641 }
642 
643 
645 {
646  const int delta = 50; // This is the number of tests between 2 calls to the progress bar
647 
648  size_t count = 0;
649 
650  for( FOOTPRINT* footprint : m_board->Footprints() )
651  count += footprint->Pads().size();
652 
653  reportAux( "Testing %d pads...", count );
654 
655  int ii = 0;
656  std::map< std::pair<BOARD_ITEM*, BOARD_ITEM*>, int> checkedPairs;
657 
658  for( FOOTPRINT* footprint : m_board->Footprints() )
659  {
660  for( PAD* pad : footprint->Pads() )
661  {
662  if( !reportProgress( ii++, count, delta ) )
663  break;
664 
665  for( PCB_LAYER_ID layer : pad->GetLayerSet().Seq() )
666  {
667  std::shared_ptr<SHAPE> padShape = DRC_ENGINE::GetShape( pad, layer );
668 
669  m_copperTree.QueryColliding( pad, layer, layer,
670  // Filter:
671  [&]( BOARD_ITEM* other ) -> bool
672  {
673  BOARD_ITEM* a = pad;
674  BOARD_ITEM* b = other;
675 
676  // store canonical order so we don't collide in both directions
677  // (a:b and b:a)
678  if( static_cast<void*>( a ) > static_cast<void*>( b ) )
679  std::swap( a, b );
680 
681  if( checkedPairs.count( { a, b } ) )
682  {
683  return false;
684  }
685  else
686  {
687  checkedPairs[ { a, b } ] = 1;
688  return true;
689  }
690  },
691  // Visitor
692  [&]( BOARD_ITEM* other ) -> bool
693  {
694  return testPadAgainstItem( pad, padShape.get(), layer, other );
695  },
697 
698  testItemAgainstZones( pad, layer );
699  }
700  }
701  }
702 }
703 
704 
706 {
707  const int delta = 50; // This is the number of tests between 2 calls to the progress bar
708 
709  SHAPE_POLY_SET buffer;
710  SHAPE_POLY_SET* boardOutline = nullptr;
711 
712  if( m_board->GetBoardPolygonOutlines( buffer ) )
713  boardOutline = &buffer;
714 
715  for( int layer_id = F_Cu; layer_id <= B_Cu; ++layer_id )
716  {
717  PCB_LAYER_ID layer = static_cast<PCB_LAYER_ID>( layer_id );
718  std::vector<SHAPE_POLY_SET> smoothed_polys;
719  smoothed_polys.resize( m_zones.size() );
720 
721  // Skip over layers not used on the current board
722  if( !m_board->IsLayerEnabled( layer ) )
723  continue;
724 
725  for( size_t ii = 0; ii < m_zones.size(); ii++ )
726  {
727  if( m_zones[ii]->IsOnLayer( layer ) )
728  m_zones[ii]->BuildSmoothedPoly( smoothed_polys[ii], layer, boardOutline );
729  }
730 
731  // iterate through all areas
732  for( size_t ia = 0; ia < m_zones.size(); ia++ )
733  {
734  if( !reportProgress( layer_id * m_zones.size() + ia, B_Cu * m_zones.size(), delta ) )
735  break;
736 
737  ZONE* zoneRef = m_zones[ia];
738 
739  if( !zoneRef->IsOnLayer( layer ) )
740  continue;
741 
742  // If we are testing a single zone, then iterate through all other zones
743  // Otherwise, we have already tested the zone combination
744  for( size_t ia2 = ia + 1; ia2 < m_zones.size(); ia2++ )
745  {
746  ZONE* zoneToTest = m_zones[ia2];
747 
748  if( zoneRef == zoneToTest )
749  continue;
750 
751  // test for same layer
752  if( !zoneToTest->IsOnLayer( layer ) )
753  continue;
754 
755  // Test for same net
756  if( zoneRef->GetNetCode() == zoneToTest->GetNetCode() && zoneRef->GetNetCode() >= 0 )
757  continue;
758 
759  // test for different priorities
760  if( zoneRef->GetPriority() != zoneToTest->GetPriority() )
761  continue;
762 
763  // rule areas may overlap at will
764  if( zoneRef->GetIsRuleArea() || zoneToTest->GetIsRuleArea() )
765  continue;
766 
767  // Examine a candidate zone: compare zoneToTest to zoneRef
768 
769  // Get clearance used in zone to zone test.
770  auto constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, zoneRef, zoneToTest,
771  layer );
772  int zone2zoneClearance = constraint.GetValue().Min();
773 
774  // test for some corners of zoneRef inside zoneToTest
775  for( auto iterator = smoothed_polys[ia].IterateWithHoles(); iterator; iterator++ )
776  {
777  VECTOR2I currentVertex = *iterator;
778  wxPoint pt( currentVertex.x, currentVertex.y );
779 
780  if( smoothed_polys[ia2].Contains( currentVertex ) )
781  {
782  std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_ZONES_INTERSECT );
783  drce->SetItems( zoneRef, zoneToTest );
784  drce->SetViolatingRule( constraint.GetParentRule() );
785 
786  reportViolation( drce, pt );
787  }
788  }
789 
790  // test for some corners of zoneToTest inside zoneRef
791  for( auto iterator = smoothed_polys[ia2].IterateWithHoles(); iterator; iterator++ )
792  {
793  VECTOR2I currentVertex = *iterator;
794  wxPoint pt( currentVertex.x, currentVertex.y );
795 
796  if( smoothed_polys[ia].Contains( currentVertex ) )
797  {
798  std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_ZONES_INTERSECT );
799  drce->SetItems( zoneToTest, zoneRef );
800  drce->SetViolatingRule( constraint.GetParentRule() );
801 
802  reportViolation( drce, pt );
803  }
804  }
805 
806  // Iterate through all the segments of refSmoothedPoly
807  std::map<wxPoint, int> conflictPoints;
808 
809  for( auto refIt = smoothed_polys[ia].IterateSegmentsWithHoles(); refIt; refIt++ )
810  {
811  // Build ref segment
812  SEG refSegment = *refIt;
813 
814  // Iterate through all the segments in smoothed_polys[ia2]
815  for( auto testIt = smoothed_polys[ia2].IterateSegmentsWithHoles(); testIt; testIt++ )
816  {
817  // Build test segment
818  SEG testSegment = *testIt;
819  wxPoint pt;
820 
821  int ax1, ay1, ax2, ay2;
822  ax1 = refSegment.A.x;
823  ay1 = refSegment.A.y;
824  ax2 = refSegment.B.x;
825  ay2 = refSegment.B.y;
826 
827  int bx1, by1, bx2, by2;
828  bx1 = testSegment.A.x;
829  by1 = testSegment.A.y;
830  bx2 = testSegment.B.x;
831  by2 = testSegment.B.y;
832 
833  int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2,
834  0,
835  ax1, ay1, ax2, ay2,
836  0,
837  zone2zoneClearance,
838  &pt.x, &pt.y );
839 
840  if( d < zone2zoneClearance )
841  {
842  if( conflictPoints.count( pt ) )
843  conflictPoints[ pt ] = std::min( conflictPoints[ pt ], d );
844  else
845  conflictPoints[ pt ] = d;
846  }
847  }
848  }
849 
850  for( const std::pair<const wxPoint, int>& conflict : conflictPoints )
851  {
852  int actual = conflict.second;
853  std::shared_ptr<DRC_ITEM> drce;
854 
855  if( actual <= 0 )
856  {
858  }
859  else
860  {
862 
863  m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
864  constraint.GetName(),
865  MessageTextFromValue( userUnits(), zone2zoneClearance ),
866  MessageTextFromValue( userUnits(), conflict.second ) );
867 
868  drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
869  }
870 
871  drce->SetItems( zoneRef, zoneToTest );
872  drce->SetViolatingRule( constraint.GetParentRule() );
873 
874  reportViolation( drce, conflict.first );
875  }
876  }
877  }
878  }
879 }
880 
881 
883 {
884  return 4;
885 }
886 
887 
889 {
891 }
892 
893 
894 namespace detail
895 {
897 }
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:125
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:1862
ZONES & Zones()
Definition: board.h:309
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: track.cpp:376
unsigned GetPriority() const
Function GetPriority.
Definition: zone.h:124
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition: zone.h:755
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)
bool Contains(PCB_LAYER_ID aLayer)
See if the layer set contains a PCB layer.
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: pcbnew/pad.cpp:286
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:313
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.h:591
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
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:85
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:513
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
PAD_ATTR_T GetAttribute() const
Definition: pad.h:363
DRC_RULE * GetParentRule() const
Definition: drc_rule.h:125
const wxSize & GetDrillSize() const
Definition: pad.h:242
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: pcbnew/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
int GetDrill() const
Function GetDrill returns the local drill setting for this VIA.
Definition: track.h:481
FOOTPRINTS & Footprints()
Definition: board.h:303
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)
ZONE handles 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:736
class DIMENSION_BASE: abstract dimension meta-type
Definition: typeinfo.h:99
FOOTPRINT * GetParent() const
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
DRC_ENGINE * m_drcEngine
VECTOR2I A
Definition: seg.h:49
Plated through hole pad.
Definition: pad_shapes.h:80
Handle the component boundary box.
Definition: eda_rect.h:42
The common library.
bool SameLogicalPadAs(const PAD *other) const
Before we had custom pad shapes it was common to have multiple overlapping pads to represent a more c...
Definition: pad.h:151
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:1154
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:89
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
wxPoint GetPosition() const override
Definition: track.h:411
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:300
virtual void reportAux(wxString fmt,...)
Definition: track.h:83
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:162
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