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 <class_board.h>
26 #include <class_drawsegment.h>
27 #include <class_pad.h>
28 #include <class_track.h>
29 
30 //#include <geometry/polygon_test_point_inside.h>
31 #include <geometry/seg.h>
33 #include <geometry/shape_rect.h>
34 #include <geometry/shape_segment.h>
35 
36 #include <drc/drc_engine.h>
37 #include <drc/drc_item.h>
38 #include <drc/drc_rule.h>
40 #include <class_dimension.h>
41 
42 /*
43  Copper clearance test. Checks all copper items (pads, vias, tracks, drawings, zones) for their electrical clearance.
44  Errors generated:
45  - DRCE_CLEARANCE
46  - DRCE_TRACKS_CROSSING
47  - DRCE_ZONES_INTERSECT
48  - DRCE_SHORTING_ITEMS
49 
50  TODO: improve zone clearance check (super slow)
51 */
52 
54 {
55 public:
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  void testPadClearances();
83 
84  void testTrackClearances();
85 
87 
88  void testZones();
89 
90  void testCopperDrawItem( BOARD_ITEM* aItem );
91 
92  void doTrackDrc( TRACK* aRefSeg, PCB_LAYER_ID aLayer, TRACKS::iterator aStartIt,
93  TRACKS::iterator aEndIt );
94 
104  void doPadToPadsDrc( int aRefPadIdx, std::vector<D_PAD*>& aSortedPadsList, int aX_limit );
105 };
106 
107 
109 {
111  DRC_CONSTRAINT worstClearanceConstraint;
112 
114  worstClearanceConstraint, DRCCQ_LARGEST_MINIMUM ) )
115  {
116  m_largestClearance = worstClearanceConstraint.GetValue().Min();
117  }
118  else
119  {
120  reportAux( "No Clearance constraints found..." );
121  return false;
122  }
123 
124  reportAux( "Worst clearance : %d nm", m_largestClearance );
125 
126  if( !reportPhase( _( "Checking pad clearances..." ) ) )
127  return false;
128 
130 
131  if( !reportPhase( _( "Checking track & via clearances..." ) ) )
132  return false;
133 
135 
136  if( !reportPhase( _( "Checking copper graphic & text clearances..." ) ) )
137  return false;
138 
140 
141  if( !reportPhase( _( "Checking copper zone clearances..." ) ) )
142  return false;
143 
144  testZones();
145 
147 
148  return true;
149 }
150 
152 {
153  // Test copper items for clearance violations with vias, tracks and pads
154 
155  for( BOARD_ITEM* brdItem : m_board->Drawings() )
156  {
157  if( IsCopperLayer( brdItem->GetLayer() ) )
158  testCopperDrawItem( brdItem );
159  }
160 
161  for( MODULE* module : m_board->Modules() )
162  {
163  TEXTE_MODULE& ref = module->Reference();
164  TEXTE_MODULE& val = module->Value();
165 
166  if( ref.IsVisible() && IsCopperLayer( ref.GetLayer() ) )
167  testCopperDrawItem( &ref );
168 
169  if( val.IsVisible() && IsCopperLayer( val.GetLayer() ) )
170  testCopperDrawItem( &val );
171 
172  if( module->IsNetTie() )
173  continue;
174 
175  for( BOARD_ITEM* item : module->GraphicalItems() )
176  {
177  if( IsCopperLayer( item->GetLayer() ) )
178  {
179  if( item->Type() == PCB_MODULE_TEXT_T && ( (TEXTE_MODULE*) item )->IsVisible() )
180  testCopperDrawItem( item );
181  else if( item->Type() == PCB_MODULE_EDGE_T )
182  testCopperDrawItem( item );
183  }
184  }
185  }
186 }
187 
188 
190 {
191  EDA_RECT bbox;
192  std::shared_ptr<SHAPE> itemShape;
193  EDA_TEXT* textItem = dynamic_cast<EDA_TEXT*>( aItem );
194  PCB_LAYER_ID layer = aItem->GetLayer();
195 
196  if( textItem )
197  {
198  bbox = textItem->GetTextBox();
199  itemShape = textItem->GetEffectiveTextShape();
200  }
201  else
202  {
203  bbox = aItem->GetBoundingBox();
204  itemShape = aItem->GetEffectiveShape( layer );
205  }
206 
207  SHAPE_RECT bboxShape( bbox.GetX(), bbox.GetY(), bbox.GetWidth(), bbox.GetHeight() );
208 
209  // Test tracks and vias
210  for( TRACK* track : m_board->Tracks() )
211  {
212  if( !track->IsOnLayer( aItem->GetLayer() ) )
213  continue;
214 
216  aItem, track, layer );
217  int minClearance = constraint.GetValue().Min();
218  int actual = INT_MAX;
219  wxPoint pos;
220 
221  accountCheck( constraint );
222 
223  SHAPE_SEGMENT trackSeg( track->GetStart(), track->GetEnd(), track->GetWidth() );
224 
225  // Fast test to detect a track segment candidate inside the text bounding box
226  if( !bboxShape.Collide( &trackSeg, 0 ) )
227  continue;
228 
229  if( !itemShape->Collide( &trackSeg, minClearance, &actual ) )
230  continue;
231 
232  pos = (wxPoint) itemShape->Centre();
233 
234  if( actual < INT_MAX )
235  {
236  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
237 
238  m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
239  constraint.GetName(),
240  MessageTextFromValue( userUnits(), minClearance, true ),
241  MessageTextFromValue( userUnits(), std::max( 0, actual ), true ) );
242 
243  drcItem->SetErrorMessage( m_msg );
244  drcItem->SetItems( track, aItem );
245  drcItem->SetViolatingRule( constraint.GetParentRule() );
246 
247  reportViolation( drcItem, pos );
248  }
249  }
250 
251  // Test pads
252  for( D_PAD* pad : m_board->GetPads() )
253  {
254  if( !pad->IsOnLayer( layer ) )
255  continue;
256 
257  // Graphic items are allowed to act as net-ties within their own footprint
258  if( aItem->Type() == PCB_MODULE_EDGE_T && pad->GetParent() == aItem->GetParent() )
259  continue;
260 
262  aItem, pad, layer );
263  int minClearance = constraint.GetValue().Min();
264  int actual;
265 
266  accountCheck( constraint );
267 
268 
269  // Fast test to detect a pad candidate inside the text bounding box
270  // Finer test (time consuming) is made only for pads near the text.
271  int bb_radius = pad->GetBoundingRadius() + minClearance;
272 
273  if( !bboxShape.Collide( SEG( pad->GetPosition(), pad->GetPosition() ), bb_radius ) )
274  continue;
275 
276  if( !pad->GetEffectiveShape()->Collide( itemShape.get(), minClearance, &actual ) )
277  continue;
278 
279  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
280 
281  m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
282  constraint.GetName(),
283  MessageTextFromValue( userUnits(), minClearance, true ),
284  MessageTextFromValue( userUnits(), actual, true ) );
285 
286  drcItem->SetErrorMessage( m_msg );
287  drcItem->SetItems( pad, aItem );
288  drcItem->SetViolatingRule( constraint.GetParentRule() );
289 
290  reportViolation( drcItem, pad->GetPosition());
291  }
292 }
293 
294 
296 {
297  // This is the number of tests between 2 calls to the progress bar
298  const int delta = m_drcEngine->GetTestTracksAgainstZones() ? 25 : 100;
299  int count = m_board->Tracks().size();
300 
301  reportAux( "Testing %d tracks...", count );
302 
303  int ii = 0;
304 
305  for( auto seg_it = m_board->Tracks().begin(); seg_it != m_board->Tracks().end(); seg_it++ )
306  {
307  if( !reportProgress( ii++, m_board->Tracks().size(), delta ) )
308  break;
309 
310  // Test segment against tracks and pads, optionally against copper zones
311  for( PCB_LAYER_ID layer : (*seg_it)->GetLayerSet().Seq() )
312  {
313  doTrackDrc( *seg_it, layer, seg_it + 1, m_board->Tracks().end() );
314  }
315  }
316 }
317 
319  TRACKS::iterator aStartIt,
320  TRACKS::iterator aEndIt )
321 {
323 
324  SHAPE_SEGMENT refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd(), aRefSeg->GetWidth() );
325  EDA_RECT refSegInflatedBB = aRefSeg->GetBoundingBox();
326  int refSegWidth = aRefSeg->GetWidth();
327 
328  refSegInflatedBB.Inflate( m_largestClearance );
329 
330  /******************************************/
331  /* Phase 1 : test DRC track to pads : */
332  /******************************************/
333 
334  // Compute the min distance to pads
335  for( MODULE* mod : m_board->Modules() )
336  {
338  break;
339 
340  // Don't preflight at the module level. Getting a module's bounding box goes
341  // through all its pads anyway (so it's no faster), and also all its drawings
342  // (so it's in fact slower).
343 
344  for( D_PAD* pad : mod->Pads() )
345  {
347  break;
348 
349  // Preflight based on bounding boxes.
350  if( !refSegInflatedBB.Intersects( pad->GetBoundingBox() ) )
351  continue;
352 
354  if( !pad->IsOnLayer( aLayer ) )
355  continue;
356 
357  // No need to check pads with the same net as the refSeg.
358  if( pad->GetNetCode() && aRefSeg->GetNetCode() == pad->GetNetCode() )
359  continue;
360 
362  aRefSeg, pad, aLayer );
363  int minClearance = constraint.GetValue().Min();
364  int actual;
365 
366  accountCheck( constraint );
367 
368  const std::shared_ptr<SHAPE>& padShape = pad->GetEffectiveShape();
369 
370  if( padShape->Collide( &refSeg, minClearance - bds.GetDRCEpsilon(), &actual ) )
371  {
372  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
373 
374  m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
375  constraint.GetName(),
376  MessageTextFromValue( userUnits(), minClearance, true ),
377  MessageTextFromValue( userUnits(), actual, true ) );
378 
379  drcItem->SetErrorMessage( m_msg );
380  drcItem->SetItems( aRefSeg, pad );
381  drcItem->SetViolatingRule( constraint.GetParentRule() );
382 
383  reportViolation( drcItem, pad->GetPosition());
384  }
385  }
386  }
387 
388  /***********************************************/
389  /* Phase 2: test DRC with other track segments */
390  /***********************************************/
391 
392  // Test the reference segment with other track segments
393  for( auto it = aStartIt; it != aEndIt; it++ )
394  {
396  break;
397 
398  TRACK* track = *it;
399 
400  if( track->Type() == PCB_VIA_T )
401  {
402  if( !track->GetLayerSet().test( aLayer ) )
403  continue;
404  }
405  else
406  {
407  if( track->GetLayer() != aLayer )
408  continue;
409  }
410 
411  // No problem if segments have the same net code:
412  if( aRefSeg->GetNetCode() == track->GetNetCode() )
413  continue;
414 
415  // Preflight based on worst-case inflated bounding boxes:
416  if( !refSegInflatedBB.Intersects( track->GetBoundingBox() ) )
417  continue;
418 
420  aRefSeg, track, aLayer );
421  int minClearance = constraint.GetValue().Min();
422  int actual;
423  SHAPE_SEGMENT trackSeg( track->GetStart(), track->GetEnd(), track->GetWidth() );
424 
425  accountCheck( constraint );
426 
428  if( track->Type() == PCB_VIA_T )
429  {
430  VIA* via = static_cast<VIA*>( track );
431 
432  if( !via->IsPadOnLayer( aLayer ) )
433  trackSeg.SetWidth( via->GetDrillValue() );
434  }
435 
436  // Check two tracks crossing first as it reports a DRCE without distances
437  if( OPT_VECTOR2I intersection = refSeg.GetSeg().Intersect( trackSeg.GetSeg() ) )
438  {
439  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TRACKS_CROSSING );
440  drcItem->SetItems( aRefSeg, track );
441  drcItem->SetViolatingRule( constraint.GetParentRule() );
442 
443  reportViolation( drcItem, (wxPoint) intersection.get());
444  }
445  else if( refSeg.Collide( &trackSeg, minClearance - bds.GetDRCEpsilon(), &actual ) )
446  {
447  wxPoint pos = getLocation( aRefSeg, trackSeg.GetSeg() );
448  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
449 
450  m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
451  constraint.GetName(),
452  MessageTextFromValue( userUnits(), minClearance, true ),
453  MessageTextFromValue( userUnits(), actual, true ) );
454 
455  drcItem->SetErrorMessage( m_msg );
456  drcItem->SetItems( aRefSeg, track );
457  drcItem->SetViolatingRule( constraint.GetParentRule() );
458 
459  reportViolation( drcItem, pos );
460 
462  break;
463  }
464  }
465 
466  /***************************************/
467  /* Phase 3: test DRC with copper zones */
468  /***************************************/
469  // Can be *very* time consuming.
470 
472  {
473  SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
474 
475  for( ZONE_CONTAINER* zone : m_board->Zones() )
476  {
478  break;
479 
480  if( !zone->GetLayerSet().test( aLayer ) || zone->GetIsRuleArea() )
481  continue;
482 
483  if( zone->GetNetCode() && zone->GetNetCode() == aRefSeg->GetNetCode() )
484  continue;
485 
486  if( zone->GetFilledPolysList( aLayer ).IsEmpty() )
487  continue;
488 
489  if( !refSegInflatedBB.Intersects( zone->GetBoundingBox() ) )
490  continue;
491 
493  aRefSeg, zone, aLayer );
494  int minClearance = constraint.GetValue().Min();
495  int halfWidth = refSegWidth / 2;
496  int allowedDist = minClearance + halfWidth - bds.GetDRCEpsilon();
497  int actual;
498 
499  accountCheck( constraint );
500 
501  if( zone->GetFilledPolysList( aLayer ).Collide( testSeg, allowedDist, &actual ) )
502  {
503  actual = std::max( 0, actual - halfWidth );
504  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
505 
506  m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
507  constraint.GetName(),
508  MessageTextFromValue( userUnits(), minClearance, true ),
509  MessageTextFromValue( userUnits(), actual, true ) );
510 
511  drcItem->SetErrorMessage( m_msg );
512  drcItem->SetItems( aRefSeg, zone );
513  drcItem->SetViolatingRule( constraint.GetParentRule() );
514 
515  reportViolation( drcItem, getLocation( aLayer, aRefSeg, zone ));
516  }
517  }
518  }
519 }
520 
521 
523 {
524  const int delta = 25; // This is the number of tests between 2 calls to the progress bar
525  std::vector<D_PAD*> sortedPads;
526 
527  m_board->GetSortedPadListByXthenYCoord( sortedPads );
528 
529  reportAux( "Testing %d pads...", sortedPads.size());
530 
531  if( sortedPads.empty() )
532  return;
533 
534  // find the max size of the pads (used to stop the pad-to-pad tests)
535  int max_size = 0;
536 
537  for( D_PAD* pad : sortedPads )
538  {
539  // GetBoundingRadius() is the radius of the minimum sized circle fully containing the pad
540  int radius = pad->GetBoundingRadius();
541 
542  if( radius > max_size )
543  max_size = radius;
544  }
545 
546  // Better to be fast than accurate; this keeps us from having to look up / calculate the
547  // actual clearances
548  max_size += m_largestClearance;
549 
550  // Test the pads
551  for( int idx = 0; idx < (int) sortedPads.size(); idx++ )
552  {
553  D_PAD* pad = sortedPads[idx];
554 
555  if( !reportProgress( idx, sortedPads.size(), delta ) )
556  break;
557 
558  int x_limit = pad->GetPosition().x + pad->GetBoundingRadius() + max_size;
559 
560  doPadToPadsDrc( idx, sortedPads, x_limit );
561  }
562 }
563 
565  std::vector<D_PAD*>& aSortedPadsList,
566  int aX_limit )
567 {
568  const static LSET all_cu = LSET::AllCuMask();
570 
571  D_PAD* refPad = aSortedPadsList[aRefPadIdx];
572  LSET layerMask = refPad->GetLayerSet() & all_cu;
573  EDA_RECT refPadInflatedBB = refPad->GetBoundingBox();
574 
575  refPadInflatedBB.Inflate( m_largestClearance );
576 
577  for( int idx = aRefPadIdx; idx < (int)aSortedPadsList.size(); ++idx )
578  {
579  bool exceedClearance = m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE );
580  bool exceedShorting = m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE );
581 
582  if( exceedClearance && exceedShorting )
583  return;
584 
585  D_PAD* pad = aSortedPadsList[idx];
586 
587  if( pad == refPad )
588  continue;
589 
590  // We can stop the test when pad->GetPosition().x > aX_limit
591  // because the list is sorted by X poditions, and other pads are too far.
592  if( pad->GetPosition().x > aX_limit )
593  break;
594 
595  // The pad must be in a net (i.e pt_pad->GetNet() != 0 ),
596  // But no problem if pads have the same netcode (same net)
597  if( pad->GetNetCode() && ( refPad->GetNetCode() == pad->GetNetCode() ) )
598  continue;
599 
600  // If pads are equivalent (ie: from the same footprint with the same pad number)...
601  if( pad->GetParent() == refPad->GetParent() && pad->PadNameEqual( refPad ) )
602  {
603  // ...and have nets, then they must be the same net
604  if( pad->GetNetCode() && refPad->GetNetCode()
605  && pad->GetNetCode() != refPad->GetNetCode()
606  && !exceedShorting )
607  {
608  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_SHORTING_ITEMS );
609 
610  m_msg.Printf( drcItem->GetErrorText() + _( " (nets %s and %s)" ),
611  pad->GetNetname(), refPad->GetNetname() );
612 
613  drcItem->SetErrorMessage( m_msg );
614  drcItem->SetItems( pad, refPad );
615 
616  reportViolation( drcItem, refPad->GetPosition());
617  }
618 
619  continue;
620  }
621 
622  // if either pad has no drill and is only on technical layers, not a clearance violation
623  if( ( ( pad->GetLayerSet() & layerMask ) == 0 && !pad->GetDrillSize().x ) ||
624  ( ( refPad->GetLayerSet() & layerMask ) == 0 && !refPad->GetDrillSize().x ) )
625  {
626  continue;
627  }
628 
629  if( !refPadInflatedBB.Intersects( pad->GetBoundingBox() ) )
630  continue;
631 
632  for( PCB_LAYER_ID layer : refPad->GetLayerSet().Seq() )
633  {
634  if( exceedClearance )
635  break;
636 
638  refPad, pad, layer );
639  int minClearance = constraint.GetValue().Min();
640  int clearanceAllowed = minClearance - bds.GetDRCEpsilon();
641  int actual;
642 
643  accountCheck( constraint );
644 
645  std::shared_ptr<SHAPE> refPadShape = refPad->GetEffectiveShape();
646 
647  if( refPadShape->Collide( pad->GetEffectiveShape().get(), clearanceAllowed, &actual ) )
648  {
649  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
650 
651  m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
652  constraint.GetName(),
653  MessageTextFromValue( userUnits(), minClearance, true ),
654  MessageTextFromValue( userUnits(), actual, true ) );
655 
656  drcItem->SetErrorMessage( m_msg );
657  drcItem->SetItems( refPad, pad );
658  drcItem->SetViolatingRule( constraint.GetParentRule() );
659 
660  reportViolation( drcItem, refPad->GetPosition());
661  break;
662  }
663  }
664  }
665 }
666 
667 
669 {
670  const int delta = 50; // This is the number of tests between 2 calls to the progress bar
671 
672  // Test copper areas for valid netcodes -> fixme, goes to connectivity checks
673 
674  for( int layer_id = F_Cu; layer_id <= B_Cu; ++layer_id )
675  {
676  PCB_LAYER_ID layer = static_cast<PCB_LAYER_ID>( layer_id );
677  std::vector<SHAPE_POLY_SET> smoothed_polys;
678  smoothed_polys.resize( m_board->GetAreaCount() );
679 
680  // Skip over layers not used on the current board
681  if( !m_board->IsLayerEnabled( layer ) )
682  continue;
683 
684  for( int ii = 0; ii < m_board->GetAreaCount(); ii++ )
685  {
686  ZONE_CONTAINER* zoneRef = m_board->GetArea( ii );
687 
688  if( zoneRef->IsOnLayer( layer ) )
689  zoneRef->BuildSmoothedPoly( smoothed_polys[ii], layer );
690  }
691 
692  // iterate through all areas
693  for( int ia = 0; ia < m_board->GetAreaCount(); ia++ )
694  {
695  if( !reportProgress( ia, m_board->GetAreaCount(), delta ) )
696  break;
697 
698  ZONE_CONTAINER* zoneRef = m_board->GetArea( ia );
699 
700  if( !zoneRef->IsOnLayer( layer ) )
701  continue;
702 
703  // If we are testing a single zone, then iterate through all other zones
704  // Otherwise, we have already tested the zone combination
705  for( int ia2 = ia + 1; ia2 < m_board->GetAreaCount(); ia2++ )
706  {
707  ZONE_CONTAINER* zoneToTest = m_board->GetArea( ia2 );
708 
709  if( zoneRef == zoneToTest )
710  continue;
711 
712  // test for same layer
713  if( !zoneToTest->IsOnLayer( layer ) )
714  continue;
715 
716  // Test for same net
717  if( zoneRef->GetNetCode() == zoneToTest->GetNetCode() && zoneRef->GetNetCode() >= 0 )
718  continue;
719 
720  // test for different priorities
721  if( zoneRef->GetPriority() != zoneToTest->GetPriority() )
722  continue;
723 
724  // test for different types
725  if( zoneRef->GetIsRuleArea() != zoneToTest->GetIsRuleArea() )
726  continue;
727 
728  // Examine a candidate zone: compare zoneToTest to zoneRef
729 
730  // Get clearance used in zone to zone test.
732  zoneRef, zoneToTest );
733  int zone2zoneClearance = constraint.GetValue().Min();
734 
735  accountCheck( constraint );
736 
737  // Keepout areas have no clearance, so set zone2zoneClearance to 1
738  // ( zone2zoneClearance = 0 can create problems in test functions)
739  if( zoneRef->GetIsRuleArea() ) // fixme: really?
740  zone2zoneClearance = 1;
741 
742  // test for some corners of zoneRef inside zoneToTest
743  for( auto iterator = smoothed_polys[ia].IterateWithHoles(); iterator; iterator++ )
744  {
745  VECTOR2I currentVertex = *iterator;
746  wxPoint pt( currentVertex.x, currentVertex.y );
747 
748  if( smoothed_polys[ia2].Contains( currentVertex ) )
749  {
750  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_ZONES_INTERSECT );
751  drcItem->SetItems( zoneRef, zoneToTest );
752  drcItem->SetViolatingRule( constraint.GetParentRule() );
753 
754  reportViolation( drcItem, pt );
755  }
756  }
757 
758  // test for some corners of zoneToTest inside zoneRef
759  for( auto iterator = smoothed_polys[ia2].IterateWithHoles(); iterator; iterator++ )
760  {
761  VECTOR2I currentVertex = *iterator;
762  wxPoint pt( currentVertex.x, currentVertex.y );
763 
764  if( smoothed_polys[ia].Contains( currentVertex ) )
765  {
766  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_ZONES_INTERSECT );
767  drcItem->SetItems( zoneToTest, zoneRef );
768  drcItem->SetViolatingRule( constraint.GetParentRule() );
769 
770  reportViolation( drcItem, pt );
771  }
772  }
773 
774  // Iterate through all the segments of refSmoothedPoly
775  std::map<wxPoint, int> conflictPoints;
776 
777  for( auto refIt = smoothed_polys[ia].IterateSegmentsWithHoles(); refIt; refIt++ )
778  {
779  // Build ref segment
780  SEG refSegment = *refIt;
781 
782  // Iterate through all the segments in smoothed_polys[ia2]
783  for( auto testIt = smoothed_polys[ia2].IterateSegmentsWithHoles(); testIt; testIt++ )
784  {
785  // Build test segment
786  SEG testSegment = *testIt;
787  wxPoint pt;
788 
789  int ax1, ay1, ax2, ay2;
790  ax1 = refSegment.A.x;
791  ay1 = refSegment.A.y;
792  ax2 = refSegment.B.x;
793  ay2 = refSegment.B.y;
794 
795  int bx1, by1, bx2, by2;
796  bx1 = testSegment.A.x;
797  by1 = testSegment.A.y;
798  bx2 = testSegment.B.x;
799  by2 = testSegment.B.y;
800 
801  int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2,
802  0,
803  ax1, ay1, ax2, ay2,
804  0,
805  zone2zoneClearance,
806  &pt.x, &pt.y );
807 
808  if( d < zone2zoneClearance )
809  {
810  if( conflictPoints.count( pt ) )
811  conflictPoints[ pt ] = std::min( conflictPoints[ pt ], d );
812  else
813  conflictPoints[ pt ] = d;
814  }
815  }
816  }
817 
818  for( const std::pair<const wxPoint, int>& conflict : conflictPoints )
819  {
820  int actual = conflict.second;
821  std::shared_ptr<DRC_ITEM> drcItem;
822 
823  if( actual <= 0 )
824  {
826  }
827  else
828  {
829  drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
830 
831  m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
832  constraint.GetName(),
833  MessageTextFromValue( userUnits(), zone2zoneClearance, true ),
834  MessageTextFromValue( userUnits(), conflict.second, true ) );
835 
836  drcItem->SetErrorMessage( m_msg );
837  }
838 
839  drcItem->SetItems( zoneRef, zoneToTest );
840  drcItem->SetViolatingRule( constraint.GetParentRule() );
841 
842  reportViolation( drcItem, conflict.first );
843  }
844  }
845  }
846  }
847 }
848 
849 
851 {
852  return 4;
853 }
854 
855 
856 std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_COPPER_CLEARANCE::GetConstraintTypes() const
857 {
859 }
860 
861 
862 namespace detail
863 {
865 }
wxPoint getLocation(TRACK *aTrack, const SEG &aConflictSeg)
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:731
ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:61
int GetNetCode() const
Function GetNetCode.
bool GetTestTracksAgainstZones() const
Definition: drc_engine.h:154
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
Definition: drc_item.cpp:205
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
wxPoint GetPosition() const override
Definition: class_pad.h:165
int GetX() const
Definition: eda_rect.h:111
const wxPoint & GetStart() const
Definition: class_track.h:116
bool IsVisible() const
Definition: eda_text.h:186
static DRC_REGISTER_TEST_PROVIDER< DRC_TEST_PROVIDER_ANNULUS > dummy
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Function IsOnLayer tests to see if this object is on the given layer.
Definition: class_zone.cpp:311
bool IsErrorLimitExceeded(int error_code)
Definition: drc_engine.cpp:605
EDA_RECT GetTextBox(int aLine=-1, bool aInvertY=false) const
Useful in multiline texts to calculate the full text or a line area (for zones filling,...
Definition: eda_text.cpp:222
void GetSortedPadListByXthenYCoord(std::vector< D_PAD * > &aVector, int aNetCode=-1)
First empties then fills the vector with all pads and sorts them by increasing x coordinate,...
int GetWidth() const
Definition: eda_rect.h:119
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes.
bool PadNameEqual(const D_PAD *other) const
Definition: class_pad.h:140
virtual bool reportProgress(int aCount, int aSize, int aDelta)
wxString GetNetname() const
Function GetNetname.
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: class_board.h:514
T Min() const
Definition: drc_rule.h:74
bool BuildSmoothedPoly(SHAPE_POLY_SET &aSmoothedPoly, PCB_LAYER_ID aLayer) const
Function GetSmoothedPoly.
bool IsLayerEnabled(PCB_LAYER_ID aLayer) const
A proxy function that calls the correspondent function in m_BoardSettings tests whether a given layer...
Definition: class_board.h:436
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:392
class EDGE_MODULE, a footprint edge
Definition: typeinfo.h:94
virtual void reportRuleStatistics()
A single base class (TRACK) represents both tracks and vias, with subclasses for curved tracks (ARC) ...
void doTrackDrc(TRACK *aRefSeg, PCB_LAYER_ID aLayer, TRACKS::iterator aStartIt, TRACKS::iterator aEndIt)
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:113
DIMENSION class definition.
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).
int GetAreaCount() const
Definition: class_board.h:855
LSET is a set of PCB_LAYER_IDs.
int GetDrillValue() const
Function GetDrillValue "calculates" the drill value for vias (m-Drill if > 0, or default drill value ...
MODULES & Modules()
Definition: class_board.h:247
OPT< VECTOR2I > OPT_VECTOR2I
Definition: seg.h:37
BOARD * GetBoard() const
Definition: drc_engine.h:140
virtual bool reportPhase(const wxString &aStageName)
LSET GetLayerSet() const override
Function GetLayerSet returns a std::bitset of all layers on which the item physically resides.
Definition: class_pad.h:332
bool GetReportAllTrackErrors() const
Definition: drc_engine.h:155
int GetBoundingRadius() const
Function GetBoundingRadius returns the radius of a minimum sized circle which fully encloses this pad...
Definition: class_pad.cpp:282
virtual void accountCheck(const DRC_RULE *ruleToTest)
EDA_UNITS userUnits() const
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER) const override
Function GetEffectiveShape Some pad shapes can be complex (rounded/chamfered rectangle),...
Definition: class_pad.cpp:264
int GetHeight() const
Definition: eda_rect.h:120
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition: class_zone.h:725
Pad object description.
MODULE * GetParent() const
Definition: class_pad.h:111
class TEXTE_MODULE, text in a footprint
Definition: typeinfo.h:93
Definition: seg.h:39
wxString MessageTextFromValue(EDA_UNITS aUnits, int aValue, bool aUseMils, EDA_DATA_TYPE aType)
Definition: base_units.cpp:124
virtual const wxString GetName() const override
virtual void reportViolation(std::shared_ptr< DRC_ITEM > &item, wxPoint aMarkerPos)
virtual std::set< DRC_CONSTRAINT_TYPE_T > GetConstraintTypes() const override
const std::vector< D_PAD * > GetPads()
Return a reference to a list of all the pads.
void doPadToPadsDrc(int aRefPadIdx, std::vector< D_PAD * > &aSortedPadsList, int aX_limit)
Test clearance of a pad hole with the pad hole of other pads.
ZONE_CONTAINERS & Zones()
Definition: class_board.h:252
unsigned GetPriority() const
Function GetPriority.
Definition: class_zone.h:106
int GetWidth() const
Definition: class_track.h:110
const MINOPTMAX< int > & GetValue() const
Definition: drc_rule.h:132
Class to handle a graphic segment.
std::shared_ptr< SHAPE_COMPOUND > GetEffectiveTextShape() const
Definition: eda_text.cpp:620
#define _(s)
Definition: 3d_actions.cpp:33
DRC_ENGINE * m_drcEngine
const wxSize & GetDrillSize() const
Definition: class_pad.h:230
VECTOR2I A
Definition: seg.h:47
EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
int GetY() const
Definition: eda_rect.h:112
The common library.
const wxPoint & GetEnd() const
Definition: class_track.h:113
bool Intersects(const EDA_RECT &aRect) const
Function Intersects tests for a common area between rectangles.
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),...
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:430
ZONE_CONTAINER * GetArea(int index) const
Return the Area (Zone Container) at a given index.
Definition: class_board.h:839
virtual const EDA_RECT GetBoundingBox() const
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes.
Definition: base_struct.cpp:97
virtual const wxString GetDescription() const override
BOARD_ITEM_CONTAINER * GetParent() const
bool QueryWorstConstraint(DRC_CONSTRAINT_TYPE_T aRuleId, DRC_CONSTRAINT &aConstraint, DRC_CONSTRAINT_QUERY_T aQueryType)
Definition: drc_engine.cpp:715
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
DRAWINGS & Drawings()
Definition: class_board.h:250
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox The bounding box is cached, so this will be efficient most of the time.
Definition: class_pad.cpp:458
TRACKS & Tracks()
Definition: class_board.h:244
virtual void reportAux(wxString fmt,...)
bool IsPadOnLayer(int aLayer) const
Checks to see whether the via should have a pad on the specific layer.
virtual LSET GetLayerSet() const
Function GetLayerSet returns a std::bitset of all layers on which the item physically resides.
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
KICAD_T Type() const
Function Type()
Definition: base_struct.h:193
BOARD_DESIGN_SETTINGS contains design settings for a BOARD object.
VECTOR2I B
Definition: seg.h:48