KiCad PCB EDA Suite
pcbnew/drc/drc.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-2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2014 Dick Hollenbeck, dick@softplc.com
6  * Copyright (C) 2017-2020 KiCad Developers, see change_log.txt for contributors.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
26 #include <fctsys.h>
27 #include <pcb_edit_frame.h>
28 #include <trigo.h>
29 #include <board_design_settings.h>
30 #include <class_edge_mod.h>
31 #include <class_drawsegment.h>
32 #include <class_module.h>
33 #include <class_track.h>
34 #include <class_pad.h>
35 #include <class_zone.h>
36 #include <class_pcb_text.h>
37 #include <geometry/seg.h>
38 #include <math_for_graphics.h>
40 #include <bitmaps.h>
41 #include <tool/tool_manager.h>
42 #include <tools/pcb_actions.h>
43 #include <tools/pcb_tool_base.h>
44 #include <tools/zone_filler_tool.h>
45 #include <kiface_i.h>
46 #include <pcbnew.h>
48 #include <math/util.h> // for KiROUND
49 #include <dialog_drc.h>
50 #include <wx/progdlg.h>
51 #include <board_commit.h>
52 #include <geometry/shape_arc.h>
53 #include <drc/drc.h>
54 #include <drc/drc_rule_parser.h>
55 #include <drc/drc_item.h>
58 #include <drc/drc_keepout_tester.h>
60 #include <drc/drc_textvar_tester.h>
61 #include <drc/footprint_tester.h>
63 
65  PCB_TOOL_BASE( "pcbnew.DRCTool" ),
66  m_editFrame( nullptr ),
67  m_pcb( nullptr ),
68  m_board_outline_valid( false ),
69  m_drcDialog( nullptr ),
70  m_largestClearance( 0 )
71 {
72  // establish initial values for everything:
73  m_doUnconnectedTest = true; // enable unconnected tests
74  m_testTracksAgainstZones = false; // disable zone to items clearance tests
75  m_doKeepoutTest = true; // enable keepout areas to items clearance tests
76  m_refillZones = false; // Only fill zones if requested by user.
77  m_reportAllTrackErrors = false;
78  m_testFootprints = false;
79 
80  m_drcRun = false;
81  m_footprintsTested = false;
82 }
83 
84 
86 {
87  for( DRC_ITEM* unconnectedItem : m_unconnected )
88  delete unconnectedItem;
89 
90  for( DRC_ITEM* footprintItem : m_footprints )
91  delete footprintItem;
92 }
93 
94 
95 void DRC::Reset( RESET_REASON aReason )
96 {
97  m_editFrame = getEditFrame<PCB_EDIT_FRAME>();
98 
99  if( m_pcb != m_editFrame->GetBoard() )
100  {
101  if( m_drcDialog )
102  DestroyDRCDialog( wxID_OK );
103 
105  }
106 }
107 
108 
109 void DRC::ShowDRCDialog( wxWindow* aParent )
110 {
111  bool show_dlg_modal = true;
112 
113  // the dialog needs a parent frame. if it is not specified, this is
114  // the PCB editor frame specified in DRC class.
115  if( !aParent )
116  {
117  // if any parent is specified, the dialog is modal.
118  // if this is the default PCB editor frame, it is not modal
119  show_dlg_modal = false;
120  aParent = m_editFrame;
121  }
122 
123  Activate();
125 
126  if( !m_drcDialog )
127  {
128  m_drcDialog = new DIALOG_DRC( this, m_editFrame, aParent );
129  updatePointers();
130 
131  if( show_dlg_modal )
132  m_drcDialog->ShowModal();
133  else
134  m_drcDialog->Show( true );
135  }
136  else // The dialog is just not visible (because the user has double clicked on an error item)
137  {
138  updatePointers();
139  m_drcDialog->Show( true );
140  }
141 }
142 
143 
144 int DRC::ShowDRCDialog( const TOOL_EVENT& aEvent )
145 {
146  ShowDRCDialog( nullptr );
147  return 0;
148 }
149 
150 
152 {
153  if( m_drcDialog )
154  return m_drcDialog->IsShown();
155 
156  return false;
157 }
158 
159 
160 void DRC::addMarkerToPcb( BOARD_COMMIT& aCommit, MARKER_PCB* aMarker )
161 {
162  if( m_pcb->GetDesignSettings().Ignore( aMarker->GetRCItem()->GetErrorCode() ) )
163  {
164  delete aMarker;
165  return;
166  }
167 
168  aCommit.Add( aMarker );
169 }
170 
171 
172 void DRC::DestroyDRCDialog( int aReason )
173 {
174  if( m_drcDialog )
175  {
176  m_drcDialog->Destroy();
177  m_drcDialog = nullptr;
178  }
179 }
180 
181 
183 {
184  wxString rulesFilepath = m_editFrame->Prj().AbsolutePath( "drc-rules" );
185  wxFileName rulesFile( rulesFilepath );
186 
187  if( rulesFile.FileExists() )
188  {
189  m_ruleSelectors.clear();
190  m_rules.clear();
191 
192  FILE* fp = wxFopen( rulesFilepath, wxT( "rt" ) );
193 
194  if( fp )
195  {
196  try
197  {
198  DRC_RULES_PARSER parser( m_pcb, fp, rulesFilepath );
199  parser.Parse( m_ruleSelectors, m_rules );
200  }
201  catch( PARSE_ERROR& pe )
202  {
203  // Don't leave possibly malformed stuff around for us to trip over
204  m_ruleSelectors.clear();
205  m_rules.clear();
206 
207  wxSafeYield( m_editFrame );
209  pe.lineNumber, pe.byteIndex );
210 
211  return false;
212  }
213  }
214  }
215 
216  std::reverse( std::begin( m_ruleSelectors ), std::end( m_ruleSelectors ) );
217 
220  bds.m_DRCRules = m_rules;
221 
222  return true;
223 }
224 
225 
226 void DRC::RunTests( wxTextCtrl* aMessages )
227 {
228  // Make absolutely sure these are up-to-date
229  if( !LoadRules() )
230  return;
231 
232  wxASSERT( m_pcb == m_editFrame->GetBoard() );
233 
234  BOARD_COMMIT commit( m_editFrame );
236 
238 
239  if( !bds.Ignore( DRCE_INVALID_OUTLINE )
240  || !bds.Ignore( DRCE_TRACK_NEAR_EDGE )
241  || !bds.Ignore( DRCE_VIA_NEAR_EDGE )
242  || !bds.Ignore( DRCE_PAD_NEAR_EDGE ) )
243  {
244  if( aMessages )
245  {
246  aMessages->AppendText( _( "Board Outline...\n" ) );
247  wxSafeYield();
248  }
249 
250  testOutline( commit );
251  }
252 
253  if( aMessages )
254  {
255  aMessages->AppendText( _( "Netclasses...\n" ) );
256  wxSafeYield();
257  }
258 
259  DRC_NETCLASS_TESTER netclassTester( [&]( MARKER_PCB* aMarker )
260  {
261  addMarkerToPcb( commit, aMarker );
262  } );
263 
264  if( !netclassTester.RunDRC( userUnits(), *m_pcb ) )
265  {
266  // testing the netclasses is a special case because if the netclasses
267  // do not pass the BOARD_DESIGN_SETTINGS checks, then every member of a net
268  // class (a NET) will cause its items such as tracks, vias, and pads
269  // to also fail. So quit after *all* netclass errors have been reported.
270  if( aMessages )
271  aMessages->AppendText( _( "NETCLASS VIOLATIONS: Aborting DRC\n" ) );
272 
273  commit.Push( wxEmptyString, false, false );
274 
275  // update the m_drcDialog listboxes
276  updatePointers();
277 
278  return;
279  }
280 
281  // test pad to pad clearances, nothing to do with tracks, vias or zones.
282  if( !bds.Ignore( DRCE_PAD_NEAR_EDGE )
283  || !bds.Ignore( DRCE_PAD_NEAR_PAD )
284  || !bds.Ignore( DRCE_HOLE_NEAR_PAD ) )
285  {
286  if( aMessages )
287  {
288  aMessages->AppendText( _( "Pad clearances...\n" ) );
289  wxSafeYield();
290  }
291 
292  testPadClearances( commit );
293  }
294 
295  // test drilled holes
300  {
301  if( aMessages )
302  {
303  aMessages->AppendText( _( "Drill sizes and clearances...\n" ) );
304  wxSafeYield();
305  }
306 
307  DRC_DRILLED_HOLE_TESTER tester( [&]( MARKER_PCB* aMarker )
308  {
309  addMarkerToPcb( commit, aMarker );
310  } );
311 
312  tester.RunDRC( userUnits(), *m_pcb );
313  }
314 
315  // caller (a wxTopLevelFrame) is the wxDialog or the Pcb Editor frame that call DRC:
316  wxWindow* caller = aMessages ? aMessages->GetParent() : m_editFrame;
317 
318  if( m_refillZones )
319  {
320  if( aMessages )
321  aMessages->AppendText( _( "Refilling all zones...\n" ) );
322 
323  m_toolMgr->GetTool<ZONE_FILLER_TOOL>()->FillAllZones( caller );
324  }
325  else
326  {
327  if( aMessages )
328  aMessages->AppendText( _( "Checking zone fills...\n" ) );
329 
330  m_toolMgr->GetTool<ZONE_FILLER_TOOL>()->CheckAllZones( caller );
331  }
332 
333  // test track and via clearances to other tracks, pads, and vias
334  if( aMessages )
335  {
336  aMessages->AppendText( _( "Track clearances...\n" ) );
337  wxSafeYield();
338  }
339 
340  testTracks( commit, aMessages ? aMessages->GetParent() : m_editFrame, true );
341 
342  // test zone clearances to other zones
343  if( aMessages )
344  {
345  aMessages->AppendText( _( "Zone to zone clearances...\n" ) );
346  wxSafeYield();
347  }
348 
349  testZones( commit );
350 
351  // find and gather unconnected pads.
353  && !bds.Ignore( DRCE_UNCONNECTED_ITEMS ) )
354  {
355  if( aMessages )
356  {
357  aMessages->AppendText( _( "Unconnected pads...\n" ) );
358  aMessages->Refresh();
359  }
360 
361  testUnconnected();
362  }
363 
364  // find and gather vias, tracks, pads inside keepout areas.
365  if( m_doKeepoutTest )
366  {
367  if( aMessages )
368  {
369  aMessages->AppendText( _( "Keepout areas ...\n" ) );
370  aMessages->Refresh();
371  }
372 
373  DRC_KEEPOUT_TESTER tester( [&]( MARKER_PCB* aMarker )
374  {
375  addMarkerToPcb( commit, aMarker );
376  } );
377 
378  tester.RunDRC( userUnits(), *m_pcb );
379  }
380 
381  // find and gather vias, tracks, pads inside text boxes.
382  if( !bds.Ignore( DRCE_VIA_NEAR_COPPER )
383  || !bds.Ignore( DRCE_TRACK_NEAR_COPPER ) )
384  {
385  if( aMessages )
386  {
387  aMessages->AppendText( _( "Text and graphic clearances...\n" ) );
388  wxSafeYield();
389  }
390 
391  testCopperTextAndGraphics( commit );
392  }
393 
394  // test courtyards
396  || !bds.Ignore( DRCE_MISSING_COURTYARD )
398  || !bds.Ignore( DRCE_PTH_IN_COURTYARD )
399  || !bds.Ignore( DRCE_NPTH_IN_COURTYARD ) )
400  {
401  if( aMessages )
402  {
403  aMessages->AppendText( _( "Courtyard areas...\n" ) );
404  aMessages->Refresh();
405  }
406 
407  DRC_COURTYARD_TESTER tester( [&]( MARKER_PCB* aMarker )
408  {
409  addMarkerToPcb( commit, aMarker );
410  } );
411 
412  tester.RunDRC( userUnits(), *m_pcb );
413  }
414 
415  for( DRC_ITEM* footprintItem : m_footprints )
416  delete footprintItem;
417 
418  m_footprints.clear();
419  m_footprintsTested = false;
420 
421  if( m_testFootprints && !Kiface().IsSingle() )
422  {
423  if( aMessages )
424  {
425  aMessages->AppendText( _( "Checking footprints against schematic...\n" ) );
426  aMessages->Refresh();
427  }
428 
429  NETLIST netlist;
431 
432  if( m_drcDialog )
433  m_drcDialog->Raise();
434 
435  TestFootprints( netlist, m_pcb, m_footprints );
436  m_footprintsTested = true;
437  }
438 
439  // Check if there are items on disabled layers
440  if( !bds.Ignore( DRCE_DISABLED_LAYER_ITEM ) )
441  {
442  if( aMessages )
443  {
444  aMessages->AppendText( _( "Items on disabled layers...\n" ) );
445  aMessages->Refresh();
446  }
447 
448  testDisabledLayers( commit );
449  }
450 
451  if( !bds.Ignore( DRCE_UNRESOLVED_VARIABLE ) )
452  {
453  if( aMessages )
454  {
455  aMessages->AppendText( _( "Unresolved text variables...\n" ) );
456  aMessages->Refresh();
457  }
458 
459  DRC_TEXTVAR_TESTER tester( [&]( MARKER_PCB* aMarker )
460  {
461  addMarkerToPcb( commit, aMarker );
462  },
464 
465  tester.RunDRC( userUnits(), *m_pcb );
466  }
467 
468  commit.Push( wxEmptyString, false, false );
469  m_drcRun = true;
470 
471  // update the m_drcDialog listboxes
472  updatePointers();
473 
474  if( aMessages )
475  {
476  // no newline on this one because it is last, don't want the window
477  // to unnecessarily scroll.
478  aMessages->AppendText( _( "Finished" ) );
479  }
480 }
481 
482 
484 {
485  // update my pointers, m_editFrame is the only unchangeable one
487 
489 
490  if( m_drcDialog ) // Use diag list boxes only in DRC dialog
491  {
494  &m_unconnected ) );
496  &m_footprints ) );
497  }
498 }
499 
500 
502 {
504  std::vector<D_PAD*> sortedPads;
505 
506  m_pcb->GetSortedPadListByXthenYCoord( sortedPads );
507 
508  if( sortedPads.empty() )
509  return;
510 
511  // find the max size of the pads (used to stop the pad-to-pad tests)
512  int max_size = 0;
513 
514  for( D_PAD* pad : sortedPads )
515  {
516  // GetBoundingRadius() is the radius of the minimum sized circle fully containing the pad
517  int radius = pad->GetBoundingRadius();
518 
519  if( radius > max_size )
520  max_size = radius;
521  }
522 
523  // Better to be fast than accurate; this keeps us from having to look up / calculate the
524  // actual clearances
525  max_size += m_largestClearance;
526 
527  // Upper limit of pad list (limit not included)
528  D_PAD** listEnd = &sortedPads[0] + sortedPads.size();
529 
530  // Test the pads
531  for( auto& pad : sortedPads )
532  {
534  {
535  int minClearance = bds.m_CopperEdgeClearance;
536  m_clearanceSource = _( "board edge" );
537 
538  static DRAWSEGMENT dummyEdge;
539  dummyEdge.SetLayer( Edge_Cuts );
540 
541  if( pad->GetRuleClearance( &dummyEdge, &minClearance, &m_clearanceSource ) )
542  /* minClearance and m_clearanceSource set in GetRuleClearance() */;
543 
544  for( auto it = m_board_outlines.IterateSegmentsWithHoles(); it; it++ )
545  {
546  int actual;
547 
548  if( !checkClearanceSegmToPad( *it, 0, pad, minClearance, &actual ) )
549  {
550  actual = std::max( 0, actual );
551  DRC_ITEM* drcItem = new DRC_ITEM( DRCE_PAD_NEAR_EDGE );
552 
553  m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
555  MessageTextFromValue( userUnits(), minClearance, true ),
556  MessageTextFromValue( userUnits(), actual, true ) );
557 
558  drcItem->SetErrorMessage( m_msg );
559  drcItem->SetItems( pad );
560 
561  MARKER_PCB* marker = new MARKER_PCB( drcItem, pad->GetPosition() );
562  addMarkerToPcb( aCommit, marker );
563 
564  break;
565  }
566  }
567  }
568 
569  if( !bds.Ignore( DRCE_PAD_NEAR_PAD ) || !bds.Ignore( DRCE_HOLE_NEAR_PAD ) )
570  {
571  int x_limit = pad->GetPosition().x + pad->GetBoundingRadius() + max_size;
572 
573  doPadToPadsDrc( aCommit, pad, &pad, listEnd, x_limit );
574  }
575  }
576 }
577 
578 
579 void DRC::testTracks( BOARD_COMMIT& aCommit, wxWindow *aActiveWindow, bool aShowProgressBar )
580 {
581  wxProgressDialog* progressDialog = NULL;
582  const int delta = 500; // This is the number of tests between 2 calls to the
583  // progress bar
584  int count = m_pcb->Tracks().size();
585  int deltamax = count/delta;
586 
587  if( aShowProgressBar && deltamax > 3 )
588  {
589  // Do not use wxPD_APP_MODAL style here: it is not necessary and create issues
590  // on OSX
591  progressDialog = new wxProgressDialog( _( "Track clearances" ), wxEmptyString,
592  deltamax, aActiveWindow,
593  wxPD_AUTO_HIDE | wxPD_CAN_ABORT | wxPD_ELAPSED_TIME );
594  progressDialog->Update( 0, wxEmptyString );
595  }
596 
597  std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_pcb->GetConnectivity();
599 
600 
603  {
604  connectivity->Clear();
605  connectivity->Build( m_pcb ); // just in case. This really needs to be reliable.
606  }
607 
608  int ii = 0;
609  count = 0;
610 
611  for( auto seg_it = m_pcb->Tracks().begin(); seg_it != m_pcb->Tracks().end(); seg_it++ )
612  {
613  if( ii++ > delta )
614  {
615  ii = 0;
616  count++;
617 
618  if( progressDialog )
619  {
620  if( !progressDialog->Update( count, wxEmptyString ) )
621  break; // Aborted by user
622 #ifdef __WXMAC__
623  // Work around a dialog z-order issue on OS X
624  if( count == deltamax )
625  aActiveWindow->Raise();
626 #endif
627  }
628  }
629 
630  // Test new segment against tracks and pads, optionally against copper zones
631  doTrackDrc( aCommit, *seg_it, seg_it + 1, m_pcb->Tracks().end(), m_testTracksAgainstZones );
632 
633  // Test for dangling items
634  int code = (*seg_it)->Type() == PCB_VIA_T ? DRCE_DANGLING_VIA : DRCE_DANGLING_TRACK;
635  wxPoint pos;
636 
637  if( !settings.Ignore( code ) && connectivity->TestTrackEndpointDangling( *seg_it, &pos ) )
638  {
639  DRC_ITEM* drcItem = new DRC_ITEM( code );
640  drcItem->SetItems( *seg_it );
641 
642  MARKER_PCB* marker = new MARKER_PCB( drcItem, pos );
643  addMarkerToPcb( aCommit, marker );
644  }
645  }
646 
647  if( progressDialog )
648  progressDialog->Destroy();
649 }
650 
651 
653 {
654  for( DRC_ITEM* unconnectedItem : m_unconnected )
655  delete unconnectedItem;
656 
657  m_unconnected.clear();
658 
659  auto connectivity = m_pcb->GetConnectivity();
660 
661  connectivity->Clear();
662  connectivity->Build( m_pcb ); // just in case. This really needs to be reliable.
663  connectivity->RecalculateRatsnest();
664 
665  std::vector<CN_EDGE> edges;
666  connectivity->GetUnconnectedEdges( edges );
667 
668  for( const CN_EDGE& edge : edges )
669  {
671  item->SetItems( edge.GetSourceNode()->Parent(), edge.GetTargetNode()->Parent() );
672  m_unconnected.push_back( item );
673  }
674 }
675 
676 
677 void DRC::testZones( BOARD_COMMIT& aCommit )
678 {
681 
682  // Test copper areas for valid netcodes
683  // if a netcode is < 0 the netname was not found when reading a netlist
684  // if a netcode is == 0 the netname is void, and the zone is not connected.
685  // This is allowed, but i am not sure this is a good idea
686  //
687  // In recent Pcbnew versions, the netcode is always >= 0, but an internal net name
688  // is stored, and initialized from the file or the zone properties editor.
689  // if it differs from the net name from net code, there is a DRC issue
690 
691  std::vector<SHAPE_POLY_SET> smoothed_polys;
692  smoothed_polys.resize( board->GetAreaCount() );
693 
694  for( int ii = 0; ii < m_pcb->GetAreaCount(); ii++ )
695  {
696  ZONE_CONTAINER* zone = m_pcb->GetArea( ii );
697 
698  if( !bds.Ignore( DRCE_ZONE_HAS_EMPTY_NET ) && zone->IsOnCopperLayer() )
699  {
700  int netcode = zone->GetNetCode();
701  // a netcode < 0 or > 0 and no pad in net is a error or strange
702  // perhaps a "dead" net, which happens when all pads in this net were removed
703  // Remark: a netcode < 0 should not happen (this is more a bug somewhere)
704  int pads_in_net = ( netcode > 0 ) ? m_pcb->GetConnectivity()->GetPadCount( netcode ) : 1;
705 
706  if( ( netcode < 0 ) || pads_in_net == 0 )
707  {
708  DRC_ITEM* drcItem = new DRC_ITEM( DRCE_ZONE_HAS_EMPTY_NET );
709  drcItem->SetItems( zone );
710 
711  MARKER_PCB* marker = new MARKER_PCB( drcItem, zone->GetPosition() );
712  addMarkerToPcb( aCommit, marker );
713  }
714  }
715 
716  ZONE_CONTAINER* zoneRef = board->GetArea( ii );
717  std::set<VECTOR2I> colinearCorners;
718  zoneRef->GetColinearCorners( board, colinearCorners );
719 
720  zoneRef->BuildSmoothedPoly( smoothed_polys[ii], &colinearCorners );
721  }
722 
723  // iterate through all areas
724  for( int ia = 0; ia < board->GetAreaCount(); ia++ )
725  {
726  ZONE_CONTAINER* zoneRef = board->GetArea( ia );
727 
728  if( !zoneRef->IsOnCopperLayer() )
729  continue;
730 
731  // If we are testing a single zone, then iterate through all other zones
732  // Otherwise, we have already tested the zone combination
733  for( int ia2 = ia + 1; ia2 < board->GetAreaCount(); ia2++ )
734  {
735  ZONE_CONTAINER* zoneToTest = board->GetArea( ia2 );
736 
737  if( zoneRef == zoneToTest )
738  continue;
739 
740  // test for same layer
741  if( zoneRef->GetLayer() != zoneToTest->GetLayer() )
742  continue;
743 
744  // Test for same net
745  if( zoneRef->GetNetCode() == zoneToTest->GetNetCode() && zoneRef->GetNetCode() >= 0 )
746  continue;
747 
748  // test for different priorities
749  if( zoneRef->GetPriority() != zoneToTest->GetPriority() )
750  continue;
751 
752  // test for different types
753  if( zoneRef->GetIsKeepout() != zoneToTest->GetIsKeepout() )
754  continue;
755 
756  // Examine a candidate zone: compare zoneToTest to zoneRef
757 
758  // Get clearance used in zone to zone test. The policy used to
759  // obtain that value is now part of the zone object itself by way of
760  // ZONE_CONTAINER::GetClearance().
761  int zone2zoneClearance = zoneRef->GetClearance( zoneToTest, &m_clearanceSource );
762 
763  // Keepout areas have no clearance, so set zone2zoneClearance to 1
764  // ( zone2zoneClearance = 0 can create problems in test functions)
765  if( zoneRef->GetIsKeepout() )
766  zone2zoneClearance = 1;
767 
768  // test for some corners of zoneRef inside zoneToTest
769  for( auto iterator = smoothed_polys[ia].IterateWithHoles(); iterator; iterator++ )
770  {
771  VECTOR2I currentVertex = *iterator;
772  wxPoint pt( currentVertex.x, currentVertex.y );
773 
774  if( smoothed_polys[ia2].Contains( currentVertex ) )
775  {
776  DRC_ITEM* drcItem = new DRC_ITEM( DRCE_ZONES_INTERSECT );
777  drcItem->SetItems( zoneRef, zoneToTest );
778 
779  MARKER_PCB* marker = new MARKER_PCB( drcItem, pt );
780  addMarkerToPcb( aCommit, marker );
781  }
782  }
783 
784  // test for some corners of zoneToTest inside zoneRef
785  for( auto iterator = smoothed_polys[ia2].IterateWithHoles(); iterator; iterator++ )
786  {
787  VECTOR2I currentVertex = *iterator;
788  wxPoint pt( currentVertex.x, currentVertex.y );
789 
790  if( smoothed_polys[ia].Contains( currentVertex ) )
791  {
792  DRC_ITEM* drcItem = new DRC_ITEM( DRCE_ZONES_INTERSECT );
793  drcItem->SetItems( zoneToTest, zoneRef );
794 
795  MARKER_PCB* marker = new MARKER_PCB( drcItem, pt );
796  addMarkerToPcb( aCommit, marker );
797  }
798  }
799 
800  // Iterate through all the segments of refSmoothedPoly
801  std::map<wxPoint, int> conflictPoints;
802 
803  for( auto refIt = smoothed_polys[ia].IterateSegmentsWithHoles(); refIt; refIt++ )
804  {
805  // Build ref segment
806  SEG refSegment = *refIt;
807 
808  // Iterate through all the segments in smoothed_polys[ia2]
809  for( auto testIt = smoothed_polys[ia2].IterateSegmentsWithHoles(); testIt; testIt++ )
810  {
811  // Build test segment
812  SEG testSegment = *testIt;
813  wxPoint pt;
814 
815  int ax1, ay1, ax2, ay2;
816  ax1 = refSegment.A.x;
817  ay1 = refSegment.A.y;
818  ax2 = refSegment.B.x;
819  ay2 = refSegment.B.y;
820 
821  int bx1, by1, bx2, by2;
822  bx1 = testSegment.A.x;
823  by1 = testSegment.A.y;
824  bx2 = testSegment.B.x;
825  by2 = testSegment.B.y;
826 
827  int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2,
828  0,
829  ax1, ay1, ax2, ay2,
830  0,
831  zone2zoneClearance,
832  &pt.x, &pt.y );
833 
834  if( d < zone2zoneClearance )
835  {
836  if( conflictPoints.count( pt ) )
837  conflictPoints[ pt ] = std::min( conflictPoints[ pt ], d );
838  else
839  conflictPoints[ pt ] = d;
840  }
841  }
842  }
843 
844  for( const std::pair<const wxPoint, int>& conflict : conflictPoints )
845  {
846  int actual = conflict.second;
847  DRC_ITEM* drcItem;
848 
849  if( actual <= 0 )
850  {
851  drcItem = new DRC_ITEM( DRCE_ZONES_INTERSECT );
852  }
853  else
854  {
855  drcItem = new DRC_ITEM( DRCE_ZONES_TOO_CLOSE );
856 
857  m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
859  MessageTextFromValue( userUnits(), zone2zoneClearance, true ),
860  MessageTextFromValue( userUnits(), conflict.second, true ) );
861 
862  drcItem->SetErrorMessage( m_msg );
863  }
864 
865  drcItem->SetItems( zoneRef, zoneToTest );
866 
867  MARKER_PCB* marker = new MARKER_PCB( drcItem, conflict.first );
868  addMarkerToPcb( aCommit, marker );
869  }
870  }
871  }
872 }
873 
874 
876 {
877  // Test copper items for clearance violations with vias, tracks and pads
878 
879  for( BOARD_ITEM* brdItem : m_pcb->Drawings() )
880  {
881  if( IsCopperLayer( brdItem->GetLayer() ) )
882  testCopperDrawItem( aCommit, brdItem );
883  }
884 
885  for( MODULE* module : m_pcb->Modules() )
886  {
887  TEXTE_MODULE& ref = module->Reference();
888  TEXTE_MODULE& val = module->Value();
889 
890  if( ref.IsVisible() && IsCopperLayer( ref.GetLayer() ) )
891  testCopperDrawItem( aCommit, &ref );
892 
893  if( val.IsVisible() && IsCopperLayer( val.GetLayer() ) )
894  testCopperDrawItem( aCommit, &val );
895 
896  if( module->IsNetTie() )
897  continue;
898 
899  for( BOARD_ITEM* item : module->GraphicalItems() )
900  {
901  if( IsCopperLayer( item->GetLayer() ) )
902  {
903  if( item->Type() == PCB_MODULE_TEXT_T && ( (TEXTE_MODULE*) item )->IsVisible() )
904  testCopperDrawItem( aCommit, item );
905  else if( item->Type() == PCB_MODULE_EDGE_T )
906  testCopperDrawItem( aCommit, item );
907  }
908  }
909  }
910 }
911 
912 
914 {
915  EDA_RECT bbox;
916  std::vector<SEG> itemShape;
917  int itemWidth;
918  DRAWSEGMENT* drawItem = dynamic_cast<DRAWSEGMENT*>( aItem );
919  EDA_TEXT* textItem = dynamic_cast<EDA_TEXT*>( aItem );
920 
921  if( drawItem )
922  {
923  bbox = drawItem->GetBoundingBox();
924  itemWidth = drawItem->GetWidth();
925 
926  switch( drawItem->GetShape() )
927  {
928  case S_ARC:
929  {
930  SHAPE_ARC arc( drawItem->GetCenter(), drawItem->GetArcStart(),
931  (double) drawItem->GetAngle() / 10.0 );
932 
933  SHAPE_LINE_CHAIN l = arc.ConvertToPolyline();
934 
935  for( int i = 0; i < l.SegmentCount(); i++ )
936  itemShape.push_back( l.Segment( i ) );
937 
938  break;
939  }
940 
941  case S_SEGMENT:
942  itemShape.emplace_back( SEG( drawItem->GetStart(), drawItem->GetEnd() ) );
943  break;
944 
945  case S_CIRCLE:
946  {
947  // SHAPE_CIRCLE has no ConvertToPolyline() method, so use a 360.0 SHAPE_ARC
948  SHAPE_ARC circle( drawItem->GetCenter(), drawItem->GetEnd(), 360.0 );
949 
950  SHAPE_LINE_CHAIN l = circle.ConvertToPolyline();
951 
952  for( int i = 0; i < l.SegmentCount(); i++ )
953  itemShape.push_back( l.Segment( i ) );
954 
955  break;
956  }
957 
958  case S_CURVE:
959  {
960  drawItem->RebuildBezierToSegmentsPointsList( drawItem->GetWidth() );
961  wxPoint start_pt = drawItem->GetBezierPoints()[0];
962 
963  for( unsigned int jj = 1; jj < drawItem->GetBezierPoints().size(); jj++ )
964  {
965  wxPoint end_pt = drawItem->GetBezierPoints()[jj];
966  itemShape.emplace_back( SEG( start_pt, end_pt ) );
967  start_pt = end_pt;
968  }
969 
970  break;
971  }
972 
973  case S_POLYGON:
974  {
975  SHAPE_LINE_CHAIN l = drawItem->GetPolyShape().Outline( 0 );
976 
977  for( int i = 0; i < l.SegmentCount(); i++ )
978  itemShape.push_back( l.Segment( i ) );
979  }
980  break;
981 
982  default:
983  wxFAIL_MSG( "unknown shape type" );
984  break;
985  }
986  }
987  else if( textItem )
988  {
989  bbox = textItem->GetTextBox();
990  itemWidth = textItem->GetEffectiveTextPenWidth();
991 
992  std::vector<wxPoint> textShape;
993  textItem->TransformTextShapeToSegmentList( textShape );
994 
995  for( unsigned jj = 0; jj < textShape.size(); jj += 2 )
996  itemShape.emplace_back( SEG( textShape[jj], textShape[jj+1] ) );
997  }
998  else
999  {
1000  wxFAIL_MSG( "unknown item type in testCopperDrawItem()" );
1001  return;
1002  }
1003 
1004  SHAPE_RECT rect_area( bbox.GetX(), bbox.GetY(), bbox.GetWidth(), bbox.GetHeight() );
1005 
1006  if( itemShape.empty() )
1007  return;
1008 
1009  // Test tracks and vias
1010  for( auto track : m_pcb->Tracks() )
1011  {
1012  if( !track->IsOnLayer( aItem->GetLayer() ) )
1013  continue;
1014 
1015  int minClearance = track->GetClearance( aItem, &m_clearanceSource );
1016  int widths = ( track->GetWidth() + itemWidth ) / 2;
1017  int center2centerAllowed = minClearance + widths;
1018 
1019  SEG trackSeg( track->GetStart(), track->GetEnd() );
1020 
1021  // Fast test to detect a track segment candidate inside the text bounding box
1022  if( !rect_area.Collide( trackSeg, center2centerAllowed ) )
1023  continue;
1024 
1025  OPT<SEG> minSeg;
1026  SEG::ecoord center2center_squared = 0;
1027 
1028  for( const SEG& itemSeg : itemShape )
1029  {
1030  SEG::ecoord thisDist_squared = trackSeg.SquaredDistance( itemSeg );
1031 
1032  if( !minSeg || thisDist_squared < center2center_squared )
1033  {
1034  minSeg = itemSeg;
1035  center2center_squared = thisDist_squared;
1036  }
1037  }
1038 
1039  if( center2center_squared < SEG::Square( center2centerAllowed ) )
1040  {
1041  int actual = std::max( 0.0, sqrt( center2center_squared ) - widths );
1042  int errorCode = ( track->Type() == PCB_VIA_T ) ? DRCE_VIA_NEAR_COPPER
1044  DRC_ITEM* drcItem = new DRC_ITEM( errorCode );
1045 
1046  m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
1048  MessageTextFromValue( userUnits(), minClearance, true ),
1049  MessageTextFromValue( userUnits(), actual, true ) );
1050 
1051  drcItem->SetErrorMessage( m_msg );
1052  drcItem->SetItems( track, aItem );
1053 
1054  wxPoint pos = GetLocation( track, minSeg.get() );
1055  MARKER_PCB* marker = new MARKER_PCB( drcItem, pos );
1056  addMarkerToPcb( aCommit, marker );
1057  }
1058  }
1059 
1060  // Test pads
1061  for( auto pad : m_pcb->GetPads() )
1062  {
1063  if( !pad->IsOnLayer( aItem->GetLayer() ) )
1064  continue;
1065 
1066  // Graphic items are allowed to act as net-ties within their own footprint
1067  if( drawItem && pad->GetParent() == drawItem->GetParent() )
1068  continue;
1069 
1070  int minClearance = pad->GetClearance( aItem, &m_clearanceSource );
1071  int widths = itemWidth / 2;
1072  int center2centerAllowed = minClearance + widths;
1073 
1074  // Fast test to detect a pad candidate inside the text bounding box
1075  // Finer test (time consumming) is made only for pads near the text.
1076  int bb_radius = pad->GetBoundingRadius() + minClearance;
1077  VECTOR2I shape_pos( pad->ShapePos() );
1078 
1079  if( !rect_area.Collide( SEG( shape_pos, shape_pos ), bb_radius ) )
1080  continue;
1081 
1082  SHAPE_POLY_SET padOutline;
1083  pad->TransformShapeWithClearanceToPolygon( padOutline, 0 );
1084 
1085  OPT<SEG> minSeg;
1086  SEG::ecoord center2center_squared = 0;
1087 
1088  for( const SEG& itemSeg : itemShape )
1089  {
1090  SEG::ecoord thisCenter2center_squared = padOutline.SquaredDistance( itemSeg );
1091 
1092  if( !minSeg || thisCenter2center_squared < center2center_squared )
1093  {
1094  minSeg = itemSeg;
1095  center2center_squared = thisCenter2center_squared;
1096  }
1097  }
1098 
1099  if( center2center_squared < SEG::Square( center2centerAllowed ) )
1100  {
1101  int actual = std::max( 0.0, sqrt( center2center_squared ) - widths );
1102  DRC_ITEM* drcItem = new DRC_ITEM( DRCE_PAD_NEAR_COPPER );
1103 
1104  m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
1106  MessageTextFromValue( userUnits(), minClearance, true ),
1107  MessageTextFromValue( userUnits(), actual, true ) );
1108 
1109  drcItem->SetErrorMessage( m_msg );
1110  drcItem->SetItems( pad, aItem );
1111 
1112  MARKER_PCB* marker = new MARKER_PCB( drcItem, pad->GetPosition() );
1113  addMarkerToPcb( aCommit, marker );
1114  }
1115  }
1116 }
1117 
1118 
1120 {
1122 
1124  m_board_outline_valid = false;
1125 
1126  if( m_pcb->GetBoardPolygonOutlines( m_board_outlines, nullptr, &error_loc ) )
1127  {
1128  m_board_outline_valid = true;
1129  }
1130  else
1131  {
1132  DRC_ITEM* drcItem = new DRC_ITEM( DRCE_INVALID_OUTLINE );
1133 
1134  m_msg.Printf( drcItem->GetErrorText() + _( " (not a closed shape)" ) );
1135 
1136  drcItem->SetErrorMessage( m_msg );
1137  drcItem->SetItems( m_pcb );
1138 
1139  MARKER_PCB* marker = new MARKER_PCB( drcItem, error_loc );
1140  addMarkerToPcb( aCommit, marker );
1141  }
1142 }
1143 
1144 
1146 {
1148  wxCHECK( board, /*void*/ );
1149 
1150  LSET disabledLayers = board->GetEnabledLayers().flip();
1151 
1152  // Perform the test only for copper layers
1153  disabledLayers &= LSET::AllCuMask();
1154 
1155  for( TRACK* track : board->Tracks() )
1156  {
1157  if( disabledLayers.test( track->GetLayer() ) )
1158  {
1159  DRC_ITEM* drcItem = new DRC_ITEM( DRCE_DISABLED_LAYER_ITEM );
1160 
1161  m_msg.Printf( drcItem->GetErrorText() + _( "layer %s" ),
1162  track->GetLayerName() );
1163 
1164  drcItem->SetErrorMessage( m_msg );
1165  drcItem->SetItems( track );
1166 
1167  MARKER_PCB* marker = new MARKER_PCB( drcItem, track->GetPosition() );
1168  addMarkerToPcb( aCommit, marker );
1169  }
1170  }
1171 
1172  for( MODULE* module : board->Modules() )
1173  {
1175  [&]( BOARD_ITEM* child )
1176  {
1177  if( disabledLayers.test( child->GetLayer() ) )
1178  {
1179  DRC_ITEM* drcItem = new DRC_ITEM( DRCE_DISABLED_LAYER_ITEM );
1180 
1181  m_msg.Printf( drcItem->GetErrorText() + _( "layer %s" ),
1182  child->GetLayerName() );
1183 
1184  drcItem->SetErrorMessage( m_msg );
1185  drcItem->SetItems( child );
1186 
1187  MARKER_PCB* marker = new MARKER_PCB( drcItem, child->GetPosition() );
1188  addMarkerToPcb( aCommit, marker );
1189  }
1190  } );
1191  }
1192 
1193  for( ZONE_CONTAINER* zone : board->Zones() )
1194  {
1195  if( disabledLayers.test( zone->GetLayer() ) )
1196  {
1197  DRC_ITEM* drcItem = new DRC_ITEM( DRCE_DISABLED_LAYER_ITEM );
1198 
1199  m_msg.Printf( drcItem->GetErrorText() + _( "layer %s" ),
1200  zone->GetLayerName() );
1201 
1202  drcItem->SetErrorMessage( m_msg );
1203  drcItem->SetItems( zone );
1204 
1205  MARKER_PCB* marker = new MARKER_PCB( drcItem, zone->GetPosition() );
1206  addMarkerToPcb( aCommit, marker );
1207  }
1208  }
1209 }
1210 
1211 
1212 bool DRC::doPadToPadsDrc( BOARD_COMMIT& aCommit, D_PAD* aRefPad, D_PAD** aStart, D_PAD** aEnd,
1213  int x_limit )
1214 {
1215  const static LSET all_cu = LSET::AllCuMask();
1216  constexpr int TOLERANCE = 1; // 1nm tolerance for rotated pad rounding errors.
1217 
1218  LSET layerMask = aRefPad->GetLayerSet() & all_cu;
1219 
1220  /* used to test DRC pad to holes: this dummy pad has the size and shape of the hole
1221  * to test pad to pad hole DRC, using the pad to pad DRC test function.
1222  * Therefore, this dummy pad is a circle or an oval.
1223  * A pad must have a parent because some functions expect a non null parent
1224  * to find the parent board, and some other data
1225  */
1226  MODULE dummymodule( m_pcb ); // Creates a dummy parent
1227  D_PAD dummypad( &dummymodule );
1228 
1229  // Ensure the hole is on all copper layers
1230  dummypad.SetLayerSet( all_cu | dummypad.GetLayerSet() );
1231 
1232  for( D_PAD** pad_list = aStart; pad_list<aEnd; ++pad_list )
1233  {
1234  D_PAD* pad = *pad_list;
1235 
1236  if( pad == aRefPad )
1237  continue;
1238 
1239  // We can stop the test when pad->GetPosition().x > x_limit
1240  // because the list is sorted by X values
1241  if( pad->GetPosition().x > x_limit )
1242  break;
1243 
1244  // No problem if pads which are on copper layers are on different copper layers,
1245  // (pads can be only on a technical layer, to build complex pads)
1246  // but their hole (if any ) can create DRC error because they are on all
1247  // copper layers, so we test them
1248  if( ( pad->GetLayerSet() & layerMask ) == 0 &&
1249  ( pad->GetLayerSet() & all_cu ) != 0 &&
1250  ( aRefPad->GetLayerSet() & all_cu ) != 0 )
1251  {
1252  // if holes are in the same location and have the same size and shape,
1253  // this can be accepted
1254  if( pad->GetPosition() == aRefPad->GetPosition()
1255  && pad->GetDrillSize() == aRefPad->GetDrillSize()
1256  && pad->GetDrillShape() == aRefPad->GetDrillShape() )
1257  {
1258  if( aRefPad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
1259  continue;
1260 
1261  // for oval holes: must also have the same orientation
1262  if( pad->GetOrientation() == aRefPad->GetOrientation() )
1263  continue;
1264  }
1265 
1266  /* Here, we must test clearance between holes and pads
1267  * dummy pad size and shape is adjusted to pad drill size and shape
1268  */
1269  if( pad->GetDrillSize().x )
1270  {
1271  // pad under testing has a hole, test this hole against pad reference
1272  dummypad.SetPosition( pad->GetPosition() );
1273  dummypad.SetSize( pad->GetDrillSize() );
1274  dummypad.SetShape( pad->GetDrillShape() == PAD_DRILL_SHAPE_OBLONG ?
1276  dummypad.SetOrientation( pad->GetOrientation() );
1277 
1278  int minClearance = aRefPad->GetClearance( nullptr, &m_clearanceSource );
1279  int actual;
1280 
1281  if( !checkClearancePadToPad( aRefPad, &dummypad, minClearance, &actual ) )
1282  {
1283  DRC_ITEM* drcItem = new DRC_ITEM( DRCE_HOLE_NEAR_PAD );
1284 
1285  m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
1287  MessageTextFromValue( userUnits(), minClearance, true ),
1288  MessageTextFromValue( userUnits(), actual, true ) );
1289 
1290  drcItem->SetErrorMessage( m_msg );
1291  drcItem->SetItems( pad, aRefPad );
1292 
1293  MARKER_PCB* marker = new MARKER_PCB( drcItem, pad->GetPosition() );
1294  addMarkerToPcb( aCommit, marker );
1295  return false;
1296  }
1297  }
1298 
1299  if( aRefPad->GetDrillSize().x ) // pad reference has a hole
1300  {
1301  dummypad.SetPosition( aRefPad->GetPosition() );
1302  dummypad.SetSize( aRefPad->GetDrillSize() );
1303  dummypad.SetShape( aRefPad->GetDrillShape() == PAD_DRILL_SHAPE_OBLONG ?
1305  dummypad.SetOrientation( aRefPad->GetOrientation() );
1306 
1307  int minClearance = pad->GetClearance( nullptr, &m_clearanceSource );
1308  int actual;
1309 
1310  if( !checkClearancePadToPad( pad, &dummypad, minClearance, &actual ) )
1311  {
1312  DRC_ITEM* drcItem = new DRC_ITEM( DRCE_HOLE_NEAR_PAD );
1313 
1314  m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
1316  MessageTextFromValue( userUnits(), minClearance, true ),
1317  MessageTextFromValue( userUnits(), actual, true ) );
1318 
1319  drcItem->SetErrorMessage( m_msg );
1320  drcItem->SetItems( aRefPad, pad );
1321 
1322  MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefPad->GetPosition() );
1323  addMarkerToPcb( aCommit, marker );
1324  return false;
1325  }
1326  }
1327 
1328  continue;
1329  }
1330 
1331  // The pad must be in a net (i.e pt_pad->GetNet() != 0 ),
1332  // But no problem if pads have the same netcode (same net)
1333  if( pad->GetNetCode() && ( aRefPad->GetNetCode() == pad->GetNetCode() ) )
1334  continue;
1335 
1336  // if pads are from the same footprint
1337  if( pad->GetParent() == aRefPad->GetParent() )
1338  {
1339  // and have the same pad number ( equivalent pads )
1340 
1341  // one can argue that this 2nd test is not necessary, that any
1342  // two pads from a single module are acceptable. This 2nd test
1343  // should eventually be a configuration option.
1344  if( pad->PadNameEqual( aRefPad ) )
1345  continue;
1346  }
1347 
1348  // if either pad has no drill and is only on technical layers, not a clearance violation
1349  if( ( ( pad->GetLayerSet() & layerMask ) == 0 && !pad->GetDrillSize().x ) ||
1350  ( ( aRefPad->GetLayerSet() & layerMask ) == 0 && !aRefPad->GetDrillSize().x ) )
1351  {
1352  continue;
1353  }
1354 
1355  int minClearance = aRefPad->GetClearance( pad, &m_clearanceSource ) - TOLERANCE;
1356  int actual;
1357 
1358  if( !checkClearancePadToPad( aRefPad, pad, minClearance, &actual ) )
1359  {
1360  DRC_ITEM* drcItem = new DRC_ITEM( DRCE_PAD_NEAR_PAD );
1361 
1362  m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
1364  MessageTextFromValue( userUnits(), minClearance, true ),
1365  MessageTextFromValue( userUnits(), actual, true ) );
1366 
1367  drcItem->SetErrorMessage( m_msg );
1368  drcItem->SetItems( aRefPad, pad );
1369 
1370  MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefPad->GetPosition() );
1371  addMarkerToPcb( aCommit, marker );
1372  return false;
1373  }
1374  }
1375 
1376  return true;
1377 }
1378 
1379 
1381 {
1382  Go( &DRC::ShowDRCDialog, PCB_ACTIONS::runDRC.MakeEvent() );
1383 }
1384 
1385 
1386 const int EPSILON = Mils2iu( 5 );
1387 
1388 
1389 wxPoint DRC::GetLocation( TRACK* aTrack, ZONE_CONTAINER* aConflictZone )
1390 {
1391  SHAPE_POLY_SET* conflictOutline;
1392 
1393  if( aConflictZone->IsFilled() )
1394  conflictOutline = const_cast<SHAPE_POLY_SET*>( &aConflictZone->GetFilledPolysList() );
1395  else
1396  conflictOutline = aConflictZone->Outline();
1397 
1398  wxPoint pt1 = aTrack->GetPosition();
1399  wxPoint pt2 = aTrack->GetEnd();
1400 
1401  // If the mid-point is in the zone, then that's a fine place for the marker
1402  if( conflictOutline->SquaredDistance( ( pt1 + pt2 ) / 2 ) == 0 )
1403  return ( pt1 + pt2 ) / 2;
1404 
1405  // Otherwise do a binary search for a "good enough" marker location
1406  else
1407  {
1408  while( GetLineLength( pt1, pt2 ) > EPSILON )
1409  {
1410  if( conflictOutline->SquaredDistance( pt1 ) < conflictOutline->SquaredDistance( pt2 ) )
1411  pt2 = ( pt1 + pt2 ) / 2;
1412  else
1413  pt1 = ( pt1 + pt2 ) / 2;
1414  }
1415 
1416  // Once we're within EPSILON pt1 and pt2 are "equivalent"
1417  return pt1;
1418  }
1419 }
1420 
1421 
1422 wxPoint DRC::GetLocation( TRACK* aTrack, const SEG& aConflictSeg )
1423 {
1424  wxPoint pt1 = aTrack->GetPosition();
1425  wxPoint pt2 = aTrack->GetEnd();
1426 
1427  // Do a binary search along the track for a "good enough" marker location
1428  while( GetLineLength( pt1, pt2 ) > EPSILON )
1429  {
1430  if( aConflictSeg.SquaredDistance( pt1 ) < aConflictSeg.SquaredDistance( pt2 ) )
1431  pt2 = ( pt1 + pt2 ) / 2;
1432  else
1433  pt1 = ( pt1 + pt2 ) / 2;
1434  }
1435 
1436  // Once we're within EPSILON pt1 and pt2 are "equivalent"
1437  return pt1;
1438 }
1439 
1440 
bool m_refillZones
Definition: drc.h:164
static TOOL_ACTION selectionClear
Clears the current selection.
Definition: pcb_actions.h:62
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Function AllCuMask returns a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:712
std::vector< DRC_ITEM * > m_footprints
Definition: drc.h:175
copper area outlines intersect
Definition: drc.h:59
ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:60
bool IsFilled() const
Definition: class_zone.h:175
TEXTE_MODULE & Reference()
Definition: class_module.h:481
void DestroyDRCDialog(int aReason)
Deletes this ui dialog box and zeros out its pointer to remember the state of the dialog's existence.
int GetNetCode() const
Function GetNetCode.
RATSNEST_DRC_ITEMS_PROVIDER.
Definition: drc_provider.h:271
double GetLineLength(const wxPoint &aPointA, const wxPoint &aPointB)
Return the length of a line segment defined by aPointA and aPointB.
Definition: trigo.h:206
void RunOnChildren(const std::function< void(BOARD_ITEM *)> &aFunction)
Function RunOnChildren.
void doTrackDrc(BOARD_COMMIT &aCommit, TRACK *aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterator aEndIt, bool aTestZones)
Test the current segment.
TEXTE_PCB class definition.
BOARD * board() const
overlapping drilled holes break drill bits
Definition: drc.h:66
RC_ITEM * GetRCItem()
Function GetReporter returns the DRC_ITEM held within this MARKER so that its interface may be used.
Definition: marker_base.h:117
SEGMENT_ITERATOR IterateSegmentsWithHoles()
Returns an iterator object, for all outlines in the set (with holes)
wxString m_msg
Definition: drc.h:186
bool RunDRC(EDA_UNITS aUnits, BOARD &aBoard) override
Runs this provider against the given PCB with configured options (if any).
bool checkClearancePadToPad(D_PAD *aRefPad, D_PAD *aPad, int aMinClearance, int *aActual)
virtual void SetLayer(PCB_LAYER_ID aLayer)
Function SetLayer sets the layer this item is on.
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
const wxPoint GetCenter() const override
Function GetCenter()
pad too close to pad
Definition: drc.h:57
int GetBiggestClearanceValue()
Function GetBiggestClearanceValue.
int GetX() const
Definition: eda_rect.h:111
COMMIT & Add(EDA_ITEM *aItem)
Adds a new item to the model
Definition: commit.h:78
const EDA_RECT GetBoardEdgesBoundingBox() const
Function GetBoardEdgesBoundingBox Returns the board bounding box calculated using exclusively the boa...
Definition: class_board.h:785
STROKE_T GetShape() const
void setTransitions() override
Sets up handlers for various events.
void testTracks(BOARD_COMMIT &aCommit, wxWindow *aActiveWindow, bool aShowProgressBar)
Perform the DRC on all tracks.
int m_largestClearance
Definition: drc.h:188
bool IsVisible() const
Definition: eda_text.h:185
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
void ResolveDRCExclusions()
Update markers to match recorded exclusions.
std::vector< DRC_SELECTOR * > m_DRCRuleSelectors
polygon (not yet used for tracks, but could be in microwave apps)
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:219
VECTOR2I::extended_type ecoord
Definition: seg.h:42
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:217
bool Ignore(int aDRCErrorCode)
returns true if the DRC error code's severity is SEVERITY_IGNORE
void RebuildBezierToSegmentsPointsList(int aMinSegLen)
Rebuild the m_BezierPoints vertex list that approximate the Bezier curve by a list of segments Has me...
void GetSortedPadListByXthenYCoord(std::vector< D_PAD * > &aVector, int aNetCode=-1)
Function GetSortedPadListByXthenYCoord first empties then fills the vector with all pads and sorts th...
virtual PCB_LAYER_ID GetLayer() const override
Function GetLayer returns the primary layer this item is on.
Definition: class_zone.cpp:219
int GetWidth() const
Definition: eda_rect.h:119
SHAPE_POLY_SET * Outline()
Definition: class_zone.h:252
bool PadNameEqual(const D_PAD *other) const
Definition: class_pad.h:213
void testCopperTextAndGraphics(BOARD_COMMIT &aCommit)
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:139
void testZones(BOARD_COMMIT &aCommit)
void SetPosition(const wxPoint &aPos) override
Definition: class_pad.h:225
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:542
footprint has a courtyard but malformed (not convertible to a closed polygon with holes)
Definition: drc.h:97
void ShowDRCDialog(wxWindow *aParent)
Open a dialog and prompts the user, then if a test run button is clicked, runs the test(s) and create...
usual segment : line with rounded ends
EDA_UNITS userUnits() const
Definition: drc.h:199
bool doPadToPadsDrc(BOARD_COMMIT &aCommit, D_PAD *aRefPad, D_PAD **aStart, D_PAD **aEnd, int x_limit)
Test the clearance between aRefPad and other pads.
ecoord SquaredDistance(const SEG &aSeg) const
Definition: seg.cpp:88
LSET GetEnabledLayers() const
Function GetEnabledLayers is a proxy function that calls the corresponding function in m_BoardSetting...
const std::vector< wxPoint > & GetBezierPoints() const
via and copper graphic collide or are too close
Definition: drc.h:50
DRAWINGS & GraphicalItems()
Definition: class_module.h:179
const int EPSILON
void Parse(std::vector< DRC_SELECTOR * > &aSelectors, std::vector< DRC_RULE * > &aRules)
const wxPoint & GetEnd() const
Function GetEnd returns the ending point of the graphic.
static SEG::ecoord Square(int a)
Definition: seg.h:116
const wxPoint GetPosition() const override
Definition: class_zone.cpp:213
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Function Go()
class EDGE_MODULE, a footprint edge
Definition: typeinfo.h:94
bool RunDRC(EDA_UNITS aUnits, BOARD &aBoard) override
Runs this provider against the given PCB with configured options (if any).
A single base class (TRACK) represents both tracks and vias, with subclasses for curved tracks (ARC) ...
int GetEffectiveTextPenWidth(int aDefaultWidth=0) const
The EffectiveTextPenWidth uses the text thickness if > 1 or aDefaultWidth.
Definition: eda_text.cpp:152
VTBL_ENTRY const wxString AbsolutePath(const wxString &aFileName) const
Function AbsolutePath fixes up aFileName if it is relative to the project's directory to be an absolu...
Definition: project.cpp:447
void TestFootprints(NETLIST &aNetlist, BOARD *aBoard, std::vector< DRC_ITEM * > &aDRCList)
wxString m_clearanceSource
Definition: drc.h:187
BOARD * m_pcb
Definition: drc.h:169
virtual const wxPoint GetPosition() const
Definition: base_struct.h:344
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:112
void testCopperDrawItem(BOARD_COMMIT &aCommit, BOARD_ITEM *aDrawing)
void GetColinearCorners(BOARD *aBoard, std::set< VECTOR2I > &colinearCorners)
Some intersecting zones, despite being on the same layer with the same net, cannot be merged due to o...
track too close to board edge
Definition: drc.h:54
bool IsNetTie() const
Definition: class_module.h:270
void Reset(RESET_REASON aReason) override
Function Reset() Brings the tool to a known, initial state.
bool m_testFootprints
Definition: drc.h:166
bool m_doKeepoutTest
Definition: drc.h:163
ZONE_FILLER_TOOL.
int GetAreaCount() const
Function GetAreaCount.
Definition: class_board.h:927
LSET is a set of PCB_LAYER_IDs.
NETLIST stores all of information read from a netlist along with the flags used to update the NETLIST...
Definition: pcb_netlist.h:212
#define NULL
const wxPoint GetPosition() const override
Definition: class_track.h:108
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
MODULES & Modules()
Definition: class_board.h:256
PCB_EDIT_FRAME * m_editFrame
Definition: drc.h:168
BOARD_DRC_ITEMS_PROVIDER is an implementation of the RC_ITEMS_PROVIDER interface which uses a BOARD i...
Definition: drc_provider.h:82
int lineNumber
at which line number, 1 based index.
Definition: ki_exception.h:125
SHAPE_POLY_SET.
TEXTE_MODULE & Value()
read/write accessors:
Definition: class_module.h:480
SHAPE_LINE_CHAIN & Outline(int aIndex)
Returns the reference to aIndex-th outline in the set
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
bool BuildSmoothedPoly(SHAPE_POLY_SET &aSmoothedPoly, std::set< VECTOR2I > *aPreserveCorners) const
Function GetSmoothedPoly returns a pointer to the corner-smoothed version of m_Poly.
track with at least one end not connected to anything
Definition: drc.h:63
item on a disabled layer
Definition: drc.h:101
const wxPoint GetPosition() const
Definition: eda_rect.h:115
Arcs (with rounded ends)
void updatePointers()
Update needed pointers from the one pointer which is known not to change.
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
PAD_DRILL_SHAPE_T GetDrillShape() const
Definition: class_pad.h:417
TOOL_EVENT.
Definition: tool_event.h:171
LSET GetLayerSet() const override
Function GetLayerSet returns a "layer mask", which is a bitmap of all layers on which the TRACK segme...
Definition: class_pad.h:435
invalid board outline
Definition: drc.h:102
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Function GetConnectivity() returns list of missing connections between components/tracks.
Definition: class_board.h:335
int GetErrorCode() const
Definition: rc_item.h:138
void SetFootprintsProvider(RC_ITEMS_PROVIDER *aProvider)
Definition: dialog_drc.cpp:229
void addMarkerToPcb(BOARD_COMMIT &aCommit, MARKER_PCB *aMarker)
Adds a DRC marker to the PCB through the COMMIT mechanism.
void TransformTextShapeToSegmentList(std::vector< wxPoint > &aCornerBuffer) const
Convert the text shape to a list of segment.
Definition: eda_text.cpp:578
Too small via drill.
Definition: drc.h:72
void SetSize(const wxSize &aSize)
Definition: class_pad.h:284
friend class DIALOG_DRC
Definition: drc.h:151
std::vector< DRC_ITEM * > m_unconnected
Definition: drc.h:174
copper area has a net but no pads in nets, which is suspicious
Definition: drc.h:61
const wxPoint & GetArcStart() const
bool GetBoardPolygonOutlines(SHAPE_POLY_SET &aOutlines, wxString *aErrorText=nullptr, wxPoint *aErrorLocation=nullptr)
Function GetBoardPolygonOutlines Extracts the board outlines and build a closed polygon from lines,...
bool m_reportAllTrackErrors
Definition: drc.h:165
SHAPE_POLY_SET & GetPolyShape()
via too close to board edge
Definition: drc.h:55
Bezier Curve.
bool m_drcRun
Definition: drc.h:176
bool LoadRules()
Load the DRC rules.
Too small micro via drill.
Definition: drc.h:77
int SegmentCount() const
Function SegmentCount()
int GetHeight() const
Definition: eda_rect.h:120
bool Show(bool show) override
int GetWidth() const
bool GetIsKeepout() const
Accessors to parameters used in Keepout zones:
Definition: class_zone.h:661
Pad object description.
bool m_testTracksAgainstZones
Definition: drc.h:162
bool m_footprintsTested
Definition: drc.h:177
MODULE * GetParent() const
Definition: class_pad.h:164
virtual int GetClearance(BOARD_ITEM *aItem=nullptr, wxString *aSource=nullptr) const
Function GetClearance returns the clearance in internal units.
class TEXTE_MODULE, text in a footprint
Definition: typeinfo.h:93
bool m_board_outline_valid
Definition: drc.h:171
Definition: seg.h:39
wxString MessageTextFromValue(EDA_UNITS aUnits, int aValue, bool aUseMils, EDA_DATA_TYPE aType)
Definition: base_units.cpp:124
void SetMarkersProvider(RC_ITEMS_PROVIDER *aProvider)
Definition: dialog_drc.cpp:213
Too small via drill.
Definition: drc.h:71
const std::vector< D_PAD * > GetPads()
Function GetPads returns a reference to a list of all the pads.
double GetAngle() const
wxString GetErrorText(int aErrorCode=-1, bool aTranslate=true) const override
Function GetErrorText returns the string form of a drc error code.
Definition: drc_item.cpp:54
void SetLayerSet(LSET aLayerMask)
Definition: class_pad.h:434
std::vector< DRC_SELECTOR * > m_ruleSelectors
Definition: drc.h:179
SEG Segment(int aIndex)
Function Segment()
bool RunDRC(EDA_UNITS aUnits, BOARD &aBoard) override
Runs this provider against the given PCB with configured options (if any).
SHAPE_POLY_SET m_board_outlines
Definition: drc.h:170
Struct PARSE_ERROR contains a filename or source description, a problem input line,...
Definition: ki_exception.h:123
pad and copper graphic collide or are too close
Definition: drc.h:58
ZONE_CONTAINERS & Zones()
Definition: class_board.h:270
unsigned GetPriority() const
Function GetPriority.
Definition: class_zone.h:100
track & copper graphic collide or are too close
Definition: drc.h:47
KIGFX::WS_PROXY_VIEW_ITEM * GetWorksheet() const
Class to handle a graphic segment.
#define ID_RULES_EDITOR
BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:181
MODULE * module() const
#define _(s)
Definition: 3d_actions.cpp:33
SHAPE_LINE_CHAIN.
double GetOrientation() const
Function GetOrientation returns the rotation angle of the pad in tenths of degrees,...
Definition: class_pad.h:411
footprint has no courtyard defined
Definition: drc.h:96
void RemoveAllContours()
Removes all outlines & holes (clears) the polygon set.
const wxSize & GetDrillSize() const
Definition: class_pad.h:291
VECTOR2I A
Definition: seg.h:47
EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
items are unconnected
Definition: drc.h:42
static TOOL_ACTION runDRC
Definition: pcb_actions.h:318
int GetY() const
Definition: eda_rect.h:112
hole too close to pad
Definition: drc.h:64
footprint courtyards overlap
Definition: drc.h:95
void SetShape(PAD_SHAPE_T aShape)
Definition: class_pad.h:223
RESET_REASON
Determines the reason of reset for a tool
Definition: tool_base.h:79
const wxPoint & GetEnd() const
Definition: class_track.h:115
int byteIndex
at which byte offset within the line, 1 based index
Definition: ki_exception.h:126
boost::optional< T > OPT
Definition: optional.h:7
void SetOrientation(double aAngle)
Function SetOrientation sets the rotation angle of the pad.
Definition: class_pad.cpp:469
void testPadClearances(BOARD_COMMIT &aCommit)
bool IsCopperLayer(LAYER_NUM aLayerId)
Function IsCopperLayer tests whether a layer is a copper layer.
void Activate()
Function Activate() Runs the tool.
void testDisabledLayers(BOARD_COMMIT &aCommit)
void SetErrorMessage(const wxString &aMessage)
Definition: rc_item.h:107
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
const wxPoint & GetStart() const
Function GetStart returns the starting point of the graphic.
bool IsDRCDialogShown()
Check to see if the DRC dialog is currently shown.
DIALOG_DRC * m_drcDialog
Definition: drc.h:172
ZONE_CONTAINER * GetArea(int index) const
Function GetArea returns the Area (Zone Container) at a given index.
Definition: class_board.h:892
BOARD * GetBoard() const
static wxPoint GetLocation(TRACK *aTrack, ZONE_CONTAINER *aConflictZone)
Fetches a reasonable point for marking a violoation between two non-point objects.
via which isn't connected to anything
Definition: drc.h:62
void SetItems(EDA_ITEM *aItem, EDA_ITEM *bItem=nullptr)
Definition: rc_item.h:109
copper area outlines are too close
Definition: drc.h:60
SEG::ecoord SquaredDistance(VECTOR2I aPoint)
Function SquaredDistance computes the minimum distance squared between aPoint and all the polygons in...
const wxPoint GetPosition() const override
Definition: class_pad.h:226
EDGE_MODULE class definition.
void testUnconnected()
void RunTests(wxTextCtrl *aMessages=NULL)
Run all the tests specified with a previous call to SetSettings()
BOARD_ITEM_CONTAINER * GetParent() const
void testOutline(BOARD_COMMIT &aCommit)
Test that the board outline is contiguous and composed of valid elements.
wxString GetLayerName() const
Function GetLayerName returns the name of the PCB layer on which the item resides.
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
DRAWINGS & Drawings()
Definition: class_board.h:265
std::vector< DRC_RULE * > m_DRCRules
void ShowBoardSetupDialog(const wxString &aInitialPage=wxEmptyString, const wxString &aErrorMsg=wxEmptyString, int aErrorCtrlId=-1, int aErrorLine=-1, int aErrorCol=-1)
Function ShowBoardSetupDialog.
VECTOR_DRC_ITEMS_PROVIDER is an implementation of the interface named DRC_ITEMS_PROVIDER which uses a...
Definition: drc_provider.h:174
void SetUnconnectedProvider(RC_ITEMS_PROVIDER *aProvider)
Definition: dialog_drc.cpp:221
bool FetchNetlistFromSchematic(NETLIST &aNetlist, FETCH_NETLIST_MODE aMode)
TRACKS & Tracks()
Definition: class_board.h:247
bool m_doUnconnectedTest
Definition: drc.h:161
bool IsOnCopperLayer() const override
Function IsOnCopperLayer.
Definition: class_zone.cpp:225
bool RunDRC(EDA_UNITS aUnits, BOARD &aBoard) override
Runs this provider against the given PCB with configured options (if any).
std::vector< DRC_RULE * > m_rules
Definition: drc.h:180
bool checkClearanceSegmToPad(const SEG &seg, int segWidth, const D_PAD *pad, int minClearance, int *aActualDist)
Check the distance from a pad to segment.
pad too close to board edge
Definition: drc.h:56
const SHAPE_POLY_SET & GetFilledPolysList() const
Function GetFilledPolysList returns a reference to the list of filled polygons.
Definition: class_zone.h:575
BOARD_DESIGN_SETTINGS contains design settings for a BOARD object.
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes.
VECTOR2I B
Definition: seg.h:48