KiCad PCB EDA Suite
board_inspection_tool.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) 2019-2021 KiCad Developers, see AUTHORS.txt for contributors.
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 <bitmaps.h>
25 #include <pcb_group.h>
26 #include <tool/tool_manager.h>
28 #include <tools/pcb_picker_tool.h>
29 #include <tools/edit_tool.h>
30 #include <pcb_painter.h>
33 #include <drc/drc_engine.h>
36 #include <string_utils.h>
37 #include "board_inspection_tool.h"
38 #include <pcbnew_settings.h>
40 #include <drc/drc_item.h>
41 #include <pad.h>
42 
43 
45  PCB_TOOL_BASE( "pcbnew.InspectionTool" ),
46  m_frame( nullptr )
47 {
48  m_probingSchToPcb = false;
49  m_dynamicData = nullptr;
50 }
51 
52 
54 {
55 public:
57  {
59  SetTitle( _( "Net Tools" ) );
60 
65  }
66 
67 private:
68  ACTION_MENU* create() const override
69  {
70  return new NET_CONTEXT_MENU();
71  }
72 };
73 
74 
76 {
78 
79  auto netSubMenu = std::make_shared<NET_CONTEXT_MENU>();
80  netSubMenu->SetTool( this );
81 
82  static KICAD_T connectedTypes[] = { PCB_TRACE_T, PCB_VIA_T, PCB_ARC_T, PCB_PAD_T, PCB_ZONE_T,
83  EOT };
84 
85  CONDITIONAL_MENU& menu = selectionTool->GetToolMenu().GetMenu();
86 
87  selectionTool->GetToolMenu().AddSubMenu( netSubMenu );
88 
89  menu.AddMenu( netSubMenu.get(), SELECTION_CONDITIONS::OnlyTypes( connectedTypes ), 200 );
91 
92  return true;
93 }
94 
95 
97 {
98  m_frame = getEditFrame<PCB_EDIT_FRAME>();
99 }
100 
101 
103 {
105  dialog.ShowModal();
106  return 0;
107 }
108 
109 
111 {
112  // Null items have no description
113  if( !aItem )
114  return wxString();
115 
116  wxString s = aItem->GetSelectMenuText( m_frame->GetUserUnits() );
117 
118  if( aItem->IsConnected() )
119  {
120  BOARD_CONNECTED_ITEM* cItem = static_cast<BOARD_CONNECTED_ITEM*>( aItem );
121  s += wxS( " " ) + wxString::Format( _( "[netclass %s]" ),
122  cItem->GetNetClass()->GetName() );
123  }
124 
125  return s;
126 };
127 
128 
130 {
131  r->Report( "" );
132  r->Report( _( "Report incomplete: could not compile custom design rules. " )
133  + "<a href='boardsetup'>" + _( "Show design rules." ) + "</a>" );
134 }
135 
136 
138  BOARD_ITEM* aA, BOARD_ITEM* aB, REPORTER* r )
139 {
140  r->Report( "" );
141 
143 
144  try
145  {
146  drcEngine.InitEngine( m_frame->GetDesignRulesPath() );
147  }
148  catch( PARSE_ERROR& )
149  {
151  return;
152  }
153 
154  for( ZONE* zone : m_frame->GetBoard()->Zones() )
155  zone->CacheBoundingBox();
156 
158  {
159  for( ZONE* zone : footprint->Zones() )
160  zone->CacheBoundingBox();
161 
163  }
164 
165  DRC_CONSTRAINT constraint = drcEngine.EvalRules( aClearanceType, aA, aB, aLayer, r );
166  int clearance = constraint.m_Value.Min();
167  wxString clearanceStr = StringFromValue( r->GetUnits(), clearance, true );
168 
169  r->Report( "" );
170  r->Report( wxString::Format( _( "Resolved clearance: %s." ), clearanceStr ) );
171 }
172 
173 
174 void BOARD_INSPECTION_TOOL::InspectDRCError( const std::shared_ptr<RC_ITEM>& aDRCItem )
175 {
176  BOARD_ITEM* a = m_frame->GetBoard()->GetItem( aDRCItem->GetMainItemID() );
177  BOARD_ITEM* b = m_frame->GetBoard()->GetItem( aDRCItem->GetAuxItemID() );
179 
180  if( !a || !b )
181  return;
182 
183  if( m_inspectClearanceDialog == nullptr )
184  {
185  m_inspectClearanceDialog = std::make_unique<DIALOG_CONSTRAINTS_REPORTER>( m_frame );
186  m_inspectClearanceDialog->SetTitle( _( "Clearance Report" ) );
187 
188  m_inspectClearanceDialog->Connect( wxEVT_CLOSE_WINDOW,
190  nullptr, this );
191  }
192 
193  WX_HTML_REPORT_BOX* r = m_inspectClearanceDialog->AddPage( _( "Clearance" ) );
194 
195  switch( aDRCItem->GetErrorCode() )
196  {
197  case DRCE_EDGE_CLEARANCE:
198  r->Report( "<h7>" + _( "Edge clearance resolution for:" ) + "</h7>" );
199 
200  r->Report( wxString::Format( "<ul><li>%s</li><li>%s</li></ul>",
202  EscapeHTML( getItemDescription( b ) ) ) );
203 
205  break;
206 
207  case DRCE_CLEARANCE:
208  if( a->Type() == PCB_TRACE_T || a->Type() == PCB_ARC_T )
209  {
210  layer = a->GetLayer();
211  }
212  else if( b->Type() == PCB_TRACE_T || b->Type() == PCB_ARC_T )
213  {
214  layer = b->GetLayer();
215  }
216  else if( a->Type() == PCB_PAD_T && static_cast<PAD*>( a )->GetAttribute() == PAD_ATTRIB::SMD )
217  {
218  PAD* pad = static_cast<PAD*>( a );
219 
220  if( pad->IsOnLayer( F_Cu ) )
221  layer = F_Cu;
222  else
223  layer = B_Cu;
224  }
225  else if( b->Type() == PCB_PAD_T && static_cast<PAD*>( a )->GetAttribute() == PAD_ATTRIB::SMD )
226  {
227  PAD* pad = static_cast<PAD*>( b );
228 
229  if( pad->IsOnLayer( F_Cu ) )
230  layer = F_Cu;
231  else
232  layer = B_Cu;
233  }
234 
235  r->Report( "<h7>" + _( "Clearance resolution for:" ) + "</h7>" );
236 
237  r->Report( wxString::Format( "<ul><li>%s %s</li><li>%s</li><li>%s</li></ul>",
238  _( "Layer" ),
239  EscapeHTML( m_frame->GetBoard()->GetLayerName( layer ) ),
241  EscapeHTML( getItemDescription( b ) ) ) );
242 
243  reportClearance( CLEARANCE_CONSTRAINT, layer, a, b, r );
244  break;
245 
246  default:
247  return;
248  }
249 
250  r->Flush();
251 
252  m_inspectClearanceDialog->Raise();
253  m_inspectClearanceDialog->Show( true );
254 }
255 
256 
258 {
260  const PCB_SELECTION& selection = selTool->GetSelection();
261 
262  if( selection.Size() != 2 )
263  {
264  m_frame->ShowInfoBarError( _( "Select two items for a clearance resolution report." ) );
265  return 0;
266  }
267 
268  BOARD_ITEM* a = static_cast<BOARD_ITEM*>( selection.GetItem( 0 ) );
269  BOARD_ITEM* b = static_cast<BOARD_ITEM*>( selection.GetItem( 1 ) );
270 
271  wxCHECK( a && b, 0 );
272 
273  if( a->Type() == PCB_GROUP_T )
274  {
275  PCB_GROUP* ag = static_cast<PCB_GROUP*>( a );
276 
277  if( ag->GetItems().empty() )
278  {
279  m_frame->ShowInfoBarError( _( "Cannot generate clearance report on empty group." ) );
280  return 0;
281  }
282 
283  a = *ag->GetItems().begin();
284  }
285 
286  if( b->Type() == PCB_GROUP_T )
287  {
288  PCB_GROUP* bg = static_cast<PCB_GROUP*>( b );
289 
290  if( bg->GetItems().empty() )
291  {
292  m_frame->ShowInfoBarError( _( "Cannot generate clearance report on empty group." ) );
293  return 0;
294  }
295 
296  b = *bg->GetItems().begin();
297  }
298 
299  // a and b could be null after group tests above.
300  wxCHECK( a && b, 0 );
301 
302  if( m_inspectClearanceDialog == nullptr )
303  {
304  m_inspectClearanceDialog = std::make_unique<DIALOG_CONSTRAINTS_REPORTER>( m_frame );
305  m_inspectClearanceDialog->SetTitle( _( "Clearance Report" ) );
306 
307  m_inspectClearanceDialog->Connect( wxEVT_CLOSE_WINDOW,
309  nullptr, this );
310  }
311 
312  WX_HTML_REPORT_BOX* r = nullptr;
313  EDA_UNITS units = m_frame->GetUserUnits();
314 
315  m_inspectClearanceDialog->DeleteAllPages();
316 
317  if( a->Type() != PCB_ZONE_T && b->Type() == PCB_ZONE_T )
318  std::swap( a, b );
319  else if( !a->IsConnected() && b->IsConnected() )
320  std::swap( a, b );
321 
322  PCB_LAYER_ID active = m_frame->GetActiveLayer();
323  LSET layerIntersection = a->GetLayerSet() & b->GetLayerSet();
324  LSET copperIntersection = layerIntersection & LSET::AllCuMask();
325  BOARD_CONNECTED_ITEM* ac = dynamic_cast<BOARD_CONNECTED_ITEM*>( a );
326  BOARD_CONNECTED_ITEM* bc = dynamic_cast<BOARD_CONNECTED_ITEM*>( b );
327  ZONE* zone = dynamic_cast<ZONE*>( a );
328  PAD* pad = dynamic_cast<PAD*>( b );
329  FOOTPRINT* aFP = dynamic_cast<FOOTPRINT*>( a );
330  FOOTPRINT* bFP = dynamic_cast<FOOTPRINT*>( b );
331 
333  bool compileError = false;
334  DRC_CONSTRAINT constraint;
335  int clearance = 0;
336 
337  try
338  {
339  drcEngine.InitEngine( m_frame->GetDesignRulesPath() );
340  }
341  catch( PARSE_ERROR& )
342  {
343  compileError = true;
344  }
345 
346  for( ZONE* z : m_frame->GetBoard()->Zones() )
347  z->CacheBoundingBox();
348 
349  for( FOOTPRINT* f : m_frame->GetBoard()->Footprints() )
350  {
351  for( ZONE* z : f->Zones() )
352  z->CacheBoundingBox();
353 
354  f->BuildPolyCourtyards();
355  }
356 
357  auto hasHole =
358  []( BOARD_ITEM* aItem )
359  {
360  PAD* tmpPad = dynamic_cast<PAD*>( aItem );
361 
362  if( tmpPad && tmpPad->GetDrillSizeX() > 0 && tmpPad->GetDrillSizeY() > 0 )
363  return true;
364 
365  PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem );
366 
367  if( via )
368  return true;
369 
370  return false;
371  };
372 
373  if( copperIntersection.any() && zone && pad && zone->GetNetCode() == pad->GetNetCode() )
374  {
375  PCB_LAYER_ID layer = active;
376  wxString source;
377 
378  if( !zone->IsOnLayer( active ) )
379  layer = zone->GetLayerSet().Seq().front();
380 
381  r = m_inspectClearanceDialog->AddPage( _( "Zone" ) );
382 
383  r->Report( "<h7>" + _( "Zone connection resolution for:" ) + "</h7>" );
384  r->Report( wxString::Format( "<ul><li>%s %s</li><li>%s</li><li>%s</li></ul>",
385  _( "Layer" ),
386  EscapeHTML( m_frame->GetBoard()->GetLayerName( layer ) ),
388  EscapeHTML( getItemDescription( b ) ) ) );
389 
390  ZONE_CONNECTION zoneConnection = zone->GetPadConnection( pad );
391 
392  if( zoneConnection == ZONE_CONNECTION::THERMAL )
393  {
394  int gap = zone->GetThermalReliefGap();
395 
396  r->Report( "" );
397  r->Report( wxString::Format( _( "Zone thermal relief: %s." ),
398  StringFromValue( r->GetUnits(), gap, true ) ) );
399 
400  gap = zone->GetThermalReliefGap( pad, &source );
401 
402  if( source != _( "zone" ) )
403  {
404  r->Report( wxString::Format( _( "Overridden by %s; thermal relief: %s." ),
405  source,
406  StringFromValue( r->GetUnits(), gap, true ) ) );
407  }
408  }
409  else if( zoneConnection == ZONE_CONNECTION::NONE )
410  {
411  clearance = zone->GetLocalClearance();
412 
413  r->Report( "" );
414  r->Report( wxString::Format( _( "Zone clearance: %s." ),
415  StringFromValue( r->GetUnits(), clearance, true ) ) );
416 
417  if( zone->GetThermalReliefGap( pad ) > clearance )
418  {
419  clearance = zone->GetThermalReliefGap( pad, &source );
420 
421  if( source != _( "zone" ) )
422  {
423  r->Report( wxString::Format( _( "Overridden by larger thermal relief from %s;"
424  "clearance: %s." ),
425  source,
426  StringFromValue( r->GetUnits(), clearance, true ) ) );
427  }
428  }
429 
430  if( compileError )
432 
433  r->Report( "" );
434  r->Report( wxString::Format( _( "Clearance: %s." ),
435  StringFromValue( units, 0, true ) ) );
436  }
437  else
438  {
439  if( compileError )
441 
442  // Report a 0 clearance for solid connections
443  r->Report( "" );
444  r->Report( wxString::Format( _( "Clearance: %s." ),
445  StringFromValue( units, 0, true ) ) );
446  }
447 
448  r->Flush();
449  }
450  else if( copperIntersection.any() && !aFP && !bFP )
451  {
452  PCB_LAYER_ID layer = active;
453 
454  if( !copperIntersection.test( layer ) )
455  layer = copperIntersection.Seq().front();
456 
457  r = m_inspectClearanceDialog->AddPage( m_frame->GetBoard()->GetLayerName( layer ) );
458 
459  r->Report( "<h7>" + _( "Clearance resolution for:" ) + "</h7>" );
460  r->Report( wxString::Format( "<ul><li>%s %s</li><li>%s</li><li>%s</li></ul>",
461  _( "Layer" ),
462  EscapeHTML( m_frame->GetBoard()->GetLayerName( layer ) ),
464  EscapeHTML( getItemDescription( b ) ) ) );
465 
466  if( ac && bc && ac->GetNetCode() > 0 && ac->GetNetCode() == bc->GetNetCode() )
467  {
468  // Same nets....
469  r->Report( _( "Items belong to the same net. Clearance is 0." ) );
470  }
471  else
472  {
473  // Different nets (or one or both unconnected)....
474  constraint = drcEngine.EvalRules( CLEARANCE_CONSTRAINT, a, b, layer, r );
475  clearance = constraint.m_Value.Min();
476 
477  if( compileError )
479 
480  r->Report( "" );
481  r->Report( wxString::Format( _( "Resolved clearance: %s." ),
482  StringFromValue( units, clearance, true ) ) );
483  }
484 
485  r->Flush();
486  }
487 
488  for( PCB_LAYER_ID layer : { F_SilkS, B_SilkS } )
489  {
490  PCB_LAYER_ID correspondingMask = IsFrontLayer( layer ) ? F_Mask : B_Mask;
491 
492  if( ( a->IsOnLayer( layer ) && b->IsOnLayer( layer ) )
493  || ( a->IsOnLayer( layer ) && b->IsOnLayer( correspondingMask ) )
494  || ( b->IsOnLayer( layer ) && a->IsOnLayer( correspondingMask ) ) )
495  {
496  r = m_inspectClearanceDialog->AddPage( m_frame->GetBoard()->GetLayerName( layer ) );
497 
498  r->Report( "<h7>" + _( "Silkscreen clearance resolution for:" ) + "</h7>" );
499  r->Report( wxString::Format( "<ul><li>%s %s</li><li>%s</li><li>%s</li></ul>",
500  _( "Layer" ),
501  EscapeHTML( m_frame->GetBoard()->GetLayerName( layer ) ),
503  EscapeHTML( getItemDescription( b ) ) ) );
504 
505  constraint = drcEngine.EvalRules( SILK_CLEARANCE_CONSTRAINT, a, b, layer, r );
506  clearance = constraint.m_Value.Min();
507 
508  if( compileError )
510 
511  r->Report( "" );
512  r->Report( wxString::Format( _( "Resolved clearance: %s." ),
513  StringFromValue( units, clearance, true ) ) );
514 
515  r->Flush();
516  }
517  }
518 
519  for( PCB_LAYER_ID layer : { F_CrtYd, B_CrtYd } )
520  {
521  bool aCourtyard = aFP && !aFP->GetPolyCourtyard( layer ).IsEmpty();
522  bool bCourtyard = bFP && !bFP->GetPolyCourtyard( layer ).IsEmpty();
523 
524  if( aCourtyard && bCourtyard )
525  {
526  r = m_inspectClearanceDialog->AddPage( m_frame->GetBoard()->GetLayerName( layer ) );
527 
528  r->Report( "<h7>" + _( "Courtyard clearance resolution for:" ) + "</h7>" );
529  r->Report( wxString::Format( "<ul><li>%s %s</li><li>%s</li><li>%s</li></ul>",
530  _( "Layer" ),
531  EscapeHTML( m_frame->GetBoard()->GetLayerName( layer ) ),
533  EscapeHTML( getItemDescription( b ) ) ) );
534 
535  constraint = drcEngine.EvalRules( COURTYARD_CLEARANCE_CONSTRAINT, a, b, layer, r );
536  clearance = constraint.m_Value.Min();
537 
538  if( compileError )
540 
541  r->Report( "" );
542  r->Report( wxString::Format( _( "Resolved clearance: %s." ),
543  StringFromValue( units, clearance, true ) ) );
544 
545  r->Flush();
546  }
547  }
548 
549  if( hasHole( a ) || hasHole( b ) )
550  {
552 
553  if( hasHole( a ) && b->IsOnLayer( active ) && IsCopperLayer( active ) )
554  layer = active;
555  else if( hasHole( b ) && a->IsOnLayer( active ) && IsCopperLayer( active ) )
556  layer = active;
557  else if( hasHole( a ) && IsCopperLayer( b->GetLayer() ) )
558  layer = b->GetLayer();
559  else if( hasHole( b ) && IsCopperLayer( a->GetLayer() ) )
560  layer = a->GetLayer();
561 
562  if( layer >= 0 )
563  {
564  r = m_inspectClearanceDialog->AddPage( _( "Hole" ) );
565 
566  r->Report( "<h7>" + _( "Hole clearance resolution for:" ) + "</h7>" );
567  r->Report( wxString::Format( "<ul><li>%s %s</li><li>%s</li><li>%s</li></ul>",
568  _( "Layer" ),
569  EscapeHTML( m_frame->GetBoard()->GetLayerName( layer ) ),
571  EscapeHTML( getItemDescription( b ) ) ) );
572 
573  constraint = drcEngine.EvalRules( HOLE_CLEARANCE_CONSTRAINT, a, b, layer, r );
574  clearance = constraint.m_Value.Min();
575 
576  if( compileError )
578 
579  r->Report( "" );
580  r->Report( wxString::Format( _( "Resolved clearance: %s." ),
581  StringFromValue( units, clearance, true ) ) );
582 
583  r->Flush();
584  }
585  }
586 
587  for( PCB_LAYER_ID edgeLayer : { Edge_Cuts, Margin } )
588  {
590 
591  if( a->IsOnLayer( edgeLayer ) && b->IsOnLayer( active ) && IsCopperLayer( active ) )
592  layer = active;
593  else if( b->IsOnLayer( edgeLayer ) && a->IsOnLayer( active ) && IsCopperLayer( active ) )
594  layer = active;
595  else if( a->IsOnLayer( edgeLayer ) && IsCopperLayer( b->GetLayer() ) )
596  layer = b->GetLayer();
597  else if( b->IsOnLayer( edgeLayer ) && IsCopperLayer( a->GetLayer() ) )
598  layer = a->GetLayer();
599 
600  if( layer >= 0 )
601  {
602  wxString layerName = m_frame->GetBoard()->GetLayerName( edgeLayer );
603  r = m_inspectClearanceDialog->AddPage( layerName + wxS( " " ) + _( "Clearance" ) );
604 
605  r->Report( "<h7>" + _( "Edge clearance resolution for:" ) + "</h7>" );
606  r->Report( wxString::Format( "<ul><li>%s %s</li><li>%s</li><li>%s</li></ul>",
607  _( "Layer" ),
608  EscapeHTML( m_frame->GetBoard()->GetLayerName( layer ) ),
610  EscapeHTML( getItemDescription( b ) ) ) );
611 
612  constraint = drcEngine.EvalRules( EDGE_CLEARANCE_CONSTRAINT, a, b, layer, r );
613  clearance = constraint.m_Value.Min();
614 
615  if( compileError )
617 
618  r->Report( "" );
619  r->Report( wxString::Format( _( "Resolved clearance: %s." ),
620  StringFromValue( units, clearance, true ) ) );
621 
622  r->Flush();
623  }
624  }
625 
626  if( m_inspectClearanceDialog->GetPageCount() == 0 )
627  {
628  r = m_inspectClearanceDialog->AddPage( _( "Clearance" ) );
629  r->Report( "<h7>" + _( "Items share no relevant layers:" ) + "</h7>" );
630  r->Report( wxString::Format( "<ul><li>%s</li><li>%s</li></ul>",
632  EscapeHTML( getItemDescription( b ) ) ) );
633  r->Flush();
634  }
635 
636  m_inspectClearanceDialog->Raise();
637  m_inspectClearanceDialog->Show( true );
638  return 0;
639 }
640 
641 
642 wxString reportMin( EDA_UNITS aUnits, DRC_CONSTRAINT& aConstraint )
643 {
644  if( aConstraint.m_Value.HasMin() )
645  return StringFromValue( aUnits, aConstraint.m_Value.Min(), true );
646  else
647  return wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
648 }
649 
650 
651 wxString reportOpt( EDA_UNITS aUnits, DRC_CONSTRAINT& aConstraint )
652 {
653  if( aConstraint.m_Value.HasOpt() )
654  return StringFromValue( aUnits, aConstraint.m_Value.Opt(), true );
655  else
656  return wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
657 }
658 
659 
660 wxString reportMax( EDA_UNITS aUnits, DRC_CONSTRAINT& aConstraint )
661 {
662  if( aConstraint.m_Value.HasMax() )
663  return StringFromValue( aUnits, aConstraint.m_Value.Max(), true );
664  else
665  return wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
666 }
667 
668 
670 {
671 #define EVAL_RULES( constraint, a, b, layer, r ) drcEngine.EvalRules( constraint, a, b, layer, r )
672 
674  const PCB_SELECTION& selection = selTool->GetSelection();
675 
676  if( selection.Size() != 1 )
677  {
678  m_frame->ShowInfoBarError( _( "Select an item for a constraints resolution report." ) );
679  return 0;
680  }
681 
682  if( m_inspectConstraintsDialog == nullptr )
683  {
684  m_inspectConstraintsDialog = std::make_unique<DIALOG_CONSTRAINTS_REPORTER>( m_frame );
685  m_inspectConstraintsDialog->SetTitle( _( "Constraints Report" ) );
686 
687  m_inspectConstraintsDialog->Connect( wxEVT_CLOSE_WINDOW,
689  nullptr, this );
690  }
691 
692  m_inspectConstraintsDialog->DeleteAllPages();
693 
694  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( selection.GetItem( 0 ) );
696  DRC_CONSTRAINT constraint;
697  bool courtyardError = false;
698  bool compileError = false;
699 
700  try
701  {
702  drcEngine.InitEngine( m_frame->GetDesignRulesPath() );
703  }
704  catch( PARSE_ERROR& )
705  {
706  compileError = true;
707  }
708 
709  for( ZONE* zone : m_frame->GetBoard()->Zones() )
710  zone->CacheBoundingBox();
711 
713  {
714  for( ZONE* zone : footprint->Zones() )
715  zone->CacheBoundingBox();
716 
718 
719  if( ( footprint->GetFlags() & MALFORMED_COURTYARDS ) != 0 )
720  courtyardError = true;
721  }
722 
723  WX_HTML_REPORT_BOX* r = nullptr;
724 
725  if( item->Type() == PCB_TRACE_T )
726  {
727  r = m_inspectConstraintsDialog->AddPage( _( "Track Width" ) );
728 
729  r->Report( "<h7>" + _( "Track width resolution for:" ) + "</h7>" );
730  r->Report( "<ul><li>" + EscapeHTML( getItemDescription( item ) ) + "</li></ul>" );
731  r->Report( "" );
732 
733  constraint = EVAL_RULES( TRACK_WIDTH_CONSTRAINT, item, nullptr, item->GetLayer(), r );
734 
735  if( compileError )
737 
738  r->Report( "" );
739  r->Report( wxString::Format( _( "Width constraints: min %s; opt %s; max %s." ),
740  reportMin( r->GetUnits(), constraint ),
741  reportOpt( r->GetUnits(), constraint ),
742  reportMax( r->GetUnits(), constraint ) ) );
743 
744  r->Flush();
745  }
746 
747  if( item->Type() == PCB_VIA_T )
748  {
749  r = m_inspectConstraintsDialog->AddPage( _( "Via Diameter" ) );
750 
751  r->Report( "<h7>" + _( "Via diameter resolution for:" ) + "</h7>" );
752  r->Report( "<ul><li>" + EscapeHTML( getItemDescription( item ) ) + "</li></ul>" );
753  r->Report( "" );
754 
755  // PADSTACKS TODO: once we have padstacks we'll need to run this per-layer....
756  constraint = EVAL_RULES( VIA_DIAMETER_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
757 
758  if( compileError )
760 
761  r->Report( "" );
762  r->Report( wxString::Format( _( "Diameter constraints: min %s; opt %s; max %s." ),
763  reportMin( r->GetUnits(), constraint ),
764  reportOpt( r->GetUnits(), constraint ),
765  reportMax( r->GetUnits(), constraint ) ) );
766 
767  r->Flush();
768 
769  r = m_inspectConstraintsDialog->AddPage( _( "Via Annular Width" ) );
770 
771  r->Report( "<h7>" + _( "Via annular width resolution for:" ) + "</h7>" );
772  r->Report( "<ul><li>" + EscapeHTML( getItemDescription( item ) ) + "</li></ul>" );
773  r->Report( "" );
774 
775  // PADSTACKS TODO: once we have padstacks we'll need to run this per-layer....
776  constraint = EVAL_RULES( ANNULAR_WIDTH_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
777 
778  if( compileError )
780 
781  r->Report( "" );
782  r->Report( wxString::Format( _( "Annular width constraints: min %s; opt %s; max %s." ),
783  reportMin( r->GetUnits(), constraint ),
784  reportOpt( r->GetUnits(), constraint ),
785  reportMax( r->GetUnits(), constraint ) ) );
786 
787  r->Flush();
788  }
789 
790  if( ( item->Type() == PCB_PAD_T && static_cast<PAD*>( item )->GetDrillSize().x > 0 )
791  || item->Type() == PCB_VIA_T )
792  {
793  r = m_inspectConstraintsDialog->AddPage( _( "Hole Size" ) );
794 
795  r->Report( "<h7>" + _( "Hole diameter resolution for:" ) + "</h7>" );
796  r->Report( "<ul><li>" + EscapeHTML( getItemDescription( item ) ) + "</li></ul>" );
797  r->Report( "" );
798 
799  // PADSTACKS TODO: once we have padstacks we'll need to run this per-layer....
800  constraint = EVAL_RULES( HOLE_SIZE_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
801 
802  if( compileError )
804 
805  wxString min = _( "undefined" );
806 
807  if( constraint.m_Value.HasMin() )
808  min = StringFromValue( r->GetUnits(), constraint.m_Value.Min(), true );
809 
810  r->Report( "" );
811  r->Report( wxString::Format( _( "Hole constraint: min %s." ), min ) );
812 
813  r->Flush();
814  }
815 
816  r = m_inspectConstraintsDialog->AddPage( _( "Keepouts" ) );
817 
818  r->Report( "<h7>" + _( "Keepout resolution for:" ) + "</h7>" );
819  r->Report( "<ul><li>" + EscapeHTML( getItemDescription( item ) ) + "</li></ul>" );
820  r->Report( "" );
821 
822  constraint = EVAL_RULES( DISALLOW_CONSTRAINT, item, nullptr, item->GetLayer(), r );
823 
824  if( compileError )
826 
827  if( courtyardError )
828  {
829  r->Report( "" );
830  r->Report( _( "Report may be incomplete: some footprint courtyards are malformed." )
831  + " <a href='drc'>" + _( "Run DRC for a full analysis." ) + "</a>" );
832  }
833 
834  r->Report( "" );
835 
836  if( constraint.m_DisallowFlags )
837  r->Report( _( "Item <b>disallowed</b> at current location." ) );
838  else
839  r->Report( _( "Item allowed at current location." ) );
840 
841  r->Flush();
842 
843  m_inspectConstraintsDialog->FinishInitialization();
845  m_inspectConstraintsDialog->Show( true );
846  return 0;
847 }
848 
849 
851 {
852  // Don't get in an infinite loop PCB -> SCH -> PCB -> SCH -> ...
853  if( m_probingSchToPcb )
854  return 0;
855 
857  const PCB_SELECTION& selection = selTool->GetSelection();
858 
859  if( selection.Size() == 1 )
860  m_frame->SendMessageToEESCHEMA( static_cast<BOARD_ITEM*>( selection.Front() ) );
861  else
862  m_frame->SendMessageToEESCHEMA( nullptr );
863 
864  // Update 3D viewer highlighting
865  m_frame->Update3DView( false, frame()->GetDisplayOptions().m_Live3DRefresh );
866 
867  return 0;
868 }
869 
870 
872 {
873  BOARD_ITEM* item = aEvent.Parameter<BOARD_ITEM*>();
874 
875  m_probingSchToPcb = true; // recursion guard
876  {
878 
879  if( item )
880  m_toolMgr->RunAction( PCB_ACTIONS::selectItem, true, (void*) item );
881  }
882  m_probingSchToPcb = false;
883 
884  bool request3DviewRedraw = frame()->GetDisplayOptions().m_Live3DRefresh;
885 
886  if( item && item->Type() != PCB_FOOTPRINT_T )
887  request3DviewRedraw = false;
888 
889  // Update 3D viewer highlighting
890  if( request3DviewRedraw )
891  m_frame->Update3DView( false, true );
892 
893  return 0;
894 }
895 
896 
897  bool BOARD_INSPECTION_TOOL::highlightNet( const VECTOR2D& aPosition, bool aUseSelection )
898 {
899  BOARD* board = static_cast<BOARD*>( m_toolMgr->GetModel() );
902 
903  int net = -1;
904  bool enableHighlight = false;
905 
906  if( aUseSelection )
907  {
908  const PCB_SELECTION& selection = selectionTool->GetSelection();
909  std::set<int> netcodes;
910 
911  for( EDA_ITEM* item : selection )
912  {
913  if( BOARD_CONNECTED_ITEM* ci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
914  netcodes.insert( ci->GetNetCode() );
915  }
916 
917  enableHighlight = !netcodes.empty();
918 
919  if( enableHighlight && netcodes.size() > 1 )
920  {
921  // If we are doing a multi-highlight, cross-probing back and other stuff is not
922  // yet supported
923  settings->SetHighlight( netcodes );
925 
926  for( int multiNet : netcodes )
927  board->SetHighLightNet( multiNet, true );
928 
929  board->HighLightON();
931  m_currentlyHighlighted = netcodes;
932  return true;
933  }
934  else if( enableHighlight )
935  {
936  net = *netcodes.begin();
937  }
938  }
939 
940  // If we didn't get a net to highlight from the selection, use the cursor
941  if( net < 0 )
942  {
944  guide.SetIgnoreZoneFills( false );
945 
946  PCB_LAYER_ID activeLayer = static_cast<PCB_LAYER_ID>( view()->GetTopLayer() );
947  guide.SetPreferredLayer( activeLayer );
948 
949  GENERAL_COLLECTOR collector;
950  collector.Collect( board, GENERAL_COLLECTOR::PadsOrTracks, (wxPoint) aPosition, guide );
951 
952  if( collector.GetCount() == 0 )
953  collector.Collect( board, GENERAL_COLLECTOR::Zones, (wxPoint) aPosition, guide );
954 
955  // Apply the active selection filter, except we want to allow picking locked items for
956  // highlighting even if the user has disabled them for selection
957  SELECTION_FILTER_OPTIONS& filter = selectionTool->GetFilter();
958 
959  bool saved = filter.lockedItems;
960  filter.lockedItems = true;
961 
962  selectionTool->FilterCollectedItems( collector, true );
963 
964  filter.lockedItems = saved;
965 
966  // Clear the previous highlight
967  m_frame->SendMessageToEESCHEMA( nullptr );
968 
969  bool highContrast = settings->GetHighContrast();
970  PCB_LAYER_ID contrastLayer = settings->GetPrimaryHighContrastLayer();
971 
972  for( int i = collector.GetCount() - 1; i >= 0; i-- )
973  {
974  LSET itemLayers = collector[i]->GetLayerSet();
975 
976  if( ( itemLayers & LSET::AllCuMask() ).none() ||
977  ( highContrast && !itemLayers.Contains( contrastLayer ) ) )
978  {
979  collector.Remove( i );
980  continue;
981  }
982  }
983 
984  enableHighlight = ( collector.GetCount() > 0 );
985 
986  // Obtain net code for the clicked item
987  if( enableHighlight )
988  {
989  BOARD_CONNECTED_ITEM* targetItem = static_cast<BOARD_CONNECTED_ITEM*>( collector[0] );
990 
991  if( targetItem->Type() == PCB_PAD_T )
992  m_frame->SendMessageToEESCHEMA( targetItem );
993 
994  net = targetItem->GetNetCode();
995  }
996  }
997 
998  auto& netcodes = settings->GetHighlightNetCodes();
999 
1000  // Toggle highlight when the same net was picked
1001  if( net > 0 && netcodes.count( net ) )
1002  enableHighlight = !settings->IsHighlightEnabled();
1003 
1004  if( enableHighlight != settings->IsHighlightEnabled() || !netcodes.count( net ) )
1005  {
1006  if( !netcodes.empty() )
1007  m_lastHighlighted = netcodes;
1008 
1009  settings->SetHighlight( enableHighlight, net );
1011  }
1012 
1013  // Store the highlighted netcode in the current board (for dialogs for instance)
1014  if( enableHighlight && net >= 0 )
1015  {
1016  m_currentlyHighlighted = netcodes;
1017  board->SetHighLightNet( net );
1018  board->HighLightON();
1019 
1020  NETINFO_ITEM* netinfo = board->FindNet( net );
1021 
1022  if( netinfo )
1023  {
1024  std::vector<MSG_PANEL_ITEM> items;
1025  netinfo->GetMsgPanelInfo( m_frame, items );
1026  m_frame->SetMsgPanel( items );
1027  m_frame->SendCrossProbeNetName( netinfo->GetNetname() );
1028  }
1029  }
1030  else
1031  {
1032  m_currentlyHighlighted.clear();
1036  }
1037 
1038  return true;
1039 }
1040 
1041 
1043 {
1044  int netcode = aEvent.Parameter<intptr_t>();
1046  const std::set<int>& highlighted = settings->GetHighlightNetCodes();
1047 
1048  if( netcode > 0 )
1049  {
1050  m_lastHighlighted = highlighted;
1051  settings->SetHighlight( true, netcode );
1053  m_currentlyHighlighted.clear();
1054  m_currentlyHighlighted.insert( netcode );
1055  }
1056  else if( aEvent.IsAction( &PCB_ACTIONS::highlightNetSelection ) )
1057  {
1058  // Highlight selection (cursor position will be ignored)
1059  highlightNet( getViewControls()->GetMousePosition(), true );
1060  }
1061  else if( aEvent.IsAction( &PCB_ACTIONS::toggleLastNetHighlight ) )
1062  {
1063  std::set<int> temp = highlighted;
1064  settings->SetHighlight( m_lastHighlighted );
1067  m_lastHighlighted = temp;
1068  }
1069  else if( aEvent.IsAction( &PCB_ACTIONS::toggleNetHighlight ) )
1070  {
1071  bool turnOn = highlighted.empty() && !m_currentlyHighlighted.empty();
1072  settings->SetHighlight( m_currentlyHighlighted, turnOn );
1074  }
1075  else // Highlight the net belonging to the item under the cursor
1076  {
1077  highlightNet( getViewControls()->GetMousePosition(), false );
1078  }
1079 
1080  return 0;
1081 }
1082 
1083 
1085 {
1086  BOARD* board = static_cast<BOARD*>( m_toolMgr->GetModel() );
1088 
1089  m_currentlyHighlighted.clear();
1090  m_lastHighlighted.clear();
1091 
1093  settings->SetHighlight( false );
1097  return 0;
1098 }
1099 
1100 #if 0
1102 {
1103  std::string tool = aEvent.GetCommandStr().get();
1105 
1106  // Deactivate other tools; particularly important if another PICKER is currently running
1107  Activate();
1108 
1109  // If the keyboard hotkey was triggered and we are already in the highlight tool, behave
1110  // the same as a left-click. Otherwise highlight the net of the selected item(s), or if
1111  // there is no selection, then behave like a ctrl-left-click.
1113  {
1114  bool use_selection = m_frame->IsCurrentTool( PCB_ACTIONS::highlightNetTool );
1115  highlightNet( getViewControls()->GetMousePosition(), use_selection );
1116  }
1117 
1118  picker->SetClickHandler(
1119  [this] ( const VECTOR2D& pt ) -> bool
1120  {
1121  highlightNet( pt, false );
1122  return true;
1123  } );
1124 
1125  picker->SetLayerSet( LSET::AllCuMask() );
1126  picker->SetSnapping( false );
1127 
1128  m_toolMgr->RunAction( ACTIONS::pickerTool, true, &tool );
1129 
1130  return 0;
1131 }
1132 #endif
1133 
1135 {
1136  std::string tool = aEvent.GetCommandStr().get();
1138  BOARD* board = getModel<BOARD>();
1139 
1140  // Deactivate other tools; particularly important if another PICKER is currently running
1141  Activate();
1142 
1143  picker->SetClickHandler(
1144  [this, board]( const VECTOR2D& pt ) -> bool
1145  {
1146  const PCB_DISPLAY_OPTIONS& opt = displayOptions();
1148 
1151  PCB_SELECTION& selection = selectionTool->GetSelection();
1152 
1153  if( selection.Empty() )
1154  {
1157  selection = selectionTool->GetSelection();
1158  }
1159 
1160  if( selection.Empty() )
1161  {
1162  // Clear the previous local ratsnest if we click off all items
1163  for( FOOTPRINT* fp : board->Footprints() )
1164  {
1165  for( PAD* pad : fp->Pads() )
1166  pad->SetLocalRatsnestVisible( opt.m_ShowGlobalRatsnest );
1167  }
1168  }
1169  else
1170  {
1171  for( EDA_ITEM* item : selection )
1172  {
1173  if( PAD* pad = dyn_cast<PAD*>( item) )
1174  {
1175  pad->SetLocalRatsnestVisible( !pad->GetLocalRatsnestVisible() );
1176  }
1177  else if( FOOTPRINT* fp = dyn_cast<FOOTPRINT*>( item) )
1178  {
1179  if( !fp->Pads().empty() )
1180  {
1181  bool enable = !fp->Pads()[0]->GetLocalRatsnestVisible();
1182 
1183  for( PAD* childPad : fp->Pads() )
1184  childPad->SetLocalRatsnestVisible( enable );
1185  }
1186  }
1187  }
1188  }
1189 
1191 
1192  return true;
1193  } );
1194 
1195  picker->SetFinalizeHandler(
1196  [this, board]( int aCondition )
1197  {
1198  const PCB_DISPLAY_OPTIONS& opt = displayOptions();
1199 
1200  if( aCondition != PCB_PICKER_TOOL::END_ACTIVATE )
1201  {
1202  for( FOOTPRINT* fp : board->Footprints() )
1203  {
1204  for( PAD* pad : fp->Pads() )
1205  pad->SetLocalRatsnestVisible( opt.m_ShowGlobalRatsnest );
1206  }
1207  }
1208  } );
1209 
1210  m_toolMgr->RunAction( ACTIONS::pickerTool, true, &tool );
1211 
1212  return 0;
1213 }
1214 
1215 
1217 {
1218  VECTOR2I delta;
1219 
1220  // If we have passed the simple move vector, we can update without recalculation
1221  if( aEvent.Parameter<VECTOR2I*>() )
1222  {
1223  delta = *aEvent.Parameter<VECTOR2I*>();
1224  delete aEvent.Parameter<VECTOR2I*>();
1225  }
1226  else
1227  {
1228  // We can delete the existing map to force a recalculation
1229  delete m_dynamicData;
1230  m_dynamicData = nullptr;
1231  }
1232 
1233  auto selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1234  auto& selection = selectionTool->GetSelection();
1235  auto connectivity = getModel<BOARD>()->GetConnectivity();
1236 
1237  if( selection.Empty() )
1238  {
1239  connectivity->ClearDynamicRatsnest();
1240  delete m_dynamicData;
1241  m_dynamicData = nullptr;
1242  }
1243  else
1244  {
1246  }
1247 
1248  return 0;
1249 }
1250 
1251 
1253 {
1254  getModel<BOARD>()->GetConnectivity()->ClearDynamicRatsnest();
1255  delete m_dynamicData;
1256  m_dynamicData = nullptr;
1257 
1258  return 0;
1259 }
1260 
1261 
1263 {
1265  SELECTION& selection = selectionTool->GetSelection();
1266  std::shared_ptr<CONNECTIVITY_DATA> connectivity = board()->GetConnectivity();
1267  std::vector<BOARD_ITEM*> items;
1268  std::deque<EDA_ITEM*> queued_items( selection.begin(), selection.end() );
1269 
1270  for( std::size_t i = 0; i < queued_items.size(); ++i )
1271  {
1272  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( queued_items[i] );
1273 
1274  if( item->Type() == PCB_FOOTPRINT_T )
1275  {
1276  for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
1277  {
1278  if( pad->GetLocalRatsnestVisible() || displayOptions().m_ShowModuleRatsnest )
1279  items.push_back( pad );
1280  }
1281  }
1282  else if( item->Type() == PCB_GROUP_T )
1283  {
1284  PCB_GROUP *group = static_cast<PCB_GROUP*>( item );
1285  group->RunOnDescendants( [ &queued_items ]( BOARD_ITEM *aItem )
1286  {
1287  queued_items.push_back( aItem );
1288  } );
1289  }
1290  else if( BOARD_CONNECTED_ITEM* boardItem = dyn_cast<BOARD_CONNECTED_ITEM*>( item ) )
1291  {
1292  if( boardItem->GetLocalRatsnestVisible() || displayOptions().m_ShowModuleRatsnest )
1293  items.push_back( boardItem );
1294  }
1295  }
1296 
1297  if( items.empty() || std::none_of( items.begin(), items.end(),
1298  []( const BOARD_ITEM* aItem )
1299  {
1300  return( aItem->Type() == PCB_TRACE_T
1301  || aItem->Type() == PCB_PAD_T
1302  || aItem->Type() == PCB_ARC_T
1303  || aItem->Type() == PCB_ZONE_T
1304  || aItem->Type() == PCB_FOOTPRINT_T
1305  || aItem->Type() == PCB_VIA_T );
1306  } ) )
1307  {
1308  return;
1309  }
1310 
1311  if( !m_dynamicData )
1312  {
1313  m_dynamicData = new CONNECTIVITY_DATA( items, true );
1314  connectivity->BlockRatsnestItems( items );
1315  }
1316  else
1317  {
1318  m_dynamicData->Move( aDelta );
1319  }
1320 
1321  connectivity->ComputeDynamicRatsnest( items, m_dynamicData );
1322 }
1323 
1324 
1326 {
1327  if( m_listNetsDialog == nullptr )
1328  {
1330  std::make_unique<DIALOG_NET_INSPECTOR>( m_frame, m_listNetsDialogSettings );
1331 
1332  m_listNetsDialog->Connect( wxEVT_CLOSE_WINDOW,
1333  wxCommandEventHandler( BOARD_INSPECTION_TOOL::onListNetsDialogClosed ), nullptr,
1334  this );
1335 
1336  m_listNetsDialog->Connect( wxEVT_BUTTON,
1337  wxCommandEventHandler( BOARD_INSPECTION_TOOL::onListNetsDialogClosed ), nullptr,
1338  this );
1339  }
1340 
1341  m_listNetsDialog->Raise();
1342  m_listNetsDialog->Show( true );
1343  return 0;
1344 }
1345 
1346 
1348 {
1350 
1351  m_listNetsDialog->Disconnect( wxEVT_CLOSE_WINDOW,
1352  wxCommandEventHandler( BOARD_INSPECTION_TOOL::onListNetsDialogClosed ), nullptr, this );
1353 
1354  m_listNetsDialog->Disconnect( wxEVT_BUTTON,
1355  wxCommandEventHandler( BOARD_INSPECTION_TOOL::onListNetsDialogClosed ), nullptr, this );
1356 
1357  m_listNetsDialog->Destroy();
1358  m_listNetsDialog.release();
1359 }
1360 
1361 
1363 {
1364  m_inspectClearanceDialog->Disconnect( wxEVT_CLOSE_WINDOW,
1366  nullptr, this );
1367 
1368  m_inspectClearanceDialog->Destroy();
1369  m_inspectClearanceDialog.release();
1370 }
1371 
1372 
1374 {
1375  m_inspectConstraintsDialog->Disconnect( wxEVT_CLOSE_WINDOW,
1377  nullptr, this );
1378 
1379  m_inspectConstraintsDialog->Destroy();
1380  m_inspectConstraintsDialog.release();
1381 }
1382 
1383 
1385 {
1386  doHideNet( aEvent.Parameter<intptr_t>(), true );
1387  return 0;
1388 }
1389 
1390 
1392 {
1393  doHideNet( aEvent.Parameter<intptr_t>(), false );
1394  return 0;
1395 }
1396 
1397 
1398 void BOARD_INSPECTION_TOOL::doHideNet( int aNetCode, bool aHide )
1399 {
1400  KIGFX::PCB_RENDER_SETTINGS* rs = static_cast<KIGFX::PCB_RENDER_SETTINGS*>(
1402 
1404  SELECTION& selection = selectionTool->GetSelection();
1405 
1406  if( aNetCode <= 0 && !selection.Empty() )
1407  {
1408  for( EDA_ITEM* item : selection )
1409  {
1410  if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
1411  {
1412  if( bci->GetNetCode() > 0 )
1413  doHideNet( bci->GetNetCode(), aHide );
1414  }
1415  }
1416 
1417  return;
1418  }
1419 
1420  if( aHide )
1421  rs->GetHiddenNets().insert( aNetCode );
1422  else
1423  rs->GetHiddenNets().erase( aNetCode );
1424 
1426  m_frame->GetCanvas()->Refresh();
1427 
1428  m_frame->GetAppearancePanel()->OnNetVisibilityChanged( aNetCode, !aHide );
1429 }
1430 
1431 
1433 {
1437 
1439  PCB_ACTIONS::localRatsnestTool.MakeEvent() );
1441  PCB_ACTIONS::hideDynamicRatsnest.MakeEvent() );
1443  PCB_ACTIONS::updateLocalRatsnest.MakeEvent() );
1444 
1449 
1456 
1459 }
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:59
void BuildPolyCourtyards(OUTLINE_ERROR_HANDLER *aErrorHandler=nullptr)
Build complex polygons of the courtyard areas from graphic items on the courtyard layers.
Definition: footprint.cpp:2022
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:750
BOARD_ITEM * GetItem(const KIID &aID) const
Definition: board.cpp:845
void reportClearance(DRC_CONSTRAINT_T aClearanceType, PCB_LAYER_ID aLayer, BOARD_ITEM *aA, BOARD_ITEM *aB, REPORTER *r)
int HideDynamicRatsnest(const TOOL_EVENT &aEvent)
Show local ratsnest of a component.
void AddMenu(ACTION_MENU *aMenu, const SELECTION_CONDITION &aCondition=SELECTION_CONDITIONS::ShowAlways, int aOrder=ANY_ORDER)
Add a submenu to the menu.
std::set< int > & GetHiddenNets()
Definition: pcb_painter.h:187
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1325
ZONE_CONNECTION
How pads are covered by copper in zone.
Definition: zones.h:41
Design Rule Checker object that performs all the DRC tests.
Definition: drc_engine.h:81
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:283
bool IsCurrentTool(const TOOL_ACTION &aAction) const
static const TOOL_EVENT SelectedEvent
Definition: actions.h:199
wxString getItemDescription(BOARD_ITEM *aItem)
const int GetDrillSizeX() const
Definition: pad.h:245
void SendCrossProbeNetName(const wxString &aNetName)
Send a net name to Eeschema for highlighting.
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:362
ZONES & Zones()
Definition: board.h:239
bool HasMin() const
Definition: minoptmax.h:37
BOARD * board() const
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
wxString GetDesignRulesPath()
Return the absolute path to the design rules file for the currently-loaded board.
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
static const TOOL_EVENT UnselectedEvent
Definition: actions.h:200
void HighLightON(bool aValue=true)
Enable or disable net highlighting.
Definition: board.cpp:2013
Defines the structure of a menu based on ACTIONs.
Definition: action_menu.h:48
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:49
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:108
A slimmed down version of WX_HTML_REPORT_PANEL.
static TOOL_ACTION hideNet
Definition: pcb_actions.h:458
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
Definition: action_menu.cpp:73
static TOOL_ACTION highlightItem
Definition: pcb_actions.h:457
A set of BOARD_ITEMs (i.e., without duplicates).
Definition: pcb_group.h:50
void Collect(BOARD_ITEM *aItem, const KICAD_T aScanList[], const wxPoint &aRefPos, const COLLECTORS_GUIDE &aGuide)
Scan a BOARD_ITEM using this class's Inspector method, which does the collection.
Definition: collectors.cpp:571
int LocalRatsnestTool(const TOOL_EVENT &aEvent)
static TOOL_ACTION boardStatistics
Definition: pcb_actions.h:444
int InspectClearance(const TOOL_EVENT &aEvent)
static SELECTION_CONDITION OnlyTypes(const KICAD_T aTypes[])
Create a functor that tests if the selected items are only of given types.
int ClearHighlight(const TOOL_EVENT &aEvent)
Launch a tool to pick the item whose net is going to be highlighted.
virtual NETCLASS * GetNetClass() const
Return the NETCLASS for this item.
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:46
bool Contains(PCB_LAYER_ID aLayer)
See if the layer set contains a PCB layer.
Definition: layer_ids.h:575
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:214
ITER end()
Definition: selection.h:65
bool IsEmpty() const
int CrossProbePcbToSch(const TOOL_EVENT &aEvent)
Highlight net belonging to the item under the cursor.
Smd pad, appears on the solder paste layer (default)
#define EVAL_RULES(constraint, a, b, layer, r)
void FilterCollectedItems(GENERAL_COLLECTOR &aCollector, bool aMultiSelect)
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: zone.cpp:295
void InspectDRCError(const std::shared_ptr< RC_ITEM > &aDRCItem)
Show the clearance resolution for two selected items.
TOOL_MENU & GetToolMenu()
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:143
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:97
T Opt() const
Definition: minoptmax.h:35
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Test to see if this object is on the given layer.
Definition: zone.cpp:320
class PAD, a pad in a footprint
Definition: typeinfo.h:89
wxString reportMin(EDA_UNITS aUnits, DRC_CONSTRAINT &aConstraint)
void SetFinalizeHandler(FINALIZE_HANDLER aHandler)
Set a handler for the finalize event.
Definition: picker_tool.h:102
static const KICAD_T PadsOrTracks[]
A scan list for PADs, TRACKs, or VIAs.
Definition: collectors.h:288
T Min() const
Definition: minoptmax.h:33
static TOOL_ACTION localRatsnestTool
Definition: pcb_actions.h:462
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:70
static SELECTION_CONDITION Count(int aNumber)
Create a functor that tests if the number of selected items is equal to the value given as parameter.
static TOOL_ACTION toggleLastNetHighlight
Definition: pcb_actions.h:454
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:411
APPEARANCE_CONTROLS * GetAppearancePanel()
const PCB_DISPLAY_OPTIONS & GetDisplayOptions() const
Display options control the way tracks, vias, outlines and other things are shown (for instance solid...
std::unordered_set< BOARD_ITEM * > & GetItems()
Definition: pcb_group.h:68
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:590
EDA_ITEM * GetModel() const
Definition: tool_manager.h:290
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
T Max() const
Definition: minoptmax.h:34
void Remove(int aIndex)
Remove the item at aIndex (first position is 0).
Definition: collector.h:110
search types array terminator (End Of Types)
Definition: typeinfo.h:81
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:77
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:208
void RedrawRatsnest()
Return the bounding box of the view that should be used if model is not valid.
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:95
static TOOL_ACTION toggleNetHighlight
Definition: pcb_actions.h:455
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
Definition: tool_event.cpp:88
static TOOL_ACTION inspectConstraints
Definition: pcb_actions.h:449
void SetLayerSet(LSET aLayerSet)
Set the tool's snap layer set.
static TOOL_ACTION pickerTool
Definition: actions.h:155
std::set< int > m_currentlyHighlighted
PCB_BASE_EDIT_FRAME * frame() const
int GetThermalReliefGap() const
Definition: zone.h:191
virtual PCB_LAYER_ID GetActiveLayer() const
void ShowInfoBarError(const wxString &aErrorMsg, bool aShowCloseButton=false, WX_INFOBAR::MESSAGE_TYPE aType=WX_INFOBAR::MESSAGE_TYPE::GENERIC)
Show the WX_INFOBAR displayed on the top of the canvas with a message and an error icon on the left o...
std::unique_ptr< DIALOG_CONSTRAINTS_REPORTER > m_inspectClearanceDialog
DRC_CONSTRAINT_T
Definition: drc_rule.h:41
PCB specific render settings.
Definition: pcb_painter.h:64
MINOPTMAX< int > m_Value
Definition: drc_rule.h:145
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:82
PCB_SELECTION & GetSelection()
Return the set of currently selected items.
int InspectConstraints(const TOOL_EVENT &aEvent)
FP_ZONES & Zones()
Definition: footprint.h:174
ITER begin()
Definition: selection.h:64
std::set< int > m_lastHighlighted
Container for display options like enable/disable some optional drawings.
void SetPreferredLayer(PCB_LAYER_ID aLayer)
Definition: collectors.h:471
GENERAL_COLLECTORS_GUIDE GetCollectorsGuide()
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:504
void ResetNetHighLight()
Reset all high light data to the init state.
Definition: board.cpp:1991
int HighlightNet(const TOOL_EVENT &aEvent)
Clear all board highlights.
const PCB_SELECTION & selection() const
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Test to see if this object is on the given layer.
Definition: board_item.h:198
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
std::unique_ptr< DIALOG_CONSTRAINTS_REPORTER > m_inspectConstraintsDialog
void MarkTargetDirty(int aTarget)
Set or clear target 'dirty' flag.
Definition: view.h:609
void onInspectClearanceDialogClosed(wxCommandEvent &aEvent)
int GetLocalClearance(wxString *aSource) const override
Return any local clearances set in the "classic" (ie: pre-rule) system.
Definition: zone.cpp:498
T Parameter() const
Return a non-standard parameter assigned to the event.
Definition: tool_event.h:432
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
FOOTPRINTS & Footprints()
Definition: board.h:233
Generic, UI-independent tool event.
Definition: tool_event.h:152
FOOTPRINT * footprint() const
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition: board.h:344
KIGFX::PCB_VIEW * view() const
static const KICAD_T Zones[]
A scan list for zones outlines only.
Definition: collectors.h:272
const wxString & GetNetname() const
Definition: netinfo.h:121
Items that may change while the view stays the same (noncached)
Definition: definitions.h:50
#define _(s)
int HighlightItem(const TOOL_EVENT &aEvent)
Update ratsnest for selected items.
static const TOOL_EVENT ClearedEvent
Selected item had a property changed (except movement)
Definition: actions.h:201
const SHAPE_POLY_SET & GetPolyCourtyard(PCB_LAYER_ID aLayer) const
Used in DRC to test the courtyard area (a complex polygon).
Definition: footprint.h:695
Handle a list of polygons defining a copper zone.
Definition: zone.h:56
class ZONE, a copper pour area
Definition: typeinfo.h:105
This file contains data structures that are saved in the project file or project local settings file ...
void reportCompileError(REPORTER *r)
void SetHighLightNet(int aNetCode, bool aMulti=false)
Select the netcode to be highlighted.
Definition: board.cpp:2000
int ShowNet(const TOOL_EVENT &aEvent)
E_SERIE r
Definition: eserie.cpp:41
bool IsFrontLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a front layer.
Definition: layer_ids.h:872
static TOOL_ACTION hideDynamicRatsnest
Definition: pcb_actions.h:463
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
bool highlightNet(const VECTOR2D &aPosition, bool aUseSelection)
Look for a BOARD_CONNECTED_ITEM in a given spot and if one is found - it enables highlight for its ne...
static void PadFilter(const VECTOR2I &, GENERAL_COLLECTOR &aCollector, PCB_SELECTION_TOOL *sTool)
A selection filter which prunes the selection to contain only items of type PCB_PAD_T.
Definition: edit_tool.cpp:2286
bool IsCopperLayer(LAYER_NUM aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:796
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:98
static TOOL_ACTION inspectClearance
Definition: pcb_actions.h:448
const PCB_DISPLAY_OPTIONS & displayOptions() const
Generic tool for picking an item.
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:155
class FOOTPRINT, a footprint
Definition: typeinfo.h:88
std::unique_ptr< DIALOG_NET_INSPECTOR > m_listNetsDialog
static TOOL_ACTION clearHighlight
Definition: pcb_actions.h:452
void SetClickHandler(CLICK_HANDLER aHandler)
Set a handler for mouse click event.
Definition: picker_tool.h:71
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
int ListNets(const TOOL_EVENT &aEvent)
Hide the ratsnest for a given net.
EDA_UNITS
Definition: eda_units.h:38
void OnNetVisibilityChanged(int aNetCode, bool aVisibility)
Notifies the panel when a net has been hidden or shown via the external tool.
OPT< std::string > GetCommandStr() const
Definition: tool_event.h:460
Use thermal relief for pads.
int HighlightNetTool(const TOOL_EVENT &aEvent)
Perform the appropriate action in response to an Eeschema cross-probe.
void SendMessageToEESCHEMA(BOARD_ITEM *objectToSync)
Send a message to the schematic editor so that it may move its cursor to a symbol with the same refer...
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
wxString EscapeHTML(const wxString &aString)
Return a new wxString escaped for embedding in HTML.
Handle the data for a net.
Definition: netinfo.h:66
const wxString GetName() const
Definition: netclass.h:65
static TOOL_ACTION showNet
Definition: pcb_actions.h:459
A filename or source description, a problem input line, a line number, a byte offset,...
Definition: ki_exception.h:118
bool HasMax() const
Definition: minoptmax.h:38
void SetTitle(const wxString &aTitle) override
Set title for the menu.
Definition: action_menu.cpp:87
static TOOL_ACTION highlightNet
Definition: pcb_actions.h:453
DIALOG_NET_INSPECTOR::SETTINGS m_listNetsDialogSettings
static TOOL_ACTION highlightNetSelection
Definition: pcb_actions.h:456
virtual KIGFX::VIEW_ITEM * GetItem(unsigned int aIdx) const override
Definition: selection.cpp:53
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:190
const int GetDrillSizeY() const
Definition: pad.h:247
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:65
static TOOL_ACTION listNets
Definition: pcb_actions.h:343
bool Init() override
Init() is called once upon a registration of the tool.
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:240
Dialog to show common board info.
virtual wxString GetSelectMenuText(EDA_UNITS aUnits) const
Return the text to display to be used in the selection clarification context menu when multiple items...
Definition: eda_item.cpp:109
bool m_Live3DRefresh
If true, 3D viewer will redraw on every modification operation.
virtual void Update3DView(bool aMarkDirty, bool aRefresh, const wxString *aTitle=nullptr)
Update the 3D view, if the viewer is opened by this frame.
Definition: layer_ids.h:71
void AddSubMenu(std::shared_ptr< ACTION_MENU > aSubMenu)
Store a submenu of this menu model.
Definition: tool_menu.cpp:52
void onListNetsDialogClosed(wxCommandEvent &aEvent)
void doHideNet(int aNetCode, bool aHide)
Bind handlers to corresponding TOOL_ACTIONs.
static TOOL_ACTION selectItem
Select an item (specified as the event parameter).
Definition: pcb_actions.h:62
wxMenuItem * Add(const wxString &aLabel, int aId, BITMAPS aIcon)
Add a wxWidgets-style entry to the menu.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
int Size() const
Returns the number of selected parts.
Definition: selection.h:104
The selection tool: currently supports:
bool HasOpt() const
Definition: minoptmax.h:39
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:100
CONNECTIVITY_DATA * m_dynamicData
Pads are not covered.
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:77
int HideNet(const TOOL_EVENT &aEvent)
Show the ratsnest for a given net.
wxString StringFromValue(EDA_UNITS aUnits, double aValue, bool aAddUnitSymbol, EDA_DATA_TYPE aType)
Convert a value to a string using double notation.
Definition: base_units.cpp:204
void Activate()
Run the tool.
int UpdateSelectionRatsnest(const TOOL_EVENT &aEvent)
Hide ratsnest for selected items. Called when there are no items selected.
constexpr int delta
virtual bool IsConnected() const
Returns information if the object is derived from BOARD_CONNECTED_ITEM.
Definition: board_item.h:103
SELECTION_FILTER_OPTIONS & GetFilter()
Set up handlers for various events.
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
void SetSnapping(bool aSnap)
Definition: picker_tool.h:64
const std::set< int > & GetHighlightNetCodes() const
Return the netcode of currently highlighted net.
static TOOL_ACTION updateLocalRatsnest
Definition: pcb_actions.h:464
static void FootprintFilter(const VECTOR2I &, GENERAL_COLLECTOR &aCollector, PCB_SELECTION_TOOL *sTool)
A selection filter which prunes the selection to contain only items of type #PCB_MODULE_T.
Definition: edit_tool.cpp:2299
BOARD * GetBoard() const
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:42
A general implementation of a COLLECTORS_GUIDE.
Definition: collectors.h:377
ZONE_CONNECTION GetPadConnection(PAD *aPad, wxString *aSource=nullptr) const
Definition: zone.cpp:778
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Return the information about the NETINFO_ITEM in aList to display in the message panel.
Definition: pad.h:57
void UpdateAllLayersColor()
Apply the new coloring scheme to all layers.
Definition: view.cpp:766
wxString reportOpt(EDA_UNITS aUnits, DRC_CONSTRAINT &aConstraint)
#define MALFORMED_COURTYARDS
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Add a menu entry to run a TOOL_ACTION on selected items.
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:140
wxString reportMax(EDA_UNITS aUnits, DRC_CONSTRAINT &aConstraint)
void Move(const VECTOR2I &aDelta)
Moves the connectivity list anchors.
static TOOL_ACTION selectionCursor
Select a single item under the cursor position.
Definition: pcb_actions.h:56
void calculateSelectionRatsnest(const VECTOR2I &aDelta)
< Recalculate dynamic ratsnest for the current selection.
EDA_UNITS GetUserUnits() const
Return the user units currently in use.
void SetIgnoreZoneFills(bool ignore)
Definition: collectors.h:568
void onInspectConstraintsDialogClosed(wxCommandEvent &aEvent)
int ShowStatisticsDialog(const TOOL_EVENT &aEvent)
Show dialog with board statistics.
void InitEngine(const wxFileName &aRulePath)
Initialize the DRC engine.
Definition: drc_engine.cpp:626
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:145
EDA_ITEM * Front() const
Definition: selection.h:145
ACTION_MENU * create() const override
< Return an instance of this class. It has to be overridden in inheriting classes.
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:113