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 #include <geometry/shape_null.h>
35 
36 #include <drc/drc_engine.h>
37 #include <drc/drc_rtree.h>
38 #include <drc/drc_item.h>
39 #include <drc/drc_rule.h>
41 #include <dimension.h>
42 
43 /*
44  Copper clearance test. Checks all copper items (pads, vias, tracks, drawings, zones) for their electrical clearance.
45  Errors generated:
46  - DRCE_CLEARANCE
47  - DRCE_TRACKS_CROSSING
48  - DRCE_ZONES_INTERSECT
49  - DRCE_SHORTING_ITEMS
50 */
51 
53 {
54 public:
57  m_drcEpsilon( 0 )
58  {
59  }
60 
62  {
63  }
64 
65  virtual bool Run() override;
66 
67  virtual const wxString GetName() const override
68  {
69  return "clearance";
70  };
71 
72  virtual const wxString GetDescription() const override
73  {
74  return "Tests copper item clearance";
75  }
76 
77  virtual std::set<DRC_CONSTRAINT_TYPE_T> GetConstraintTypes() const override;
78 
79  int GetNumPhases() const override;
80 
81 private:
82  bool testTrackAgainstItem( TRACK* track, SHAPE* trackShape, PCB_LAYER_ID layer,
83  BOARD_ITEM* other );
84 
85  void testTrackClearances();
86 
87  bool testPadAgainstItem( PAD* pad, SHAPE* padShape, PCB_LAYER_ID layer, BOARD_ITEM* other );
88 
89  void testPadClearances();
90 
91  void testZones();
92 
93  void testItemAgainstZones( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer );
94 
95 private:
98 
99  std::vector<ZONE*> m_zones;
100  std::map<ZONE*, std::unique_ptr<DRC_RTREE>> m_zoneTrees;
101 
102 };
103 
104 
106 {
108  DRC_CONSTRAINT worstClearanceConstraint;
109 
110  if( m_drcEngine->QueryWorstConstraint( CLEARANCE_CONSTRAINT, worstClearanceConstraint ) )
111  {
112  m_largestClearance = worstClearanceConstraint.GetValue().Min();
113  }
114  else
115  {
116  reportAux( "No Clearance constraints found..." );
117  return false;
118  }
119 
121 
122  m_zones.clear();
123 
124  for( ZONE* zone : m_board->Zones() )
125  {
126  if( !zone->GetIsRuleArea() )
127  m_zones.push_back( zone );
128  }
129 
130  for( FOOTPRINT* footprint : m_board->Footprints() )
131  {
132  for( ZONE* zone : footprint->Zones() )
133  {
134  if( !zone->GetIsRuleArea() )
135  m_zones.push_back( zone );
136  }
137  }
138 
139  reportAux( "Worst clearance : %d nm", m_largestClearance );
140 
141  // This is the number of tests between 2 calls to the progress bar
142  size_t delta = 50;
143  size_t count = 0;
144  size_t ii = 0;
145 
147 
148  auto countItems =
149  [&]( BOARD_ITEM* item ) -> bool
150  {
151  ++count;
152  return true;
153  };
154 
155  auto addToCopperTree =
156  [&]( BOARD_ITEM* item ) -> bool
157  {
158  if( !reportProgress( ii++, count, delta ) )
159  return false;
160 
161  item->ClearFlags( SKIP_STRUCT );
162 
163  if( item->Type() == PCB_FP_TEXT_T && !static_cast<FP_TEXT*>( item )->IsVisible() )
164  return true;
165 
167  return true;
168  };
169 
170  if( !reportPhase( _( "Gathering copper items..." ) ) )
171  return false;
172 
173  static const std::vector<KICAD_T> itemTypes = {
177  };
178 
179  forEachGeometryItem( itemTypes, LSET::AllCuMask(), countItems );
180  forEachGeometryItem( itemTypes, LSET::AllCuMask(), addToCopperTree );
181 
182  if( !reportPhase( _( "Tessellating copper zones..." ) ) )
183  return false;
184 
185  delta = 5;
186  ii = 0;
187  m_zoneTrees.clear();
188 
189  for( ZONE* zone : m_zones )
190  {
191  if( !reportProgress( ii++, m_zones.size(), delta ) )
192  break;
193 
194  zone->CacheBoundingBox();
195  m_zoneTrees[ zone ] = std::make_unique<DRC_RTREE>();
196 
197  for( int layer : zone->GetLayerSet().Seq() )
198  {
199  if( IsCopperLayer( layer ) )
200  m_zoneTrees[ zone ]->Insert( zone, layer );
201  }
202 
203  }
204 
205  reportAux( "Testing %d copper items and %d zones...", count, m_zones.size() );
206 
207  if( !reportPhase( _( "Checking track & via clearances..." ) ) )
208  return false;
209 
211 
212  if( !reportPhase( _( "Checking pad clearances..." ) ) )
213  return false;
214 
216 
217  if( !reportPhase( _( "Checking copper zone clearances..." ) ) )
218  return false;
219 
220  testZones();
221 
223 
224  return true;
225 }
226 
227 
228 static std::shared_ptr<SHAPE> getShape( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer )
229 {
230  if( aItem->Type() == PCB_PAD_T && !static_cast<PAD*>( aItem )->FlashLayer( aLayer ) )
231  {
232  PAD* aPad = static_cast<PAD*>( aItem );
233 
234  if( aPad->GetAttribute() == PAD_ATTRIB_PTH )
235  {
237 
238  // Note: drill size represents finish size, which means the actual holes size is the
239  // plating thickness larger.
240  auto hole = static_cast<SHAPE_SEGMENT*>( aPad->GetEffectiveHoleShape()->Clone() );
241  hole->SetWidth( hole->GetWidth() + bds.GetHolePlatingThickness() );
242  return std::make_shared<SHAPE_SEGMENT>( *hole );
243  }
244 
245  return std::make_shared<SHAPE_NULL>();
246  }
247 
248  return aItem->GetEffectiveShape( aLayer );
249 }
250 
251 
252 static bool isNetTie( BOARD_ITEM* aItem )
253 {
254  if( aItem->GetParent() && aItem->GetParent()->Type() == PCB_FOOTPRINT_T )
255  return static_cast<FOOTPRINT*>( aItem->GetParent() )->IsNetTie();
256 
257  return false;
258 }
259 
260 
262  PCB_LAYER_ID layer,
263  BOARD_ITEM* other )
264 {
266  return false;
267 
268  auto constraint = m_drcEngine->EvalRulesForItems( CLEARANCE_CONSTRAINT, track, other,
269  layer );
270  int minClearance = constraint.GetValue().Min();
271  int actual;
272  VECTOR2I pos;
273 
274  accountCheck( constraint );
275 
276  // Special processing for track:track intersections
277  if( track->Type() == PCB_TRACE_T && other->Type() == PCB_TRACE_T )
278  {
279  SEG trackSeg( track->GetStart(), track->GetEnd() );
280  SEG otherSeg( track->GetStart(), track->GetEnd() );
281 
282  if( OPT_VECTOR2I intersection = trackSeg.Intersect( otherSeg ) )
283  {
284  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TRACKS_CROSSING );
285  drcItem->SetItems( track, other );
286  drcItem->SetViolatingRule( constraint.GetParentRule() );
287 
288  reportViolation( drcItem, (wxPoint) intersection.get() );
289  return true;
290  }
291  }
292 
293  std::shared_ptr<SHAPE> otherShape = getShape( other, layer );
294 
295  if( trackShape->Collide( otherShape.get(), minClearance - m_drcEpsilon, &actual, &pos ) )
296  {
297  std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CLEARANCE );
298 
299  m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
300  constraint.GetName(),
301  MessageTextFromValue( userUnits(), minClearance ),
302  MessageTextFromValue( userUnits(), actual ) );
303 
304  drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
305  drce->SetItems( track, other );
306  drce->SetViolatingRule( constraint.GetParentRule() );
307 
308  reportViolation( drce, (wxPoint) pos );
309 
311  return false;
312  }
313 
314  return true;
315 }
316 
317 
319  PCB_LAYER_ID aLayer )
320 {
321  for( ZONE* zone : m_zones )
322  {
324  break;
325 
326  if( !zone->GetLayerSet().test( aLayer ) )
327  continue;
328 
329  if( zone->GetNetCode() && aItem->IsConnected() )
330  {
331  if( zone->GetNetCode() == static_cast<BOARD_CONNECTED_ITEM*>( aItem )->GetNetCode() )
332  continue;
333  }
334 
335  if( aItem->GetBoundingBox().Intersects( zone->GetCachedBoundingBox() ) )
336  {
337  auto constraint = m_drcEngine->EvalRulesForItems( CLEARANCE_CONSTRAINT, aItem, zone,
338  aLayer );
339  int clearance = constraint.GetValue().Min();
340  int actual;
341  VECTOR2I pos;
342  DRC_RTREE* zoneTree = m_zoneTrees[ zone ].get();
343 
344  EDA_RECT itemBBox = aItem->GetBoundingBox();
345  std::shared_ptr<SHAPE> itemShape = aItem->GetEffectiveShape( aLayer );
346 
347  if( aItem->Type() == PCB_PAD_T )
348  {
349  PAD* pad = static_cast<PAD*>( aItem );
350 
351  if( !pad->FlashLayer( aLayer ) )
352  {
353  if( pad->GetDrillSize().x == 0 && pad->GetDrillSize().y == 0 )
354  continue;
355 
356  const SHAPE_SEGMENT* hole = pad->GetEffectiveHoleShape();
357  int size = hole->GetWidth();
358 
359  // Note: drill size represents finish size, which means the actual hole
360  // size is the plating thickness larger.
361  if( pad->GetAttribute() == PAD_ATTRIB_PTH )
363 
364  itemShape = std::make_shared<SHAPE_SEGMENT>( hole->GetSeg(), size );
365  }
366  }
367 
368  if( zoneTree->QueryColliding( itemBBox, itemShape.get(), aLayer,
369  clearance - m_drcEpsilon,
370  &actual, &pos ) )
371  {
372  std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CLEARANCE );
373 
374  m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
375  constraint.GetName(),
376  MessageTextFromValue( userUnits(), clearance ),
377  MessageTextFromValue( userUnits(), actual ) );
378 
379  drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
380  drce->SetItems( aItem, zone );
381  drce->SetViolatingRule( constraint.GetParentRule() );
382 
383  reportViolation( drce, (wxPoint) pos );
384  }
385  }
386  }
387 }
388 
389 
391 {
392  // This is the number of tests between 2 calls to the progress bar
393  const int delta = 25;
394  int ii = 0;
395 
396  reportAux( "Testing %d tracks & vias...", m_board->Tracks().size() );
397 
398  std::map< std::pair<BOARD_ITEM*, BOARD_ITEM*>, int> checkedPairs;
399 
400  for( TRACK* track : m_board->Tracks() )
401  {
402  if( !reportProgress( ii++, m_board->Tracks().size(), delta ) )
403  break;
404 
405  for( PCB_LAYER_ID layer : track->GetLayerSet().Seq() )
406  {
407  std::shared_ptr<SHAPE> trackShape = track->GetEffectiveShape( layer );
408 
409  m_copperTree.QueryColliding( track, layer, layer,
410  // Filter:
411  [&]( BOARD_ITEM* other ) -> bool
412  {
413  if( other->HasFlag( SKIP_STRUCT ) )
414  return false;
415 
416  // It would really be better to know what particular nets a nettie
417  // should allow, but for now it is what it is.
418  if( isNetTie( other ) )
419  return false;
420 
421  auto otherCItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( other );
422 
423  if( otherCItem && otherCItem->GetNetCode() == track->GetNetCode() )
424  return false;
425 
426  BOARD_ITEM* a = track;
427  BOARD_ITEM* b = other;
428 
429  // store canonical order so we don't collide in both directions
430  // (a:b and b:a)
431  if( static_cast<void*>( a ) > static_cast<void*>( b ) )
432  std::swap( a, b );
433 
434  if( checkedPairs.count( { a, b } ) )
435  {
436  return false;
437  }
438  else
439  {
440  checkedPairs[ { a, b } ] = 1;
441  return true;
442  }
443  },
444  // Visitor:
445  [&]( BOARD_ITEM* other ) -> bool
446  {
447  return testTrackAgainstItem( track, trackShape.get(), layer, other );
448  },
450 
451  testItemAgainstZones( track, layer );
452  }
453 
454  track->SetFlags( SKIP_STRUCT );
455  }
456 }
457 
458 
460  PCB_LAYER_ID layer,
461  BOARD_ITEM* other )
462 {
463  bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE );
464  bool testShorting = !m_drcEngine->IsErrorLimitExceeded( DRCE_SHORTING_ITEMS );
466 
467  // Graphic items are allowed to act as net-ties within their own footprint
468  if( other->Type() == PCB_FP_SHAPE_T && pad->GetParent() == other->GetParent() )
469  testClearance = false;
470 
471  if( !testClearance && !testShorting && !testHoles )
472  return false;
473 
474  std::shared_ptr<SHAPE> otherShape = getShape( other, layer );
475  DRC_CONSTRAINT constraint;
476  int clearance;
477  int actual;
478  VECTOR2I pos;
479 
480  if( other->Type() == PCB_PAD_T )
481  {
482  auto otherPad = static_cast<PAD*>( other );
483 
484  // If pads are equivalent (ie: from the same footprint with the same pad number)...
485  if( pad->SameLogicalPadAs( otherPad ) )
486  {
487  // ...and have nets, then they must be the same net
488  if( pad->GetNetCode() && otherPad->GetNetCode()
489  && pad->GetNetCode() != otherPad->GetNetCode()
490  && testShorting )
491  {
492  std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_SHORTING_ITEMS );
493 
494  m_msg.Printf( _( "(nets %s and %s)" ),
495  pad->GetNetname(),
496  otherPad->GetNetname() );
497 
498  drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
499  drce->SetItems( pad, otherPad );
500 
501  reportViolation( drce, otherPad->GetPosition() );
502  }
503 
504  return true;
505  }
506 
507  if( testHoles )
508  {
509  if( ( pad->FlashLayer( layer ) && otherPad->GetDrillSize().x )
510  || ( pad->GetDrillSize().x && otherPad->FlashLayer( layer ) ) )
511  {
513  otherPad );
514  clearance = constraint.GetValue().Min();
515 
516  accountCheck( constraint.GetParentRule() );
517 
518  if( padShape->Collide( otherShape.get(), clearance - m_drcEpsilon, &actual, &pos ) )
519  {
520  std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
521 
522  m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
523  constraint.GetName(),
524  MessageTextFromValue( userUnits(), clearance ),
525  MessageTextFromValue( userUnits(), actual ) );
526 
527  drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
528  drce->SetItems( pad, other );
529  drce->SetViolatingRule( constraint.GetParentRule() );
530 
531  reportViolation( drce, (wxPoint) pos );
532  }
533  }
534  }
535 
536  // Pads of the same (defined) net get a waiver on clearance tests
537  if( pad->GetNetCode() && otherPad->GetNetCode() == pad->GetNetCode() )
538  testClearance = false;
539  }
540 
541  if( testClearance )
542  {
543  constraint = m_drcEngine->EvalRulesForItems( CLEARANCE_CONSTRAINT, pad, other, layer );
544  clearance = constraint.GetValue().Min();
545 
546  accountCheck( constraint );
547 
548  if( padShape->Collide( otherShape.get(), clearance - m_drcEpsilon, &actual, &pos ) )
549  {
550  std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CLEARANCE );
551 
552  m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
553  constraint.GetName(),
554  MessageTextFromValue( userUnits(), clearance ),
555  MessageTextFromValue( userUnits(), actual ) );
556 
557  drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
558  drce->SetItems( pad, other );
559  drce->SetViolatingRule( constraint.GetParentRule() );
560 
561  reportViolation( drce, (wxPoint) pos );
562  }
563  }
564 
565  return true;
566 }
567 
568 
570 {
571  const int delta = 25; // This is the number of tests between 2 calls to the progress bar
572 
573  size_t count = 0;
574 
575  for( FOOTPRINT* footprint : m_board->Footprints() )
576  count += footprint->Pads().size();
577 
578  reportAux( "Testing %d pads...", count );
579 
580  int ii = 0;
581  std::map< std::pair<BOARD_ITEM*, BOARD_ITEM*>, int> checkedPairs;
582 
583  for( FOOTPRINT* footprint : m_board->Footprints() )
584  {
585  for( PAD* pad : footprint->Pads() )
586  {
587  if( !reportProgress( ii++, count, delta ) )
588  break;
589 
590  for( PCB_LAYER_ID layer : pad->GetLayerSet().Seq() )
591  {
592  std::shared_ptr<SHAPE> padShape = getShape( pad, layer );
593 
594  m_copperTree.QueryColliding( pad, layer, layer,
595  // Filter:
596  [&]( BOARD_ITEM* other ) -> bool
597  {
598  if( other->HasFlag( SKIP_STRUCT ) )
599  return false;
600 
601  BOARD_ITEM* a = pad;
602  BOARD_ITEM* b = other;
603 
604  // store canonical order so we don't collide in both directions
605  // (a:b and b:a)
606  if( static_cast<void*>( a ) > static_cast<void*>( b ) )
607  std::swap( a, b );
608 
609  if( checkedPairs.count( { a, b } ) )
610  {
611  return false;
612  }
613  else
614  {
615  checkedPairs[ { a, b } ] = 1;
616  return true;
617  }
618  },
619  // Visitor
620  [&]( BOARD_ITEM* other ) -> bool
621  {
622  return testPadAgainstItem( pad, padShape.get(), layer, other );
623  },
625 
626  testItemAgainstZones( pad, layer );
627  }
628 
629  pad->SetFlags( SKIP_STRUCT );
630  }
631  }
632 }
633 
634 
636 {
637  const int delta = 50; // This is the number of tests between 2 calls to the progress bar
638 
639  SHAPE_POLY_SET buffer;
640  SHAPE_POLY_SET* boardOutline = nullptr;
641 
642  if( m_board->GetBoardPolygonOutlines( buffer ) )
643  boardOutline = &buffer;
644 
645  for( int layer_id = F_Cu; layer_id <= B_Cu; ++layer_id )
646  {
647  PCB_LAYER_ID layer = static_cast<PCB_LAYER_ID>( layer_id );
648  std::vector<SHAPE_POLY_SET> smoothed_polys;
649  smoothed_polys.resize( m_zones.size() );
650 
651  // Skip over layers not used on the current board
652  if( !m_board->IsLayerEnabled( layer ) )
653  continue;
654 
655  for( size_t ii = 0; ii < m_zones.size(); ii++ )
656  {
657  if( m_zones[ii]->IsOnLayer( layer ) )
658  m_zones[ii]->BuildSmoothedPoly( smoothed_polys[ii], layer, boardOutline );
659  }
660 
661  // iterate through all areas
662  for( size_t ia = 0; ia < m_zones.size(); ia++ )
663  {
664  if( !reportProgress( layer_id * m_zones.size() + ia, B_Cu * m_zones.size(), delta ) )
665  break;
666 
667  ZONE* zoneRef = m_zones[ia];
668 
669  if( !zoneRef->IsOnLayer( layer ) )
670  continue;
671 
672  // If we are testing a single zone, then iterate through all other zones
673  // Otherwise, we have already tested the zone combination
674  for( size_t ia2 = ia + 1; ia2 < m_zones.size(); ia2++ )
675  {
676  ZONE* zoneToTest = m_zones[ia2];
677 
678  if( zoneRef == zoneToTest )
679  continue;
680 
681  // test for same layer
682  if( !zoneToTest->IsOnLayer( layer ) )
683  continue;
684 
685  // Test for same net
686  if( zoneRef->GetNetCode() == zoneToTest->GetNetCode() && zoneRef->GetNetCode() >= 0 )
687  continue;
688 
689  // test for different priorities
690  if( zoneRef->GetPriority() != zoneToTest->GetPriority() )
691  continue;
692 
693  // test for different types
694  if( zoneRef->GetIsRuleArea() != zoneToTest->GetIsRuleArea() )
695  continue;
696 
697  // Examine a candidate zone: compare zoneToTest to zoneRef
698 
699  // Get clearance used in zone to zone test.
700  auto constraint = m_drcEngine->EvalRulesForItems( CLEARANCE_CONSTRAINT, zoneRef,
701  zoneToTest );
702  int zone2zoneClearance = constraint.GetValue().Min();
703 
704  accountCheck( constraint );
705 
706  // Keepout areas have no clearance, so set zone2zoneClearance to 1
707  // ( zone2zoneClearance = 0 can create problems in test functions)
708  if( zoneRef->GetIsRuleArea() ) // fixme: really?
709  zone2zoneClearance = 1;
710 
711  // test for some corners of zoneRef inside zoneToTest
712  for( auto iterator = smoothed_polys[ia].IterateWithHoles(); iterator; iterator++ )
713  {
714  VECTOR2I currentVertex = *iterator;
715  wxPoint pt( currentVertex.x, currentVertex.y );
716 
717  if( smoothed_polys[ia2].Contains( currentVertex ) )
718  {
719  std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_ZONES_INTERSECT );
720  drce->SetItems( zoneRef, zoneToTest );
721  drce->SetViolatingRule( constraint.GetParentRule() );
722 
723  reportViolation( drce, pt );
724  }
725  }
726 
727  // test for some corners of zoneToTest inside zoneRef
728  for( auto iterator = smoothed_polys[ia2].IterateWithHoles(); iterator; iterator++ )
729  {
730  VECTOR2I currentVertex = *iterator;
731  wxPoint pt( currentVertex.x, currentVertex.y );
732 
733  if( smoothed_polys[ia].Contains( currentVertex ) )
734  {
735  std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_ZONES_INTERSECT );
736  drce->SetItems( zoneToTest, zoneRef );
737  drce->SetViolatingRule( constraint.GetParentRule() );
738 
739  reportViolation( drce, pt );
740  }
741  }
742 
743  // Iterate through all the segments of refSmoothedPoly
744  std::map<wxPoint, int> conflictPoints;
745 
746  for( auto refIt = smoothed_polys[ia].IterateSegmentsWithHoles(); refIt; refIt++ )
747  {
748  // Build ref segment
749  SEG refSegment = *refIt;
750 
751  // Iterate through all the segments in smoothed_polys[ia2]
752  for( auto testIt = smoothed_polys[ia2].IterateSegmentsWithHoles(); testIt; testIt++ )
753  {
754  // Build test segment
755  SEG testSegment = *testIt;
756  wxPoint pt;
757 
758  int ax1, ay1, ax2, ay2;
759  ax1 = refSegment.A.x;
760  ay1 = refSegment.A.y;
761  ax2 = refSegment.B.x;
762  ay2 = refSegment.B.y;
763 
764  int bx1, by1, bx2, by2;
765  bx1 = testSegment.A.x;
766  by1 = testSegment.A.y;
767  bx2 = testSegment.B.x;
768  by2 = testSegment.B.y;
769 
770  int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2,
771  0,
772  ax1, ay1, ax2, ay2,
773  0,
774  zone2zoneClearance,
775  &pt.x, &pt.y );
776 
777  if( d < zone2zoneClearance )
778  {
779  if( conflictPoints.count( pt ) )
780  conflictPoints[ pt ] = std::min( conflictPoints[ pt ], d );
781  else
782  conflictPoints[ pt ] = d;
783  }
784  }
785  }
786 
787  for( const std::pair<const wxPoint, int>& conflict : conflictPoints )
788  {
789  int actual = conflict.second;
790  std::shared_ptr<DRC_ITEM> drce;
791 
792  if( actual <= 0 )
793  {
795  }
796  else
797  {
799 
800  m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
801  constraint.GetName(),
802  MessageTextFromValue( userUnits(), zone2zoneClearance ),
803  MessageTextFromValue( userUnits(), conflict.second ) );
804 
805  drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
806  }
807 
808  drce->SetItems( zoneRef, zoneToTest );
809  drce->SetViolatingRule( constraint.GetParentRule() );
810 
811  reportViolation( drce, conflict.first );
812  }
813  }
814  }
815  }
816 }
817 
818 
820 {
821  return 5;
822 }
823 
824 
825 std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_COPPER_CLEARANCE::GetConstraintTypes() const
826 {
827  return { CLEARANCE_CONSTRAINT };
828 }
829 
830 
831 namespace detail
832 {
834 }
static bool isNetTie(BOARD_ITEM *aItem)
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)
Definition: base_units.cpp:123
bool testTrackAgainstItem(TRACK *track, SHAPE *trackShape, PCB_LAYER_ID layer, BOARD_ITEM *other)
class ALIGNED_DIMENSION, a linear dimension (graphic item)
Definition: typeinfo.h:101
int GetNetCode() const
Function GetNetCode.
class LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:102
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
Definition: drc_item.cpp:239
class FP_TEXT, text in a footprint
Definition: typeinfo.h:93
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:1845
ZONES & Zones()
Definition: board.h:289
unsigned GetPriority() const
Function GetPriority.
Definition: zone.h:124
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition: zone.h:747
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
Definition: board_item.h:86
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:103
static DRC_REGISTER_TEST_PROVIDER< DRC_TEST_PROVIDER_ANNULUS > dummy
bool IsErrorLimitExceeded(int error_code)
bool QueryWorstConstraint(DRC_CONSTRAINT_TYPE_T aRuleId, DRC_CONSTRAINT &aConstraint)
class PCB_TEXT, text on a layer
Definition: typeinfo.h:92
class ARC, an arc track segment on a copper layer
Definition: typeinfo.h:98
virtual bool reportProgress(int aCount, int aSize, int aDelta)
const SHAPE_SEGMENT * GetEffectiveHoleShape() const
Function GetEffectiveHoleShape Returns a SHAPE object representing the pad's hole.
Definition: pcbnew/pad.cpp:270
wxString GetNetname() const
Function GetNetname.
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Function IsOnLayer tests to see if this object is on the given layer.
Definition: zone.cpp:313
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.h:559
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:94
class PAD, a pad in a footprint
Definition: typeinfo.h:90
T Min() const
Definition: minoptmax.h:31
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:481
virtual void reportRuleStatistics()
virtual bool Collide(const VECTOR2I &aP, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const
Function Collide()
Definition: shape.h:176
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:126
const SEG & GetSeg() const
class TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
PAD_ATTR_T GetAttribute() const
Definition: pad.h:348
DRC_RULE * GetParentRule() const
Definition: drc_rule.h:124
const wxSize & GetDrillSize() const
Definition: pad.h:236
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
Definition: pcbnew/pad.cpp:189
OPT< VECTOR2I > OPT_VECTOR2I
Definition: seg.h:37
BOARD * GetBoard() const
Definition: drc_engine.h:85
virtual bool reportPhase(const wxString &aStageName)
SHAPE_POLY_SET.
FOOTPRINTS & Footprints()
Definition: board.h:283
static std::shared_ptr< SHAPE > getShape(BOARD_ITEM *aItem, PCB_LAYER_ID aLayer)
virtual BOARD * GetBoard() const
Function GetBoard returns the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:46
bool GetReportAllTrackErrors() const
Definition: drc_engine.h:153
void clear()
Function RemoveAll() Removes all items from the RTree.
Definition: drc_rtree.h:134
virtual void accountCheck(const DRC_RULE *ruleToTest)
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
SHAPE.
Definition: shape.h:122
EDA_UNITS userUnits() const
class DIMENSION_BASE: abstract dimension meta-type
Definition: typeinfo.h:100
std::map< ZONE *, std::unique_ptr< DRC_RTREE > > m_zoneTrees
class FOOTPRINT, a footprint
Definition: typeinfo.h:89
FOOTPRINT * GetParent() const
Definition: seg.h:39
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)
virtual std::set< DRC_CONSTRAINT_TYPE_T > GetConstraintTypes() const override
const MINOPTMAX< int > & GetValue() const
Definition: drc_rule.h:120
SHAPE * Clone() const override
Function Clone()
Definition: shape_segment.h:49
#define _(s)
Definition: 3d_actions.cpp:33
DRC_ENGINE * m_drcEngine
VECTOR2I A
Definition: seg.h:47
Plated through hole pad.
Definition: pad_shapes.h:80
EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
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:141
const wxPoint & GetEnd() const
Definition: track.h:113
bool Intersects(const EDA_RECT &aRect) const
Function Intersects tests for a common area between rectangles.
Definition: eda_rect.cpp:150
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
Function GetEffectiveShape Some pad shapes can be complex (rounded/chamfered rectangle),...
Definition: board_item.cpp:153
virtual bool IsConnected() const
Function IsConnected() Returns information if the object is derived from BOARD_CONNECTED_ITEM.
Definition: board_item.h:146
class ORTHOGONAL_DIMENSION, a linear dimension constrained to x/y
Definition: typeinfo.h:104
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
DRC_CONSTRAINT EvalRulesForItems(DRC_CONSTRAINT_TYPE_T ruleID, const BOARD_ITEM *a, const BOARD_ITEM *b=nullptr, PCB_LAYER_ID aLayer=UNDEFINED_LAYER, REPORTER *aReporter=nullptr)
Definition: drc_engine.cpp:697
virtual const EDA_RECT GetBoundingBox() const
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes.
Definition: eda_item.cpp:89
#define SKIP_STRUCT
flag indicating that the structure should be ignored
Definition: eda_item.h:117
virtual const wxString GetDescription() const override
bool HasFlag(STATUS_FLAGS aFlag)
Definition: eda_item.h:223
Definition: pad.h:59
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:179
int GetWidth() const
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:91
TRACKS & Tracks()
Definition: board.h:280
virtual void reportAux(wxString fmt,...)
Definition: track.h:83
KICAD_T Type() const
Function Type()
Definition: eda_item.h:181
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:179
BOARD_DESIGN_SETTINGS contains design settings for a BOARD object.
VECTOR2I B
Definition: seg.h:48