KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 The 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
25
26#include <bitmaps.h>
27#include <collectors.h>
28#include <footprint.h>
29#include <pcb_group.h>
30#include <tool/tool_manager.h>
33#include <tools/edit_tool.h>
34#include <tools/drc_tool.h>
35#include <pcb_painter.h>
37#include <drc/drc_engine.h>
42#include <dialogs/dialog_drc.h>
43#include <kiplatform/ui.h>
44#include <status_popup.h>
45#include <string_utils.h>
47#include <pcb_shape.h>
51#include <drc/drc_item.h>
52#include <pad.h>
53#include <pcb_track.h>
54#include <project_pcb.h>
55#include <view/view_controls.h>
56
57
59 PCB_TOOL_BASE( "pcbnew.InspectionTool" ),
60 m_frame( nullptr )
61{
62 m_dynamicData = nullptr;
63}
64
65
67{
68public:
81
82private:
83 ACTION_MENU* create() const override
84 {
85 return new NET_CONTEXT_MENU();
86 }
87};
88
89
91{
92 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
93
94 std::shared_ptr<NET_CONTEXT_MENU> netSubMenu = std::make_shared<NET_CONTEXT_MENU>();
95 netSubMenu->SetTool( this );
96
97 // Only show the net menu if all items in the selection are connectable
98 auto showNetMenuFunc =
99 []( const SELECTION& aSelection )
100 {
101 if( aSelection.Empty() )
102 return false;
103
104 for( const EDA_ITEM* item : aSelection )
105 {
106 switch( item->Type() )
107 {
108 case PCB_TRACE_T:
109 case PCB_ARC_T:
110 case PCB_VIA_T:
111 case PCB_PAD_T:
112 case PCB_ZONE_T:
113 continue;
114
115 case PCB_SHAPE_T:
116 {
117 if( !static_cast<const PCB_SHAPE*>( item )->IsOnCopperLayer() )
118 return false;
119 else
120 continue;
121 }
122
123 default:
124 return false;
125 }
126 }
127
128 return true;
129 };
130
131 CONDITIONAL_MENU& menu = selectionTool->GetToolMenu().GetMenu();
132
133 selectionTool->GetToolMenu().RegisterSubMenu( netSubMenu );
134
135 menu.AddMenu( netSubMenu.get(), showNetMenuFunc, 100 );
136
137 return true;
138}
139
140
145
146
148{
150 dialog.ShowModal();
151 return 0;
152}
153
154
155std::unique_ptr<DRC_ENGINE> BOARD_INSPECTION_TOOL::makeDRCEngine( bool* aCompileError,
156 bool* aCourtyardError )
157{
158 auto engine = std::make_unique<DRC_ENGINE>( m_frame->GetBoard(),
159 &m_frame->GetBoard()->GetDesignSettings() );
160
161 try
162 {
163 engine->InitEngine( m_frame->GetDesignRulesPath() );
164 }
165 catch( PARSE_ERROR& )
166 {
167 if( aCompileError )
168 *aCompileError = true;
169 }
170
171 for( ZONE* zone : m_frame->GetBoard()->Zones() )
172 zone->CacheBoundingBox();
173
174 for( FOOTPRINT* footprint : m_frame->GetBoard()->Footprints() )
175 {
176 for( ZONE* zone : footprint->Zones() )
177 zone->CacheBoundingBox();
178
179 footprint->BuildCourtyardCaches();
180
181 if( aCourtyardError && ( footprint->GetFlags() & MALFORMED_COURTYARDS ) != 0 )
182 *aCourtyardError = true;
183 }
184
185 return engine;
186}
187
188
189bool isNPTHPad( BOARD_ITEM* aItem )
190{
191 return aItem->Type() == PCB_PAD_T
192 && static_cast<PAD*>( aItem )->GetAttribute() == PAD_ATTRIB::NPTH;
193}
194
195
197{
198 // Null items have no description
199 if( !aItem )
200 return wxString();
201
202 wxString msg = aItem->GetItemDescription( m_frame, true );
203
204 if( aItem->IsConnected() && !isNPTHPad( aItem ) )
205 {
206 BOARD_CONNECTED_ITEM* cItem = static_cast<BOARD_CONNECTED_ITEM*>( aItem );
207
208 msg += wxS( " " )
209 + wxString::Format( _( "[netclass %s]" ),
211 }
212
213 return msg;
214};
215
216
218 const VECTOR2I& aPos )
219{
220 std::vector<BOARD_ITEM*> toAdd;
221
222 for( int i = 0; i < aCollector.GetCount(); ++i )
223 {
224 if( aCollector[i]->Type() == PCB_GROUP_T )
225 {
226 PCB_GROUP* group = static_cast<PCB_GROUP*>( aCollector[i] );
227
228 group->RunOnChildren(
229 [&]( BOARD_ITEM* child )
230 {
231 if( child->Type() == PCB_GROUP_T )
232 return;
233
234 if( !child->HitTest( aPos ) )
235 return;
236
237 toAdd.push_back( child );
238
239 if( child->Type() == PCB_FOOTPRINT_T )
240 {
241 for( PAD* pad : static_cast<FOOTPRINT*>( child )->Pads() )
242 {
243 if( pad->HitTest( aPos ) )
244 toAdd.push_back( pad );
245 }
246 }
247 },
249 }
250 }
251
252 for( BOARD_ITEM* item : toAdd )
253 aCollector.Append( item );
254
255 bool hasPadOrTrack = false;
256
257 for( int i = 0; i < aCollector.GetCount(); ++i )
258 {
259 KICAD_T type = aCollector[i]->Type();
260
261 if( type == PCB_PAD_T || type == PCB_VIA_T || type == PCB_TRACE_T
262 || type == PCB_ARC_T || type == PCB_ZONE_T )
263 {
264 hasPadOrTrack = true;
265 break;
266 }
267 }
268
269 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
270 {
271 BOARD_ITEM* item = aCollector[i];
272
273 if( hasPadOrTrack && item->Type() == PCB_FOOTPRINT_T )
274 {
275 aCollector.Remove( i );
276 continue;
277 }
278
279 if( item->Type() == PCB_GROUP_T )
280 aCollector.Remove( i );
281 }
282}
283
284
286 const wxString& aPrompt,
287 const std::vector<KICAD_T>& aTypes,
288 BOARD_ITEM* aLockedHighlight )
289{
290 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
291 PCB_PICKER_TOOL* picker = m_toolMgr->GetTool<PCB_PICKER_TOOL>();
292 STATUS_TEXT_POPUP statusPopup( m_frame );
293 BOARD_ITEM* pickedItem = nullptr;
294 BOARD_ITEM* highlightedItem = nullptr;
295 bool done = false;
296
297 statusPopup.SetText( aPrompt );
298
299 picker->SetCursor( KICURSOR::BULLSEYE );
300 picker->SetSnapping( false );
301 picker->ClearHandlers();
302
303 picker->SetClickHandler(
304 [&]( const VECTOR2D& aPoint ) -> bool
305 {
307
308 GENERAL_COLLECTORS_GUIDE guide = m_frame->GetCollectorsGuide();
309 GENERAL_COLLECTOR collector;
310
311 collector.Collect( m_frame->GetBoard(), aTypes, aPoint, guide );
312
313 for( int i = collector.GetCount() - 1; i >= 0; --i )
314 {
315 if( !selTool->Selectable( collector[i] ) )
316 collector.Remove( i );
317 }
318
319 filterCollectorForInspection( collector, aPoint );
320
321 if( collector.GetCount() > 1 )
322 selTool->GuessSelectionCandidates( collector, aPoint );
323
324 if( collector.GetCount() == 0 )
325 return true;
326
327 pickedItem = collector[0];
328 statusPopup.Hide();
329
330 return false;
331 } );
332
333 picker->SetMotionHandler(
334 [&]( const VECTOR2D& aPos )
335 {
336 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
337
338 GENERAL_COLLECTORS_GUIDE guide = m_frame->GetCollectorsGuide();
339 GENERAL_COLLECTOR collector;
340
341 collector.Collect( m_frame->GetBoard(), aTypes, aPos, guide );
342
343 for( int i = collector.GetCount() - 1; i >= 0; --i )
344 {
345 if( !selTool->Selectable( collector[i] ) )
346 collector.Remove( i );
347 }
348
349 filterCollectorForInspection( collector, aPos );
350
351 if( collector.GetCount() > 1 )
352 selTool->GuessSelectionCandidates( collector, aPos );
353
354 BOARD_ITEM* item = collector.GetCount() >= 1 ? collector[0] : nullptr;
355
356 if( highlightedItem != item )
357 {
358 if( highlightedItem && highlightedItem != aLockedHighlight )
359 selTool->UnbrightenItem( highlightedItem );
360
361 highlightedItem = item;
362
363 if( highlightedItem && highlightedItem != aLockedHighlight )
364 selTool->BrightenItem( highlightedItem );
365 }
366 } );
367
368 picker->SetCancelHandler(
369 [&]()
370 {
371 if( highlightedItem && highlightedItem != aLockedHighlight )
372 selTool->UnbrightenItem( highlightedItem );
373
374 highlightedItem = nullptr;
375 statusPopup.Hide();
376 done = true;
377 } );
378
379 picker->SetFinalizeHandler(
380 [&]( const int& aFinalState )
381 {
382 if( highlightedItem && highlightedItem != aLockedHighlight )
383 selTool->UnbrightenItem( highlightedItem );
384
385 highlightedItem = nullptr;
386
387 if( !pickedItem )
388 done = true;
389 } );
390
391 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
392 statusPopup.Popup();
393 m_frame->GetCanvas()->SetStatusPopup( statusPopup.GetPanel() );
394
395 m_toolMgr->RunAction( ACTIONS::pickerTool, &aEvent );
396
397 while( !done && !pickedItem )
398 {
399 if( TOOL_EVENT* evt = Wait() )
400 evt->SetPassEvent();
401 else
402 break;
403 }
404
405 picker->ClearHandlers();
406 m_frame->GetCanvas()->SetStatusPopup( nullptr );
407
408 return pickedItem;
409}
410
411
413{
414 r->Report( "" );
415 r->Report( _( "Report incomplete: could not compile custom design rules." )
416 + wxS( "&nbsp;&nbsp;" )
417 + wxS( "<a href='$CUSTOM_RULES'>" ) + _( "Show design rules." ) + wxS( "</a>" ) );
418}
419
420
421void BOARD_INSPECTION_TOOL::reportHeader( const wxString& aTitle, BOARD_ITEM* a, REPORTER* r )
422{
423 r->Report( wxT( "<h7>" ) + EscapeHTML( aTitle ) + wxT( "</h7>" ) );
424 r->Report( wxT( "<ul><li>" ) + EscapeHTML( getItemDescription( a ) ) + wxT( "</li></ul>" ) );
425}
426
427
428void BOARD_INSPECTION_TOOL::reportHeader( const wxString& aTitle, BOARD_ITEM* a, BOARD_ITEM* b,
429 REPORTER* r )
430{
431 r->Report( wxT( "<h7>" ) + EscapeHTML( aTitle ) + wxT( "</h7>" ) );
432 r->Report( wxT( "<ul><li>" ) + EscapeHTML( getItemDescription( a ) ) + wxT( "</li>" )
433 + wxT( "<li>" ) + EscapeHTML( getItemDescription( b ) ) + wxT( "</li></ul>" ) );
434}
435
436
437void BOARD_INSPECTION_TOOL::reportHeader( const wxString& aTitle, BOARD_ITEM* a, BOARD_ITEM* b,
438 PCB_LAYER_ID aLayer, REPORTER* r )
439{
440 wxString layerStr = _( "Layer" ) + wxS( " " ) + m_frame->GetBoard()->GetLayerName( aLayer );
441
442 r->Report( wxT( "<h7>" ) + EscapeHTML( aTitle ) + wxT( "</h7>" ) );
443 r->Report( wxT( "<ul><li>" ) + EscapeHTML( layerStr ) + wxT( "</li>" )
444 + wxT( "<li>" ) + EscapeHTML( getItemDescription( a ) ) + wxT( "</li>" )
445 + wxT( "<li>" ) + EscapeHTML( getItemDescription( b ) ) + wxT( "</li></ul>" ) );
446}
447
448
449wxString reportMin( PCB_BASE_FRAME* aFrame, DRC_CONSTRAINT& aConstraint )
450{
451 if( aConstraint.m_Value.HasMin() )
452 return aFrame->StringFromValue( aConstraint.m_Value.Min(), true );
453 else
454 return wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
455}
456
457
458wxString reportOpt( PCB_BASE_FRAME* aFrame, DRC_CONSTRAINT& aConstraint )
459{
460 if( aConstraint.m_Value.HasOpt() )
461 return aFrame->StringFromValue( aConstraint.m_Value.Opt(), true );
462 else
463 return wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
464}
465
466
467wxString reportMax( PCB_BASE_FRAME* aFrame, DRC_CONSTRAINT& aConstraint )
468{
469 if( aConstraint.m_Value.HasMax() )
470 return aFrame->StringFromValue( aConstraint.m_Value.Max(), true );
471 else
472 return wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
473}
474
475
476wxString BOARD_INSPECTION_TOOL::InspectDRCErrorMenuText( const std::shared_ptr<RC_ITEM>& aDRCItem )
477{
478 if( aDRCItem->GetErrorCode() == DRCE_CLEARANCE
479 || aDRCItem->GetErrorCode() == DRCE_EDGE_CLEARANCE
480 || aDRCItem->GetErrorCode() == DRCE_HOLE_CLEARANCE
481 || aDRCItem->GetErrorCode() == DRCE_DRILLED_HOLES_TOO_CLOSE
482 || aDRCItem->GetErrorCode() == DRCE_STARVED_THERMAL )
483 {
484 return m_frame->GetRunMenuCommandDescription( PCB_ACTIONS::inspectClearance );
485 }
486 else if( aDRCItem->GetErrorCode() == DRCE_TEXT_HEIGHT
487 || aDRCItem->GetErrorCode() == DRCE_TEXT_THICKNESS
488 || aDRCItem->GetErrorCode() == DRCE_DIFF_PAIR_UNCOUPLED_LENGTH_TOO_LONG
489 || aDRCItem->GetErrorCode() == DRCE_TRACK_WIDTH
490 || aDRCItem->GetErrorCode() == DRCE_TRACK_ANGLE
491 || aDRCItem->GetErrorCode() == DRCE_TRACK_SEGMENT_LENGTH
492 || aDRCItem->GetErrorCode() == DRCE_VIA_DIAMETER
493 || aDRCItem->GetErrorCode() == DRCE_ANNULAR_WIDTH
494 || aDRCItem->GetErrorCode() == DRCE_DRILL_OUT_OF_RANGE
495 || aDRCItem->GetErrorCode() == DRCE_MICROVIA_DRILL_OUT_OF_RANGE
496 || aDRCItem->GetErrorCode() == DRCE_CONNECTION_WIDTH
497 || aDRCItem->GetErrorCode() == DRCE_ASSERTION_FAILURE )
498 {
499 return m_frame->GetRunMenuCommandDescription( PCB_ACTIONS::inspectConstraints );
500 }
501 else if( aDRCItem->GetErrorCode() == DRCE_LIB_FOOTPRINT_MISMATCH )
502 {
503 return m_frame->GetRunMenuCommandDescription( PCB_ACTIONS::diffFootprint );
504 }
505
506 return wxEmptyString;
507}
508
509
510void BOARD_INSPECTION_TOOL::InspectDRCError( const std::shared_ptr<RC_ITEM>& aDRCItem )
511{
512 DRC_TOOL* drcTool = m_toolMgr->GetTool<DRC_TOOL>();
513
514 wxCHECK( drcTool && m_frame, /* void */ );
515
516 BOARD_ITEM* a = m_frame->GetBoard()->ResolveItem( aDRCItem->GetMainItemID() );
517 BOARD_ITEM* b = m_frame->GetBoard()->ResolveItem( aDRCItem->GetAuxItemID() );
518 BOARD_CONNECTED_ITEM* ac = dynamic_cast<BOARD_CONNECTED_ITEM*>( a );
519 BOARD_CONNECTED_ITEM* bc = dynamic_cast<BOARD_CONNECTED_ITEM*>( b );
520 PCB_LAYER_ID layer = m_frame->GetActiveLayer();
521
522 if( aDRCItem->GetErrorCode() == DRCE_LIB_FOOTPRINT_MISMATCH )
523 {
524 if( FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( a ) )
525 DiffFootprint( footprint, drcTool->GetDRCDialog() );
526
527 return;
528 }
529
530 DIALOG_BOOK_REPORTER* dialog = m_frame->GetInspectDrcErrorDialog();
531 wxCHECK( dialog, /* void */ );
532
533 dialog->DeleteAllPages();
534
535 bool compileError = false;
536 bool courtyardError = false;
537 std::unique_ptr<DRC_ENGINE> drcEngine = makeDRCEngine( &compileError, &courtyardError );
538
539 WX_HTML_REPORT_BOX* r = nullptr;
540 DRC_CONSTRAINT constraint;
541 int clearance = 0;
542 wxString clearanceStr;
543
544 switch( aDRCItem->GetErrorCode() )
545 {
547 {
548 for( KIID id : aDRCItem->GetIDs() )
549 {
550 bc = dynamic_cast<BOARD_CONNECTED_ITEM*>( m_frame->GetBoard()->ResolveItem( id, true ) );
551
552 if( ac && bc && ac->GetNetCode() != bc->GetNetCode() )
553 break;
554 }
555
556 r = dialog->AddHTMLPage( _( "Uncoupled Length" ) );
557 reportHeader( _( "Diff pair uncoupled length resolution for:" ), ac, bc, r );
558
559 if( compileError )
561
562 constraint = drcEngine->EvalRules( MAX_UNCOUPLED_CONSTRAINT, a, b, layer, r );
563
564 r->Report( "" );
565 r->Report( wxString::Format( _( "Resolved max uncoupled length: %s." ),
566 reportMax( m_frame, constraint ) ) );
567 break;
568 }
569
570 case DRCE_TEXT_HEIGHT:
571 r = dialog->AddHTMLPage( _( "Text Height" ) );
572 reportHeader( _( "Text height resolution for:" ), a, r );
573
574 if( compileError )
576
577 constraint = drcEngine->EvalRules( TEXT_HEIGHT_CONSTRAINT, a, b, layer, r );
578
579 r->Report( "" );
580 r->Report( wxString::Format( _( "Resolved height constraints: min %s; max %s." ),
581 reportMin( m_frame, constraint ),
582 reportMax( m_frame, constraint ) ) );
583 break;
584
586 r = dialog->AddHTMLPage( _( "Text Thickness" ) );
587 reportHeader( _( "Text thickness resolution for:" ), a, r );
588
589 if( compileError )
591
592 constraint = drcEngine->EvalRules( TEXT_THICKNESS_CONSTRAINT, a, b, layer, r );
593
594 r->Report( "" );
595 r->Report( wxString::Format( _( "Resolved thickness constraints: min %s; max %s." ),
596 reportMin( m_frame, constraint ),
597 reportMax( m_frame, constraint ) ) );
598 break;
599
600 case DRCE_TRACK_WIDTH:
601 r = dialog->AddHTMLPage( _( "Track Width" ) );
602 reportHeader( _( "Track width resolution for:" ), a, r );
603
604 if( compileError )
606
607 constraint = drcEngine->EvalRules( TRACK_WIDTH_CONSTRAINT, a, b, layer, r );
608
609 r->Report( "" );
610 r->Report( wxString::Format( _( "Resolved width constraints: min %s; max %s." ),
611 reportMin( m_frame, constraint ),
612 reportMax( m_frame, constraint ) ) );
613 break;
614
615 case DRCE_TRACK_ANGLE:
616 r = dialog->AddHTMLPage( _( "Track Angle" ) );
617 reportHeader( _( "Track Angle resolution for:" ), a, r );
618
619 if( compileError )
621
622 constraint = drcEngine->EvalRules( TRACK_ANGLE_CONSTRAINT, a, b, layer, r );
623
624 r->Report( "" );
625 r->Report( wxString::Format( _( "Resolved angle constraints: min %s; max %s." ),
626 reportMin( m_frame, constraint ),
627 reportMax( m_frame, constraint ) ) );
628 break;
629
631 r = dialog->AddHTMLPage( _( "Track Segment Length" ) );
632 reportHeader( _( "Track segment length resolution for:" ), a, r );
633
634 if( compileError )
636
637 constraint = drcEngine->EvalRules( TRACK_SEGMENT_LENGTH_CONSTRAINT, a, b, layer, r );
638
639 r->Report( "" );
640 r->Report( wxString::Format( _( "Resolved segment length constraints: min %s; max %s." ),
641 reportMin( m_frame, constraint ),
642 reportMax( m_frame, constraint ) ) );
643 break;
644
646 r = dialog->AddHTMLPage( _( "Connection Width" ) );
647 reportHeader( _( "Connection width resolution for:" ), a, b, r );
648
649 if( compileError )
651
652 constraint = drcEngine->EvalRules( CONNECTION_WIDTH_CONSTRAINT, a, b, layer, r );
653
654 r->Report( "" );
655 r->Report( wxString::Format( _( "Resolved min connection width: %s." ),
656 reportMin( m_frame, constraint ) ) );
657 break;
658
660 r = dialog->AddHTMLPage( _( "Via Diameter" ) );
661 reportHeader( _( "Via diameter resolution for:" ), a, r );
662
663 if( compileError )
665
666 constraint = drcEngine->EvalRules( VIA_DIAMETER_CONSTRAINT, a, b, layer, r );
667
668 r->Report( "" );
669 r->Report( wxString::Format( _( "Resolved diameter constraints: min %s; max %s." ),
670 reportMin( m_frame, constraint ),
671 reportMax( m_frame, constraint ) ) );
672 break;
673
675 r = dialog->AddHTMLPage( _( "Via Annulus" ) );
676 reportHeader( _( "Via annular width resolution for:" ), a, r );
677
678 if( compileError )
680
681 constraint = drcEngine->EvalRules( ANNULAR_WIDTH_CONSTRAINT, a, b, layer, r );
682
683 r->Report( "" );
684 r->Report( wxString::Format( _( "Resolved annular width constraints: min %s; max %s." ),
685 reportMin( m_frame, constraint ),
686 reportMax( m_frame, constraint ) ) );
687 break;
688
691 r = dialog->AddHTMLPage( _( "Hole Size" ) );
692 reportHeader( _( "Hole size resolution for:" ), a, r );
693
694 if( compileError )
696
697 constraint = drcEngine->EvalRules( HOLE_SIZE_CONSTRAINT, a, b, layer, r );
698
699 r->Report( "" );
700 r->Report( wxString::Format( _( "Resolved hole size constraints: min %s; max %s." ),
701 reportMin( m_frame, constraint ),
702 reportMax( m_frame, constraint ) ) );
703 break;
704
706 r = dialog->AddHTMLPage( _( "Hole Clearance" ) );
707 reportHeader( _( "Hole clearance resolution for:" ), a, b, r );
708
709 if( compileError )
711
712 if( ac && bc && ac->GetNetCode() == bc->GetNetCode() )
713 {
714 r->Report( "" );
715 r->Report( _( "Items belong to the same net. Clearance is 0." ) );
716 }
717 else
718 {
719 constraint = drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, a, b, layer, r );
720 clearance = constraint.m_Value.Min();
721 clearanceStr = m_frame->StringFromValue( clearance, true );
722
723 r->Report( "" );
724 r->Report( wxString::Format( _( "Resolved min clearance: %s." ), clearanceStr ) );
725 }
726
727 r->Report( "" );
728 r->Report( "" );
729 r->Report( "" );
730 reportHeader( _( "Physical hole clearance resolution for:" ), a, b, layer, r );
731
732 constraint = drcEngine->EvalRules( PHYSICAL_HOLE_CLEARANCE_CONSTRAINT, a, b, layer, r );
733 clearance = constraint.m_Value.Min();
734 clearanceStr = m_frame->StringFromValue( clearance, true );
735
736 if( !drcEngine->HasRulesForConstraintType( PHYSICAL_HOLE_CLEARANCE_CONSTRAINT ) )
737 {
738 r->Report( "" );
739 r->Report( _( "No 'physical_hole_clearance' constraints defined." ) );
740 }
741 else
742 {
743 r->Report( "" );
744 r->Report( wxString::Format( _( "Resolved min clearance: %s." ), clearanceStr ) );
745 }
746
747 break;
748
750 r = dialog->AddHTMLPage( _( "Hole to Hole" ) );
751 reportHeader( _( "Hole-to-hole clearance resolution for:" ), a, b, r );
752
753 if( compileError )
755
756 constraint = drcEngine->EvalRules( HOLE_TO_HOLE_CONSTRAINT, a, b, UNDEFINED_LAYER, r );
757 clearance = constraint.m_Value.Min();
758 clearanceStr = m_frame->StringFromValue( clearance, true );
759
760 r->Report( "" );
761 r->Report( wxString::Format( _( "Resolved min clearance: %s." ), clearanceStr ) );
762 break;
763
765 r = dialog->AddHTMLPage( _( "Edge Clearance" ) );
766 reportHeader( _( "Edge clearance resolution for:" ), a, b, r );
767
768 if( compileError )
770
771 constraint = drcEngine->EvalRules( EDGE_CLEARANCE_CONSTRAINT, a, b, layer, r );
772 clearance = constraint.m_Value.Min();
773 clearanceStr = m_frame->StringFromValue( clearance, true );
774
775 r->Report( "" );
776 r->Report( wxString::Format( _( "Resolved min clearance: %s." ), clearanceStr ) );
777 break;
778
779 case DRCE_CLEARANCE:
780 if( a->Type() == PCB_TRACE_T || a->Type() == PCB_ARC_T )
781 {
782 layer = a->GetLayer();
783 }
784 else if( b->Type() == PCB_TRACE_T || b->Type() == PCB_ARC_T )
785 {
786 layer = b->GetLayer();
787 }
788 else if( a->Type() == PCB_PAD_T
789 && static_cast<PAD*>( a )->GetAttribute() == PAD_ATTRIB::SMD )
790 {
791 PAD* pad = static_cast<PAD*>( a );
792
793 if( pad->IsOnLayer( F_Cu ) )
794 layer = F_Cu;
795 else
796 layer = B_Cu;
797 }
798 else if( b->Type() == PCB_PAD_T
799 && static_cast<PAD*>( a )->GetAttribute() == PAD_ATTRIB::SMD )
800 {
801 PAD* pad = static_cast<PAD*>( b );
802
803 if( pad->IsOnLayer( F_Cu ) )
804 layer = F_Cu;
805 else
806 layer = B_Cu;
807 }
808
809 r = dialog->AddHTMLPage( _( "Clearance" ) );
810 reportHeader( _( "Clearance resolution for:" ), a, b, layer, r );
811
812 if( compileError )
814
815 if( ac && bc && ac->GetNetCode() == bc->GetNetCode() )
816 {
817 r->Report( "" );
818 r->Report( _( "Items belong to the same net. Clearance is 0." ) );
819 }
820 else
821 {
822 constraint = drcEngine->EvalRules( CLEARANCE_CONSTRAINT, a, b, layer, r );
823 clearance = constraint.m_Value.Min();
824 clearanceStr = m_frame->StringFromValue( clearance, true );
825
826 r->Report( "" );
827 r->Report( wxString::Format( _( "Resolved min clearance: %s." ), clearanceStr ) );
828 }
829
830 r->Report( "" );
831 r->Report( "" );
832 r->Report( "" );
833 reportHeader( _( "Physical clearance resolution for:" ), a, b, layer, r );
834
835 constraint = drcEngine->EvalRules( PHYSICAL_CLEARANCE_CONSTRAINT, a, b, layer, r );
836 clearance = constraint.m_Value.Min();
837 clearanceStr = m_frame->StringFromValue( clearance, true );
838
839 if( !drcEngine->HasRulesForConstraintType( PHYSICAL_CLEARANCE_CONSTRAINT ) )
840 {
841 r->Report( "" );
842 r->Report( _( "No 'physical_clearance' constraints defined." ) );
843 }
844 else
845 {
846 r->Report( "" );
847 r->Report( wxString::Format( _( "Resolved min clearance: %s." ), clearanceStr ) );
848 }
849
850 break;
851
853 r = dialog->AddHTMLPage( _( "Assertions" ) );
854 reportHeader( _( "Assertions for:" ), a, r );
855
856 if( compileError )
858
859 drcEngine->ProcessAssertions( a, []( const DRC_CONSTRAINT* c ){}, r );
860 break;
861
862 default:
863 return;
864 }
865
866 r->Flush();
867
868 KIPLATFORM::UI::ReparentWindow( dialog, drcTool->GetDRCDialog() );
869 dialog->Show( true );
870}
871
872
874{
875 wxCHECK( m_frame, 0 );
876
877 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
878
879 wxCHECK( selTool, 0 );
880
881 const PCB_SELECTION& selection = selTool->GetSelection();
882 BOARD_ITEM* firstItem = nullptr;
883 BOARD_ITEM* secondItem = nullptr;
884
885 if( selection.Size() == 2 )
886 {
887 if( !selection.GetItem( 0 )->IsBOARD_ITEM() || !selection.GetItem( 1 )->IsBOARD_ITEM() )
888 return 0;
889
890 firstItem = static_cast<BOARD_ITEM*>( selection.GetItem( 0 ) );
891 secondItem = static_cast<BOARD_ITEM*>( selection.GetItem( 1 ) );
892
893 reportClearance( firstItem, secondItem );
894 return 0;
895 }
896
897 // Selection size is not 2, so we need to use picker mode.
898 // If there is one item selected, use it as the first item.
899 if( selection.Size() == 1 && selection.GetItem( 0 )->IsBOARD_ITEM() )
900 firstItem = static_cast<BOARD_ITEM*>( selection.GetItem( 0 ) );
901
902 static const std::vector<KICAD_T> clearanceTypes = {
903 PCB_PAD_T,
904 PCB_VIA_T,
906 PCB_ARC_T,
911 };
912
913 Activate();
914
915 if( !firstItem )
916 {
917 firstItem = pickItemForInspection( aEvent,
918 _( "Select first item for clearance resolution..." ),
919 clearanceTypes, nullptr );
920
921 if( !firstItem )
922 return 0;
923 }
924
925 // Keep the first item highlighted while selecting the second
926 selTool->BrightenItem( firstItem );
927
928 secondItem = pickItemForInspection( aEvent,
929 _( "Select second item for clearance resolution..." ),
930 clearanceTypes, firstItem );
931
932 selTool->UnbrightenItem( firstItem );
933
934 if( !secondItem )
935 return 0;
936
937 if( firstItem == secondItem )
938 {
939 m_frame->ShowInfoBarError( _( "Select two different items for clearance resolution." ) );
940 return 0;
941 }
942
943 reportClearance( firstItem, secondItem );
944
945 return 0;
946}
947
948
950{
951 wxCHECK( m_frame && aItemA && aItemB, /* void */ );
952
953 BOARD_ITEM* a = aItemA;
954 BOARD_ITEM* b = aItemB;
955
956 if( a->Type() == PCB_GROUP_T )
957 {
958 PCB_GROUP* ag = static_cast<PCB_GROUP*>( a );
959
960 if( ag->GetItems().empty() )
961 {
962 m_frame->ShowInfoBarError( _( "Cannot generate clearance report on empty group." ) );
963 return;
964 }
965
966 a = static_cast<BOARD_ITEM*>( *ag->GetItems().begin() );
967 }
968
969 if( b->Type() == PCB_GROUP_T )
970 {
971 PCB_GROUP* bg = static_cast<PCB_GROUP*>( b );
972
973 if( bg->GetItems().empty() )
974 {
975 m_frame->ShowInfoBarError( _( "Cannot generate clearance report on empty group." ) );
976 return;
977 }
978
979 b = static_cast<BOARD_ITEM*>( *bg->GetItems().begin() );
980 }
981
982 if( !a || !b )
983 return;
984
985 auto checkFootprint =
986 [&]( FOOTPRINT* footprint ) -> BOARD_ITEM*
987 {
988 PAD* foundPad = nullptr;
989
990 for( PAD* pad : footprint->Pads() )
991 {
992 if( !foundPad || pad->SameLogicalPadAs( foundPad ) )
993 foundPad = pad;
994 else
995 return footprint;
996 }
997
998 if( !foundPad )
999 return footprint;
1000
1001 return foundPad;
1002 };
1003
1004 if( a->Type() == PCB_FOOTPRINT_T )
1005 a = checkFootprint( static_cast<FOOTPRINT*>( a ) );
1006
1007 if( b->Type() == PCB_FOOTPRINT_T )
1008 b = checkFootprint( static_cast<FOOTPRINT*>( b ) );
1009
1010 if( !a || !b )
1011 return;
1012
1013 DIALOG_BOOK_REPORTER* dialog = m_frame->GetInspectClearanceDialog();
1014
1015 wxCHECK( dialog, /* void */ );
1016
1017 dialog->DeleteAllPages();
1018
1019 if( a->Type() != PCB_ZONE_T && b->Type() == PCB_ZONE_T )
1020 std::swap( a, b );
1021 else if( !a->IsConnected() && b->IsConnected() )
1022 std::swap( a, b );
1023
1024 WX_HTML_REPORT_BOX* r = nullptr;
1025 PCB_LAYER_ID active = m_frame->GetActiveLayer();
1026 LSET layerIntersection = a->GetLayerSet() & b->GetLayerSet();
1027 LSET copperIntersection = layerIntersection & LSET::AllCuMask();
1028 BOARD_CONNECTED_ITEM* ac = dynamic_cast<BOARD_CONNECTED_ITEM*>( a );
1029 BOARD_CONNECTED_ITEM* bc = dynamic_cast<BOARD_CONNECTED_ITEM*>( b );
1030 ZONE* zone = dynamic_cast<ZONE*>( a );
1031 PAD* pad = dynamic_cast<PAD*>( b );
1032 FOOTPRINT* aFP = dynamic_cast<FOOTPRINT*>( a );
1033 FOOTPRINT* bFP = dynamic_cast<FOOTPRINT*>( b );
1034 DRC_CONSTRAINT constraint;
1035 int clearance = 0;
1036
1037 bool compileError = false;
1038 bool courtyardError = false;
1039 std::unique_ptr<DRC_ENGINE> drcEngine = makeDRCEngine( &compileError, &courtyardError );
1040
1041 if( copperIntersection.any() && zone && pad && zone->GetNetCode() == pad->GetNetCode() )
1042 {
1044
1045 if( zone->IsOnLayer( active ) )
1046 layer = active;
1047 else if( zone->GetLayerSet().count() > 0 )
1048 layer = zone->GetLayerSet().Seq().front();
1049
1050 r = dialog->AddHTMLPage( _( "Zone" ) );
1051 reportHeader( _( "Zone connection resolution for:" ), a, b, layer, r );
1052
1053 constraint = drcEngine->EvalZoneConnection( pad, zone, layer, r );
1054
1055 if( constraint.m_ZoneConnection == ZONE_CONNECTION::THERMAL )
1056 {
1057 r->Report( "" );
1058 r->Report( "" );
1059 reportHeader( _( "Thermal-relief gap resolution for:" ), a, b, layer, r );
1060
1061 constraint = drcEngine->EvalRules( THERMAL_RELIEF_GAP_CONSTRAINT, pad, zone, layer, r );
1062 int gap = constraint.m_Value.Min();
1063
1064 if( compileError )
1065 reportCompileError( r );
1066
1067 r->Report( "" );
1068 r->Report( wxString::Format( _( "Resolved thermal relief gap: %s." ),
1069 m_frame->StringFromValue( gap, true ) ) );
1070
1071 r->Report( "" );
1072 r->Report( "" );
1073 reportHeader( _( "Thermal-relief spoke width resolution for:" ), a, b, layer, r );
1074
1075 constraint = drcEngine->EvalRules( THERMAL_SPOKE_WIDTH_CONSTRAINT, pad, zone, layer, r );
1076 int width = constraint.m_Value.Opt();
1077
1078 if( compileError )
1079 reportCompileError( r );
1080
1081 r->Report( "" );
1082 r->Report( wxString::Format( _( "Resolved spoke width: %s." ),
1083 m_frame->StringFromValue( width, true ) ) );
1084
1085 r->Report( "" );
1086 r->Report( "" );
1087 reportHeader( _( "Thermal-relief min spoke count resolution for:" ), a, b, layer, r );
1088
1089 constraint = drcEngine->EvalRules( MIN_RESOLVED_SPOKES_CONSTRAINT, pad, zone, layer, r );
1090 int minSpokes = constraint.m_Value.Min();
1091
1092 if( compileError )
1093 reportCompileError( r );
1094
1095 r->Report( "" );
1096 r->Report( wxString::Format( _( "Resolved min spoke count: %d." ),
1097 minSpokes ) );
1098
1099 std::shared_ptr<CONNECTIVITY_DATA> connectivity = pad->GetBoard()->GetConnectivity();
1100 }
1101 else if( constraint.m_ZoneConnection == ZONE_CONNECTION::NONE )
1102 {
1103 r->Report( "" );
1104 r->Report( "" );
1105 reportHeader( _( "Zone clearance resolution for:" ), a, b, layer, r );
1106
1107 clearance = zone->GetLocalClearance().value();
1108 r->Report( "" );
1109 r->Report( wxString::Format( _( "Zone clearance: %s." ),
1110 m_frame->StringFromValue( clearance, true ) ) );
1111
1112 constraint = drcEngine->EvalRules( PHYSICAL_CLEARANCE_CONSTRAINT, pad, zone, layer, r );
1113
1114 if( constraint.m_Value.Min() > clearance )
1115 {
1116 clearance = constraint.m_Value.Min();
1117
1118 r->Report( "" );
1119 r->Report( wxString::Format( _( "Overridden by larger physical clearance from %s;"
1120 "clearance: %s." ),
1121 EscapeHTML( constraint.GetName() ),
1122 m_frame->StringFromValue( clearance, true ) ) );
1123 }
1124
1125 if( !pad->FlashLayer( layer ) )
1126 {
1127 constraint = drcEngine->EvalRules( PHYSICAL_HOLE_CLEARANCE_CONSTRAINT, pad, zone,
1128 layer, r );
1129
1130 if( constraint.m_Value.Min() > clearance )
1131 {
1132 clearance = constraint.m_Value.Min();
1133
1134 r->Report( "" );
1135 r->Report( wxString::Format( _( "Overridden by larger physical hole clearance "
1136 "from %s; clearance: %s." ),
1137 EscapeHTML( constraint.GetName() ),
1138 m_frame->StringFromValue( clearance, true ) ) );
1139 }
1140 }
1141
1142 if( compileError )
1143 reportCompileError( r );
1144
1145 r->Report( "" );
1146 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1147 m_frame->StringFromValue( clearance, true ) ) );
1148 }
1149 else
1150 {
1151 r->Report( "" );
1152 r->Report( "" );
1153 reportHeader( _( "Zone clearance resolution for:" ), a, b, layer, r );
1154
1155 if( compileError )
1156 reportCompileError( r );
1157
1158 r->Report( "" );
1159 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1160 m_frame->StringFromValue( 0, true ) ) );
1161 }
1162
1163 r->Flush();
1164 }
1165 else if( copperIntersection.any() && !aFP && !bFP )
1166 {
1167 PCB_LAYER_ID layer = active;
1168
1169 if( !copperIntersection.test( layer ) )
1170 layer = copperIntersection.Seq().front();
1171
1172 r = dialog->AddHTMLPage( m_frame->GetBoard()->GetLayerName( layer ) );
1173 reportHeader( _( "Clearance resolution for:" ), a, b, layer, r );
1174
1175 if( ac && bc && ac->GetNetCode() > 0 && ac->GetNetCode() == bc->GetNetCode() )
1176 {
1177 r->Report( _( "Items belong to the same net. Min clearance is 0." ) );
1178 }
1179 else
1180 {
1181 constraint = drcEngine->EvalRules( CLEARANCE_CONSTRAINT, a, b, layer, r );
1182 clearance = constraint.m_Value.Min();
1183
1184 if( compileError )
1185 reportCompileError( r );
1186
1187 r->Report( "" );
1188
1189 if( constraint.IsNull() )
1190 {
1191 r->Report( _( "Min clearance is 0." ) );
1192 }
1193 else if( clearance < 0 )
1194 {
1195 r->Report( wxString::Format( _( "Resolved clearance: %s; clearance will not be "
1196 "tested." ),
1197 m_frame->StringFromValue( clearance, true ) ) );
1198 }
1199 else
1200 {
1201 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1202 m_frame->StringFromValue( clearance, true ) ) );
1203 }
1204 }
1205
1206 r->Flush();
1207 }
1208
1209 if( ac && bc )
1210 {
1211 NETINFO_ITEM* refNet = ac->GetNet();
1212 wxString coupledNet;
1213 wxString dummy;
1214
1215 if( DRC_ENGINE::MatchDpSuffix( refNet->GetNetname(), coupledNet, dummy )
1216 && bc->GetNetname() == coupledNet )
1217 {
1218 r = dialog->AddHTMLPage( _( "Diff Pair" ) );
1219 reportHeader( _( "Diff-pair gap resolution for:" ), ac, bc, active, r );
1220
1221 constraint = drcEngine->EvalRules( DIFF_PAIR_GAP_CONSTRAINT, ac, bc, active, r );
1222
1223 r->Report( "" );
1224 r->Report( wxString::Format( _( "Resolved gap constraints: min %s; opt %s; max %s." ),
1225 reportMin( m_frame, constraint ),
1226 reportOpt( m_frame, constraint ),
1227 reportMax( m_frame, constraint ) ) );
1228
1229 r->Report( "" );
1230 r->Report( "" );
1231 r->Report( "" );
1232 reportHeader( _( "Diff-pair max uncoupled length resolution for:" ), ac, bc,
1233 active, r );
1234
1235 if( !drcEngine->HasRulesForConstraintType( MAX_UNCOUPLED_CONSTRAINT ) )
1236 {
1237 r->Report( "" );
1238 r->Report( _( "No 'diff_pair_uncoupled' constraints defined." ) );
1239 }
1240 else
1241 {
1242 constraint = drcEngine->EvalRules( MAX_UNCOUPLED_CONSTRAINT, ac, bc, active, r );
1243
1244 r->Report( "" );
1245 r->Report( wxString::Format( _( "Resolved max uncoupled length: %s." ),
1246 reportMax( m_frame, constraint ) ) );
1247 }
1248
1249 r->Flush();
1250 }
1251 }
1252
1253 auto isOnCorrespondingLayer=
1254 [&]( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer, wxString* aWarning )
1255 {
1256 if( aItem->IsOnLayer( aLayer ) )
1257 return true;
1258
1259 PCB_LAYER_ID correspondingMask = IsFrontLayer( aLayer ) ? F_Mask : B_Mask;
1260 PCB_LAYER_ID correspondingCopper = IsFrontLayer( aLayer ) ? F_Cu : B_Cu;
1261
1262 if( aItem->IsOnLayer( aLayer ) )
1263 return true;
1264
1265 if( aItem->IsOnLayer( correspondingMask ) )
1266 return true;
1267
1268 if( aItem->IsTented( correspondingMask ) && aItem->IsOnLayer( correspondingCopper ) )
1269 {
1270 *aWarning = wxString::Format( _( "Note: %s is tented; clearance will only be "
1271 "applied to holes." ),
1272 getItemDescription( aItem ) );
1273 return true;
1274 }
1275
1276 return false;
1277 };
1278
1279 for( PCB_LAYER_ID layer : { F_SilkS, B_SilkS } )
1280 {
1281 wxString warning;
1282
1283 if( ( a->IsOnLayer( layer ) && isOnCorrespondingLayer( b, layer, &warning ) )
1284 || ( b->IsOnLayer( layer ) && isOnCorrespondingLayer( a, layer, &warning ) ) )
1285 {
1286 r = dialog->AddHTMLPage( m_frame->GetBoard()->GetLayerName( layer ) );
1287 reportHeader( _( "Silkscreen clearance resolution for:" ), a, b, layer, r );
1288
1289 constraint = drcEngine->EvalRules( SILK_CLEARANCE_CONSTRAINT, a, b, layer, r );
1290 clearance = constraint.m_Value.Min();
1291
1292 if( compileError )
1293 reportCompileError( r );
1294
1295 r->Report( "" );
1296
1297 if( !warning.IsEmpty() )
1298 r->Report( warning );
1299
1300 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1301 m_frame->StringFromValue( clearance, true ) ) );
1302
1303 r->Flush();
1304 }
1305 }
1306
1307 for( PCB_LAYER_ID layer : { F_CrtYd, B_CrtYd } )
1308 {
1309 bool aCourtyard = aFP && !aFP->GetCourtyard( layer ).IsEmpty();
1310 bool bCourtyard = bFP && !bFP->GetCourtyard( layer ).IsEmpty();
1311
1312 if( aCourtyard && bCourtyard )
1313 {
1314 r = dialog->AddHTMLPage( m_frame->GetBoard()->GetLayerName( layer ) );
1315 reportHeader( _( "Courtyard clearance resolution for:" ), a, b, layer, r );
1316
1317 constraint = drcEngine->EvalRules( COURTYARD_CLEARANCE_CONSTRAINT, a, b, layer, r );
1318 clearance = constraint.m_Value.Min();
1319
1320 if( compileError )
1321 reportCompileError( r );
1322
1323 r->Report( "" );
1324 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1325 m_frame->StringFromValue( clearance, true ) ) );
1326
1327 r->Flush();
1328 }
1329 }
1330
1331 if( a->HasHole() || b->HasHole() )
1332 {
1334 bool pageAdded = false;
1335
1336 if( a->HasHole() && b->IsOnLayer( active ) && IsCopperLayer( active ) )
1337 layer = active;
1338 else if( b->HasHole() && a->IsOnLayer( active ) && IsCopperLayer( active ) )
1339 layer = active;
1340 else if( a->HasHole() && b->IsOnCopperLayer() )
1341 layer = b->GetLayer();
1342 else if( b->HasHole() && b->IsOnCopperLayer() )
1343 layer = a->GetLayer();
1344
1345 if( layer >= 0 )
1346 {
1347 r = dialog->AddHTMLPage( _( "Hole" ) );
1348 pageAdded = true;
1349
1350 reportHeader( _( "Hole clearance resolution for:" ), a, b, layer, r );
1351
1352 constraint = drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, a, b, layer, r );
1353 clearance = constraint.m_Value.Min();
1354
1355 if( compileError )
1356 reportCompileError( r );
1357
1358 r->Report( "" );
1359 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1360 m_frame->StringFromValue( clearance, true ) ) );
1361
1362 r->Flush();
1363 }
1364
1365 if( a->HasDrilledHole() || b->HasDrilledHole() )
1366 {
1367 if( !pageAdded )
1368 {
1369 r = dialog->AddHTMLPage( _( "Hole" ) );
1370 pageAdded = true;
1371 }
1372 else
1373 {
1374 r->Report( "" );
1375 r->Report( "" );
1376 r->Report( "" );
1377 }
1378
1379 reportHeader( _( "Hole-to-hole clearance resolution for:" ), a, b, r );
1380
1381 constraint = drcEngine->EvalRules( HOLE_TO_HOLE_CONSTRAINT, a, b, UNDEFINED_LAYER, r );
1382 clearance = constraint.m_Value.Min();
1383
1384 if( compileError )
1385 reportCompileError( r );
1386
1387 r->Report( "" );
1388 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1389 m_frame->StringFromValue( clearance, true ) ) );
1390
1391 r->Flush();
1392 }
1393 }
1394
1395 for( PCB_LAYER_ID edgeLayer : { Edge_Cuts, Margin } )
1396 {
1398
1399 if( a->IsOnLayer( edgeLayer ) && b->Type() != PCB_FOOTPRINT_T )
1400 {
1401 if( b->IsOnLayer( active ) && IsCopperLayer( active ) )
1402 layer = active;
1403 else if( IsCopperLayer( b->GetLayer() ) )
1404 layer = b->GetLayer();
1405 }
1406 else if( b->IsOnLayer( edgeLayer ) && a->Type() != PCB_FOOTPRINT_T )
1407 {
1408 if( a->IsOnLayer( active ) && IsCopperLayer( active ) )
1409 layer = active;
1410 else if( IsCopperLayer( a->GetLayer() ) )
1411 layer = a->GetLayer();
1412 }
1413
1414 if( layer >= 0 )
1415 {
1416 wxString layerName = m_frame->GetBoard()->GetLayerName( edgeLayer );
1417 r = dialog->AddHTMLPage( layerName + wxS( " " ) + _( "Clearance" ) );
1418 reportHeader( _( "Edge clearance resolution for:" ), a, b, layer, r );
1419
1420 constraint = drcEngine->EvalRules( EDGE_CLEARANCE_CONSTRAINT, a, b, layer, r );
1421 clearance = constraint.m_Value.Min();
1422
1423 if( compileError )
1424 reportCompileError( r );
1425
1426 r->Report( "" );
1427 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1428 m_frame->StringFromValue( clearance, true ) ) );
1429
1430 r->Flush();
1431 }
1432 }
1433
1434 r = dialog->AddHTMLPage( _( "Physical Clearances" ) );
1435
1436 if( compileError )
1437 {
1438 reportCompileError( r );
1439 }
1440 else if( !drcEngine->HasRulesForConstraintType( PHYSICAL_CLEARANCE_CONSTRAINT ) )
1441 {
1442 r->Report( "" );
1443 r->Report( _( "No 'physical_clearance' constraints defined." ) );
1444 }
1445 else
1446 {
1447 LSET reportLayers = layerIntersection;
1448 bool reported = false;
1449
1450 if( a->IsOnLayer( Edge_Cuts ) )
1451 {
1452 LSET edgeInteractingLayers = bFP ? LSET( { F_CrtYd, B_CrtYd } )
1454 reportLayers |= edgeInteractingLayers;
1455 }
1456
1457 if( b->IsOnLayer( Edge_Cuts ) )
1458 {
1459 LSET edgeInteractingLayers = aFP ? LSET( { F_CrtYd, B_CrtYd } )
1461 reportLayers |= edgeInteractingLayers;
1462 }
1463
1464 for( PCB_LAYER_ID layer : reportLayers )
1465 {
1466 reported = true;
1467 reportHeader( _( "Physical clearance resolution for:" ), a, b, layer, r );
1468
1469 constraint = drcEngine->EvalRules( PHYSICAL_CLEARANCE_CONSTRAINT, a, b, layer, r );
1470 clearance = constraint.m_Value.Min();
1471
1472 if( constraint.IsNull() )
1473 {
1474 r->Report( "" );
1475 r->Report( wxString::Format( _( "No 'physical_clearance' constraints in effect on %s." ),
1476 m_frame->GetBoard()->GetLayerName( layer ) ) );
1477 }
1478 else
1479 {
1480 r->Report( "" );
1481 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1482 m_frame->StringFromValue( clearance, true ) ) );
1483 }
1484
1485 r->Report( "" );
1486 r->Report( "" );
1487 r->Report( "" );
1488 }
1489
1490 if( !reported )
1491 {
1492 reportHeader( _( "Physical clearance resolution for:" ), a, b, r );
1493 r->Report( "" );
1494 r->Report( _( "Items share no relevant layers. No 'physical_clearance' constraints will "
1495 "be applied." ) );
1496 }
1497 }
1498
1499 if( a->HasHole() || b->HasHole() )
1500 {
1501 PCB_LAYER_ID layer;
1502
1503 if( a->HasHole() && b->IsOnLayer( active ) )
1504 layer = active;
1505 else if( b->HasHole() && a->IsOnLayer( active ) )
1506 layer = active;
1507 else if( a->HasHole() )
1508 layer = b->GetLayer();
1509 else
1510 layer = a->GetLayer();
1511
1512 reportHeader( _( "Physical hole clearance resolution for:" ), a, b, layer, r );
1513
1514 constraint = drcEngine->EvalRules( PHYSICAL_HOLE_CLEARANCE_CONSTRAINT, a, b, layer, r );
1515 clearance = constraint.m_Value.Min();
1516
1517 if( compileError )
1518 {
1519 reportCompileError( r );
1520 }
1521 else if( !drcEngine->HasRulesForConstraintType( PHYSICAL_HOLE_CLEARANCE_CONSTRAINT ) )
1522 {
1523 r->Report( "" );
1524 r->Report( _( "No 'physical_hole_clearance' constraints defined." ) );
1525 }
1526 else
1527 {
1528 r->Report( "" );
1529 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1530 m_frame->StringFromValue( clearance, true ) ) );
1531 }
1532 }
1533
1534 r->Flush();
1535
1536 dialog->Raise();
1537 dialog->Show( true );
1538}
1539
1540
1542{
1543#define EVAL_RULES( constraint, a, b, layer, r ) drcEngine->EvalRules( constraint, a, b, layer, r )
1544
1545 wxCHECK( m_frame, 0 );
1546
1547 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1548
1549 wxCHECK( selTool, 0 );
1550
1551 const PCB_SELECTION& selection = selTool->GetSelection();
1552 BOARD_ITEM* item = nullptr;
1553
1554 if( selection.Size() == 1 && selection.GetItem( 0 )->IsBOARD_ITEM() )
1555 {
1556 item = static_cast<BOARD_ITEM*>( selection.GetItem( 0 ) );
1557 }
1558 else if( selection.Size() == 0 )
1559 {
1560 static const std::vector<KICAD_T> constraintTypes = {
1561 PCB_PAD_T,
1562 PCB_VIA_T,
1564 PCB_ARC_T,
1565 PCB_ZONE_T,
1569 PCB_TEXT_T,
1572 };
1573
1574 Activate();
1575
1576 item = pickItemForInspection( aEvent, _( "Select item for constraints resolution..." ),
1577 constraintTypes, nullptr );
1578
1579 if( !item )
1580 return 0;
1581 }
1582 else
1583 {
1584 m_frame->ShowInfoBarError( _( "Select a single item for a constraints resolution report." ) );
1585 return 0;
1586 }
1587
1588 DIALOG_BOOK_REPORTER* dialog = m_frame->GetInspectConstraintsDialog();
1589
1590 wxCHECK( dialog, 0 );
1591
1592 dialog->DeleteAllPages();
1593 DRC_CONSTRAINT constraint;
1594
1595 bool compileError = false;
1596 bool courtyardError = false;
1597 std::unique_ptr<DRC_ENGINE> drcEngine = makeDRCEngine( &compileError, &courtyardError );
1598
1599 WX_HTML_REPORT_BOX* r = nullptr;
1600
1601 if( item->Type() == PCB_TRACE_T )
1602 {
1603 r = dialog->AddHTMLPage( _( "Track Width" ) );
1604 reportHeader( _( "Track width resolution for:" ), item, r );
1605
1606 constraint = EVAL_RULES( TRACK_WIDTH_CONSTRAINT, item, nullptr, item->GetLayer(), r );
1607
1608 if( compileError )
1609 reportCompileError( r );
1610
1611 r->Report( "" );
1612 r->Report( wxString::Format( _( "Resolved width constraints: min %s; opt %s; max %s." ),
1613 reportMin( m_frame, constraint ),
1614 reportOpt( m_frame, constraint ),
1615 reportMax( m_frame, constraint ) ) );
1616
1617 r->Flush();
1618 }
1619
1620 if( item->Type() == PCB_VIA_T )
1621 {
1622 r = dialog->AddHTMLPage( _( "Via Diameter" ) );
1623 reportHeader( _( "Via diameter resolution for:" ), item, r );
1624
1625 // PADSTACKS TODO: once we have padstacks we'll need to run this per-layer....
1626 constraint = EVAL_RULES( VIA_DIAMETER_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
1627
1628 if( compileError )
1629 reportCompileError( r );
1630
1631 r->Report( "" );
1632 r->Report( wxString::Format( _( "Resolved diameter constraints: min %s; opt %s; max %s." ),
1633 reportMin( m_frame, constraint ),
1634 reportOpt( m_frame, constraint ),
1635 reportMax( m_frame, constraint ) ) );
1636
1637 r->Flush();
1638
1639 r = dialog->AddHTMLPage( _( "Via Annular Width" ) );
1640 reportHeader( _( "Via annular width resolution for:" ), item, r );
1641
1642 // PADSTACKS TODO: once we have padstacks we'll need to run this per-layer....
1643 constraint = EVAL_RULES( ANNULAR_WIDTH_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
1644
1645 if( compileError )
1646 reportCompileError( r );
1647
1648 r->Report( "" );
1649 r->Report( wxString::Format( _( "Resolved annular width constraints: min %s; opt %s; max %s." ),
1650 reportMin( m_frame, constraint ),
1651 reportOpt( m_frame, constraint ),
1652 reportMax( m_frame, constraint ) ) );
1653
1654 r->Flush();
1655 }
1656
1657 if( ( item->Type() == PCB_PAD_T && static_cast<PAD*>( item )->GetDrillSize().x > 0 )
1658 || item->Type() == PCB_VIA_T )
1659 {
1660 r = dialog->AddHTMLPage( _( "Hole Size" ) );
1661 reportHeader( _( "Hole size resolution for:" ), item, r );
1662
1663 constraint = EVAL_RULES( HOLE_SIZE_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
1664
1665 if( compileError )
1666 reportCompileError( r );
1667
1668 r->Report( "" );
1669 r->Report( wxString::Format( _( "Resolved hole size constraints: min %s; opt %s; max %s." ),
1670 reportMin( m_frame, constraint ),
1671 reportOpt( m_frame, constraint ),
1672 reportMax( m_frame, constraint ) ) );
1673
1674 r->Flush();
1675 }
1676
1677 if( item->Type() == PCB_PAD_T || item->Type() == PCB_SHAPE_T || dynamic_cast<PCB_TRACK*>( item ) )
1678 {
1679 r = dialog->AddHTMLPage( _( "Solder Mask" ) );
1680 reportHeader( _( "Solder mask expansion resolution for:" ), item, r );
1681
1682 constraint = EVAL_RULES( SOLDER_MASK_EXPANSION_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
1683
1684 if( compileError )
1685 reportCompileError( r );
1686
1687 r->Report( "" );
1688 r->Report( wxString::Format( _( "Resolved solder mask expansion: %s." ),
1689 reportOpt( m_frame, constraint ) ) );
1690
1691 r->Flush();
1692 }
1693
1694 if( item->Type() == PCB_PAD_T )
1695 {
1696 r = dialog->AddHTMLPage( _( "Solder Paste" ) );
1697 reportHeader( _( "Solder paste absolute clearance resolution for:" ), item, r );
1698
1699 constraint = EVAL_RULES( SOLDER_PASTE_ABS_MARGIN_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
1700
1701 if( compileError )
1702 reportCompileError( r );
1703
1704 r->Report( "" );
1705 r->Report( wxString::Format( _( "Resolved solder paste absolute clearance: %s." ),
1706 reportOpt( m_frame, constraint ) ) );
1707
1708 reportHeader( _( "Solder paste relative clearance resolution for:" ), item, r );
1709
1710 constraint = EVAL_RULES( SOLDER_PASTE_REL_MARGIN_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
1711
1712 if( compileError )
1713 reportCompileError( r );
1714
1715 r->Report( "" );
1716 r->Report( "" );
1717 r->Report( "" );
1718 r->Report( wxString::Format( _( "Resolved solder paste relative clearance: %s." ),
1719 reportOpt( m_frame, constraint ) ) );
1720
1721 r->Flush();
1722 }
1723
1724 if( item->Type() == PCB_FIELD_T || item->Type() == PCB_TEXT_T || item->Type() == PCB_TEXTBOX_T )
1725 {
1726 r = dialog->AddHTMLPage( _( "Text Size" ) );
1727 reportHeader( _( "Text height resolution for:" ), item, r );
1728
1729 constraint = EVAL_RULES( TEXT_HEIGHT_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
1730
1731 if( compileError )
1732 reportCompileError( r );
1733
1734 r->Report( "" );
1735 r->Report( wxString::Format( _( "Resolved height constraints: min %s; opt %s; max %s." ),
1736 reportMin( m_frame, constraint ),
1737 reportOpt( m_frame, constraint ),
1738 reportMax( m_frame, constraint ) ) );
1739
1740 r->Report( "" );
1741 r->Report( "" );
1742 r->Report( "" );
1743 reportHeader( _( "Text thickness resolution for:" ), item, r );
1744
1745 constraint = EVAL_RULES( TEXT_THICKNESS_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
1746
1747 if( compileError )
1748 reportCompileError( r );
1749
1750 r->Report( "" );
1751 r->Report( wxString::Format( _( "Resolved thickness constraints: min %s; opt %s; max %s." ),
1752 reportMin( m_frame, constraint ),
1753 reportOpt( m_frame, constraint ),
1754 reportMax( m_frame, constraint ) ) );
1755
1756 r->Flush();
1757 }
1758
1759 r = dialog->AddHTMLPage( _( "Keepouts" ) );
1760 reportHeader( _( "Keepout resolution for:" ), item, r );
1761
1762 constraint = EVAL_RULES( DISALLOW_CONSTRAINT, item, nullptr, item->GetLayer(), r );
1763
1764 if( compileError )
1765 reportCompileError( r );
1766
1767 if( courtyardError )
1768 {
1769 r->Report( "" );
1770 r->Report( _( "Report may be incomplete: some footprint courtyards are malformed." )
1771 + wxS( "&nbsp;&nbsp;" )
1772 + wxS( "<a href='$DRC'>" ) + _( "Run DRC for a full analysis." )
1773 + wxS( "</a>" ) );
1774 }
1775
1776 r->Report( "" );
1777
1778 if( constraint.m_DisallowFlags )
1779 r->Report( _( "Item <b>disallowed</b> at current location." ) );
1780 else
1781 r->Report( _( "Item allowed at current location." ) );
1782
1783 r->Flush();
1784
1785 r = dialog->AddHTMLPage( _( "Assertions" ) );
1786 reportHeader( _( "Assertions for:" ), item, r );
1787
1788 if( compileError )
1789 reportCompileError( r );
1790
1791 if( courtyardError )
1792 {
1793 r->Report( "" );
1794 r->Report( _( "Report may be incomplete: some footprint courtyards are malformed." )
1795 + wxS( "&nbsp;&nbsp;" )
1796 + wxS( "<a href='$DRC'>" ) + _( "Run DRC for a full analysis." )
1797 + wxS( "</a>" ) );
1798 }
1799
1800 drcEngine->ProcessAssertions( item, []( const DRC_CONSTRAINT* c ){}, r );
1801 r->Flush();
1802
1803 dialog->Raise();
1804 dialog->Show( true );
1805 return 0;
1806}
1807
1808
1810{
1811 wxCHECK( m_frame, 0 );
1812
1813 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1814
1815 wxCHECK( selTool, 0 );
1816
1817 const PCB_SELECTION& selection = selTool->RequestSelection(
1818 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
1819 {
1820 // Iterate from the back so we don't have to worry about removals.
1821 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
1822 {
1823 BOARD_ITEM* item = aCollector[ i ];
1824
1825 if( !dynamic_cast<FOOTPRINT*>( item ) )
1826 aCollector.Remove( item );
1827 }
1828 } );
1829
1830 if( selection.Size() == 1 )
1831 DiffFootprint( static_cast<FOOTPRINT*>( selection.GetItem( 0 ) ) );
1832 else
1833 m_frame->ShowInfoBarError( _( "Select a footprint to diff with its library equivalent." ) );
1834
1835 return 0;
1836}
1837
1838
1840{
1841 wxCHECK( m_frame, 0 );
1842
1843 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1844
1845 wxCHECK( selTool, 0 );
1846
1847 const PCB_SELECTION& selection = selTool->GetSelection();
1848
1849 if( selection.Size() != 1 || selection.Front()->Type() != PCB_FOOTPRINT_T )
1850 {
1851 m_frame->ShowInfoBarError( _( "Select a footprint for a footprint associations report." ) );
1852 return 0;
1853 }
1854
1855 DIALOG_FOOTPRINT_ASSOCIATIONS dlg( m_frame, static_cast<FOOTPRINT*>( selection.Front() ) );
1856
1857 dlg.ShowModal();
1858
1859 return 0;
1860}
1861
1862
1863void BOARD_INSPECTION_TOOL::DiffFootprint( FOOTPRINT* aFootprint, wxTopLevelWindow* aReparentTo )
1864{
1865 DIALOG_BOOK_REPORTER* dialog = m_frame->GetFootprintDiffDialog();
1866
1867 wxCHECK( dialog, /* void */ );
1868
1869 dialog->DeleteAllPages();
1870 dialog->SetUserItemID( aFootprint->m_Uuid );
1871
1872 LIB_ID fpID = aFootprint->GetFPID();
1873 wxString libName = fpID.GetLibNickname();
1874 wxString fpName = fpID.GetLibItemName();
1875 WX_HTML_REPORT_BOX* r = nullptr;
1876
1877 r = dialog->AddHTMLPage( _( "Summary" ) );
1878
1879 r->Report( wxS( "<h7>" ) + _( "Board vs library diff for:" ) + wxS( "</h7>" ) );
1880 r->Report( wxS( "<ul><li>" ) + EscapeHTML( getItemDescription( aFootprint ) ) + wxS( "</li>" )
1881 + wxS( "<li>" ) + _( "Library: " ) + EscapeHTML( libName ) + wxS( "</li>" )
1882 + wxS( "<li>" ) + _( "Library item: " ) + EscapeHTML( fpName ) + wxS( "</li></ul>" ) );
1883
1884 r->Report( "" );
1885
1886 PROJECT* project = aFootprint->GetBoard()->GetProject();
1888
1889 if( !adapter->HasLibrary( libName, false ) )
1890 {
1891 r->Report( _( "The library is not included in the current configuration." )
1892 + wxS( "&nbsp;&nbsp;&nbsp" )
1893 + wxS( "<a href='$CONFIG'>" ) + _( "Manage Footprint Libraries" )
1894 + wxS( "</a>" ) );
1895
1896 }
1897 else if( !adapter->HasLibrary( libName, true ) )
1898 {
1899 r->Report( _( "The library is not enabled in the current configuration." )
1900 + wxS( "&nbsp;&nbsp;&nbsp" )
1901 + wxS( "<a href='$CONFIG'>" ) + _( "Manage Footprint Libraries" )
1902 + wxS( "</a>" ) );
1903
1904 }
1905 else
1906 {
1907 std::shared_ptr<FOOTPRINT> libFootprint;
1908
1909 try
1910 {
1911 libFootprint.reset( adapter->LoadFootprint( libName, fpName, true ) );
1912 }
1913 catch( const IO_ERROR& )
1914 {
1915 }
1916
1917 if( !libFootprint )
1918 {
1919 r->Report( wxString::Format( _( "The library no longer contains the item %s." ),
1920 fpName) );
1921 }
1922 else
1923 {
1924 if( !aFootprint->FootprintNeedsUpdate( libFootprint.get(), 0, r ) )
1925 r->Report( _( "No relevant differences detected." ) );
1926
1927 wxPanel* panel = dialog->AddBlankPage( _( "Visual" ) );
1929
1930 diff->DisplayDiff( aFootprint, libFootprint );
1931 }
1932 }
1933
1934 r->Flush();
1935
1936 if( aReparentTo )
1937 KIPLATFORM::UI::ReparentWindow( dialog, aReparentTo );
1938 else
1939 dialog->Raise();
1940
1941 dialog->Show( true );
1942}
1943
1944
1946{
1947 wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
1948
1949 FOOTPRINT_DIFF_WIDGET* diffWidget = new FOOTPRINT_DIFF_WIDGET( aParentPanel, m_frame->Kiway() );
1950
1951 sizer->Add( diffWidget, 1, wxEXPAND | wxALL, 5 );
1952 aParentPanel->SetSizer( sizer );
1953 aParentPanel->Layout();
1954
1955 return diffWidget;
1956}
1957
1958
1960{
1961 BOARD_ITEM* item = aEvent.Parameter<BOARD_ITEM*>();
1962
1963 m_frame->m_ProbingSchToPcb = true; // recursion guard
1964 {
1965 m_toolMgr->RunAction( ACTIONS::selectionClear );
1966
1967 if( item )
1968 m_toolMgr->RunAction<EDA_ITEM*>( ACTIONS::selectItem, item );
1969 }
1970 m_frame->m_ProbingSchToPcb = false;
1971
1972 bool request3DviewRedraw = frame()->GetPcbNewSettings()->m_Display.m_Live3DRefresh;
1973
1974 if( item && item->Type() != PCB_FOOTPRINT_T )
1975 request3DviewRedraw = false;
1976
1977 // Update 3D viewer highlighting
1978 if( request3DviewRedraw )
1979 m_frame->Update3DView( false, true );
1980
1981 return 0;
1982}
1983
1984
1985 bool BOARD_INSPECTION_TOOL::highlightNet( const VECTOR2D& aPosition, bool aUseSelection )
1986{
1987 BOARD* board = static_cast<BOARD*>( m_toolMgr->GetModel() );
1989 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1990
1991 int net = -1;
1992 bool enableHighlight = false;
1993
1994 if( aUseSelection )
1995 {
1996 const PCB_SELECTION& selection = selectionTool->GetSelection();
1997 std::set<int> netcodes;
1998
1999 for( EDA_ITEM* item : selection )
2000 {
2001 if( BOARD_CONNECTED_ITEM* ci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
2002 netcodes.insert( ci->GetNetCode() );
2003 }
2004
2005 enableHighlight = !netcodes.empty();
2006
2007 if( enableHighlight && netcodes.size() > 1 )
2008 {
2009 // If we are doing a multi-highlight, cross-probing back and other stuff is not
2010 // yet supported
2011 settings->SetHighlight( netcodes );
2012 board->ResetNetHighLight();
2013
2014 for( int multiNet : netcodes )
2015 board->SetHighLightNet( multiNet, true );
2016
2017 board->HighLightON();
2018 m_toolMgr->GetView()->UpdateAllLayersColor();
2019 m_currentlyHighlighted = netcodes;
2020 return true;
2021 }
2022 else if( enableHighlight )
2023 {
2024 net = *netcodes.begin();
2025 }
2026 }
2027
2028 // If we didn't get a net to highlight from the selection, use the cursor
2029 if( net < 0 )
2030 {
2031 GENERAL_COLLECTORS_GUIDE guide = m_frame->GetCollectorsGuide();
2032 guide.SetIgnoreZoneFills( false );
2033 guide.SetIgnoreNoNets( true );
2034
2035 PCB_LAYER_ID activeLayer = static_cast<PCB_LAYER_ID>( view()->GetTopLayer() );
2036 guide.SetPreferredLayer( activeLayer );
2037
2038 GENERAL_COLLECTOR collector;
2039 collector.Collect( board, { PCB_PAD_T, PCB_VIA_T, PCB_TRACE_T, PCB_ARC_T, PCB_SHAPE_T }, aPosition,
2040 guide );
2041
2042 if( collector.GetCount() == 0 )
2043 collector.Collect( board, { PCB_ZONE_T }, aPosition, guide );
2044
2045 // Apply the active selection filter, except we want to allow picking locked items for
2046 // highlighting even if the user has disabled them for selection
2047 PCB_SELECTION_FILTER_OPTIONS& filter = selectionTool->GetFilter();
2048
2049 bool saved = filter.lockedItems;
2050 filter.lockedItems = true;
2051
2052 selectionTool->FilterCollectedItems( collector, true, nullptr );
2053
2054 filter.lockedItems = saved;
2055
2056 // Clear the previous highlight
2057 //m_frame->SendMessageToEESCHEMA( nullptr );
2058
2059 bool highContrast = settings->GetHighContrast();
2060 PCB_LAYER_ID contrastLayer = settings->GetPrimaryHighContrastLayer();
2061
2062 for( int i = collector.GetCount() - 1; i >= 0; i-- )
2063 {
2064 LSET itemLayers = collector[i]->GetLayerSet();
2065
2066 if( ( itemLayers & LSET::AllCuMask() ).none() ||
2067 ( highContrast && !itemLayers.Contains( contrastLayer ) ) )
2068 {
2069 collector.Remove( i );
2070 continue;
2071 }
2072 }
2073
2074 enableHighlight = ( collector.GetCount() > 0 );
2075
2076 // Obtain net code for the clicked item
2077 if( enableHighlight )
2078 {
2079 BOARD_CONNECTED_ITEM* targetItem = static_cast<BOARD_CONNECTED_ITEM*>( collector[0] );
2080
2081 if( targetItem->Type() == PCB_PAD_T )
2082 m_frame->SendCrossProbeItem( targetItem );
2083
2084 net = targetItem->GetNetCode();
2085 }
2086 }
2087
2088 const std::set<int>& netcodes = settings->GetHighlightNetCodes();
2089
2090 // Toggle highlight when the same net was picked
2091 if( !aUseSelection && netcodes.size() == 1 && netcodes.contains( net ) )
2092 enableHighlight = !settings->IsHighlightEnabled();
2093
2094 if( enableHighlight != settings->IsHighlightEnabled() || !netcodes.count( net ) )
2095 {
2096 if( !netcodes.empty() )
2097 m_lastHighlighted = netcodes;
2098
2099 settings->SetHighlight( enableHighlight, net );
2100 m_toolMgr->GetView()->UpdateAllLayersColor();
2101 }
2102
2103 // Store the highlighted netcode in the current board (for dialogs for instance)
2104 if( enableHighlight && net >= 0 )
2105 {
2106 m_currentlyHighlighted = netcodes;
2107 board->SetHighLightNet( net );
2108 board->HighLightON();
2109
2110 NETINFO_ITEM* netinfo = board->FindNet( net );
2111
2112 if( netinfo )
2113 {
2114 std::vector<MSG_PANEL_ITEM> items;
2115 netinfo->GetMsgPanelInfo( m_frame, items );
2116 m_frame->SetMsgPanel( items );
2117 m_frame->SendCrossProbeNetName( netinfo->GetNetname() );
2118 }
2119 }
2120 else
2121 {
2122 m_currentlyHighlighted.clear();
2123 board->ResetNetHighLight();
2124 m_frame->SetMsgPanel( board );
2125 m_frame->SendCrossProbeNetName( "" );
2126 }
2127
2128 return true;
2129}
2130
2131
2133{
2134 int netcode = aEvent.Parameter<int>();
2135 KIGFX::RENDER_SETTINGS* settings = m_toolMgr->GetView()->GetPainter()->GetSettings();
2136 const std::set<int>& highlighted = settings->GetHighlightNetCodes();
2137
2138 if( netcode > 0 )
2139 {
2140 m_lastHighlighted = highlighted;
2141 settings->SetHighlight( true, netcode );
2142 m_toolMgr->GetView()->UpdateAllLayersColor();
2143 m_currentlyHighlighted.clear();
2144 m_currentlyHighlighted.insert( netcode );
2145 }
2146 else if( aEvent.IsAction( &PCB_ACTIONS::highlightNetSelection ) )
2147 {
2148 // Highlight selection (cursor position will be ignored)
2149 highlightNet( getViewControls()->GetMousePosition(), true );
2150 }
2151 else if( aEvent.IsAction( &PCB_ACTIONS::toggleLastNetHighlight ) )
2152 {
2153 std::set<int> temp = highlighted;
2154 settings->SetHighlight( m_lastHighlighted );
2155 m_toolMgr->GetView()->UpdateAllLayersColor();
2157 m_lastHighlighted = std::move( temp );
2158 }
2159 else if( aEvent.IsAction( &PCB_ACTIONS::toggleNetHighlight ) )
2160 {
2161 bool turnOn = highlighted.empty() && !m_currentlyHighlighted.empty();
2162 settings->SetHighlight( m_currentlyHighlighted, turnOn );
2163 m_toolMgr->GetView()->UpdateAllLayersColor();
2164 }
2165 else // Highlight the net belonging to the item under the cursor
2166 {
2167 highlightNet( getViewControls()->GetMousePosition(), false );
2168 }
2169
2170 return 0;
2171}
2172
2173
2175{
2176 BOARD* board = static_cast<BOARD*>( m_toolMgr->GetModel() );
2177 KIGFX::RENDER_SETTINGS* settings = m_toolMgr->GetView()->GetPainter()->GetSettings();
2178
2179 m_currentlyHighlighted.clear();
2180 m_lastHighlighted.clear();
2181
2182 board->ResetNetHighLight();
2183 settings->SetHighlight( false );
2184 m_toolMgr->GetView()->UpdateAllLayersColor();
2185 m_frame->SetMsgPanel( board );
2186 m_frame->SendCrossProbeNetName( "" );
2187 return 0;
2188}
2189
2190
2192{
2193 PCB_PICKER_TOOL* picker = m_toolMgr->GetTool<PCB_PICKER_TOOL>();
2194
2195 // Deactivate other tools; particularly important if another PICKER is currently running
2196 Activate();
2197
2198 picker->SetCursor( KICURSOR::BULLSEYE );
2199 picker->SetSnapping( false );
2200 picker->ClearHandlers();
2201
2202 picker->SetClickHandler(
2203 [this]( const VECTOR2D& pt ) -> bool
2204 {
2205 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
2206
2207 m_toolMgr->RunAction( ACTIONS::selectionClear );
2209 EDIT_TOOL::PadFilter );
2210
2211 PCB_SELECTION& selection = selectionTool->GetSelection();
2212
2213 if( selection.Empty() )
2214 {
2216 EDIT_TOOL::FootprintFilter );
2217 selection = selectionTool->GetSelection();
2218 }
2219
2220 if( selection.Empty() )
2221 {
2222 // Clear the previous local ratsnest if we click off all items
2223 for( FOOTPRINT* fp : getModel<BOARD>()->Footprints() )
2224 {
2225 for( PAD* pad : fp->Pads() )
2226 pad->SetLocalRatsnestVisible( displayOptions().m_ShowGlobalRatsnest );
2227 }
2228 }
2229 else
2230 {
2231 for( EDA_ITEM* item : selection )
2232 {
2233 if( PAD* pad = dyn_cast<PAD*>( item) )
2234 {
2235 pad->SetLocalRatsnestVisible( !pad->GetLocalRatsnestVisible() );
2236 }
2237 else if( FOOTPRINT* fp = dyn_cast<FOOTPRINT*>( item) )
2238 {
2239 if( !fp->Pads().empty() )
2240 {
2241 bool enable = !fp->Pads()[0]->GetLocalRatsnestVisible();
2242
2243 for( PAD* childPad : fp->Pads() )
2244 childPad->SetLocalRatsnestVisible( enable );
2245 }
2246 }
2247 }
2248 }
2249
2250 m_toolMgr->GetView()->MarkTargetDirty( KIGFX::TARGET_OVERLAY );
2251
2252 return true;
2253 } );
2254
2255 picker->SetFinalizeHandler(
2256 [this]( int aCondition )
2257 {
2258 if( aCondition != PCB_PICKER_TOOL::END_ACTIVATE )
2259 {
2260 for( FOOTPRINT* fp : getModel<BOARD>()->Footprints() )
2261 {
2262 for( PAD* pad : fp->Pads() )
2263 pad->SetLocalRatsnestVisible( displayOptions().m_ShowGlobalRatsnest );
2264 }
2265 }
2266 } );
2267
2268 m_toolMgr->RunAction( ACTIONS::pickerTool, &aEvent );
2269
2270 return 0;
2271}
2272
2273
2275{
2276 VECTOR2I delta = aEvent.Parameter<VECTOR2I>();
2277
2278 if( delta == VECTOR2I() )
2279 {
2280 // We can delete the existing map to force a recalculation
2281 delete m_dynamicData;
2282 m_dynamicData = nullptr;
2283 }
2284
2285 auto selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
2286 auto& selection = selectionTool->GetSelection();
2287 auto connectivity = getModel<BOARD>()->GetConnectivity();
2288
2289 if( selection.Empty() )
2290 {
2291 connectivity->ClearLocalRatsnest();
2292 delete m_dynamicData;
2293 m_dynamicData = nullptr;
2294 }
2295 else
2296 {
2298 }
2299
2300 return 0;
2301}
2302
2303
2305{
2306 getModel<BOARD>()->GetConnectivity()->ClearLocalRatsnest();
2307 delete m_dynamicData;
2308 m_dynamicData = nullptr;
2309
2310 return 0;
2311}
2312
2313
2315{
2316 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
2317 SELECTION& selection = selectionTool->GetSelection();
2318 std::shared_ptr<CONNECTIVITY_DATA> connectivity = board()->GetConnectivity();
2319 std::vector<BOARD_ITEM*> items;
2320 std::deque<EDA_ITEM*> queued_items( selection.begin(), selection.end() );
2321
2322 for( std::size_t i = 0; i < queued_items.size(); ++i )
2323 {
2324 if( !queued_items[i]->IsBOARD_ITEM() )
2325 continue;
2326
2327 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( queued_items[i] );
2328
2329 wxCHECK2( item, continue );
2330
2331 if( item->Type() == PCB_FOOTPRINT_T )
2332 {
2333 for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
2334 {
2335 if( pad->GetLocalRatsnestVisible() || displayOptions().m_ShowModuleRatsnest )
2336 items.push_back( pad );
2337 }
2338 }
2339 else if( item->Type() == PCB_GROUP_T || item->Type() == PCB_GENERATOR_T )
2340 {
2341 item->RunOnChildren( [ &queued_items ]( BOARD_ITEM *aItem )
2342 {
2343 queued_items.push_back( aItem );
2344 },
2346 }
2347 else if( BOARD_CONNECTED_ITEM* boardItem = dyn_cast<BOARD_CONNECTED_ITEM*>( item ) )
2348 {
2349 if( boardItem->GetLocalRatsnestVisible() || displayOptions().m_ShowModuleRatsnest )
2350 items.push_back( boardItem );
2351 }
2352 }
2353
2354 if( items.empty() || std::none_of( items.begin(), items.end(),
2355 []( const BOARD_ITEM* aItem )
2356 {
2357 return( aItem->Type() == PCB_TRACE_T
2358 || aItem->Type() == PCB_PAD_T
2359 || aItem->Type() == PCB_ARC_T
2360 || aItem->Type() == PCB_ZONE_T
2361 || aItem->Type() == PCB_FOOTPRINT_T
2362 || aItem->Type() == PCB_VIA_T
2363 || aItem->Type() == PCB_SHAPE_T );
2364 } ) )
2365 {
2366 return;
2367 }
2368
2369 if( !m_dynamicData )
2370 {
2371 m_dynamicData = new CONNECTIVITY_DATA( board()->GetConnectivity(), items, true );
2372 connectivity->BlockRatsnestItems( items );
2373 }
2374 else
2375 {
2376 m_dynamicData->Move( aDelta );
2377 }
2378
2379 connectivity->ComputeLocalRatsnest( items, m_dynamicData );
2380}
2381
2382
2384{
2385 doHideRatsnestNet( aEvent.Parameter<int>(), true );
2386 return 0;
2387}
2388
2389
2391{
2392 doHideRatsnestNet( aEvent.Parameter<int>(), false );
2393 return 0;
2394}
2395
2396
2397void BOARD_INSPECTION_TOOL::doHideRatsnestNet( int aNetCode, bool aHide )
2398{
2400 m_toolMgr->GetView()->GetPainter()->GetSettings() );
2401
2402 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
2403 SELECTION& selection = selectionTool->GetSelection();
2404
2405 if( aNetCode <= 0 && !selection.Empty() )
2406 {
2407 for( EDA_ITEM* item : selection )
2408 {
2409 if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
2410 {
2411 if( bci->GetNetCode() > 0 )
2412 doHideRatsnestNet( bci->GetNetCode(), aHide );
2413 }
2414 }
2415
2416 return;
2417 }
2418
2419 if( aHide )
2420 rs->GetHiddenNets().insert( aNetCode );
2421 else
2422 rs->GetHiddenNets().erase( aNetCode );
2423
2424 if( !m_frame->GetAppearancePanel()->IsTogglingNetclassRatsnestVisibility() )
2425 {
2426 m_frame->GetCanvas()->RedrawRatsnest();
2427 m_frame->GetCanvas()->Refresh();
2428
2429 m_frame->GetAppearancePanel()->OnNetVisibilityChanged( aNetCode, !aHide );
2430 }
2431}
2432
2433
2435{
2439
2445
2452
2455}
std::function< void(const VECTOR2I &, GENERAL_COLLECTOR &, PCB_SELECTION_TOOL *)> CLIENT_SELECTION_FILTER
Definition actions.h:37
#define EVAL_RULES(constraint, a, b, layer, r)
wxString reportMax(PCB_BASE_FRAME *aFrame, DRC_CONSTRAINT &aConstraint)
bool isNPTHPad(BOARD_ITEM *aItem)
wxString reportMin(PCB_BASE_FRAME *aFrame, DRC_CONSTRAINT &aConstraint)
wxString reportOpt(PCB_BASE_FRAME *aFrame, DRC_CONSTRAINT &aConstraint)
static TOOL_ACTION selectItem
Select an item (specified as the event parameter).
Definition actions.h:227
static TOOL_ACTION selectionCursor
Select a single item under the cursor position.
Definition actions.h:217
static TOOL_ACTION pickerTool
Definition actions.h:253
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:224
ACTION_MENU(bool isContextMenu, TOOL_INTERACTIVE *aTool=nullptr)
Default constructor.
void SetTitle(const wxString &aTitle) override
Set title for the menu.
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
wxMenuItem * Add(const wxString &aLabel, int aId, BITMAPS aIcon)
Add a wxWidgets-style entry to the menu.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
virtual NETCLASS * GetEffectiveNetClass() const
Return the NETCLASS for this item.
NETINFO_ITEM * GetNet() const
Return #NET_INFO object for a given item.
void InspectDRCError(const std::shared_ptr< RC_ITEM > &aDRCItem)
Show the clearance resolution for two selected items.
int HighlightNet(const TOOL_EVENT &aEvent)
Clear all board highlights.
void calculateSelectionRatsnest(const VECTOR2I &aDelta)
< Recalculate dynamic ratsnest for the current selection.
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
int ShowBoardStatistics(const TOOL_EVENT &aEvent)
Show dialog with board statistics.
wxString InspectDRCErrorMenuText(const std::shared_ptr< RC_ITEM > &aDRCItem)
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...
int DiffFootprint(const TOOL_EVENT &aEvent)
void reportClearance(BOARD_ITEM *aItemA, BOARD_ITEM *aItemB)
int LocalRatsnestTool(const TOOL_EVENT &aEvent)
Hide the ratsnest for a given net.
bool Init() override
Init() is called once upon a registration of the tool.
int ShowNetInRatsnest(const TOOL_EVENT &aEvent)
void reportCompileError(REPORTER *r)
int ClearHighlight(const TOOL_EVENT &aEvent)
Perform the appropriate action in response to an Eeschema cross-probe.
std::unique_ptr< DRC_ENGINE > makeDRCEngine(bool *aCompileError, bool *aCourtyardError)
int HideNetInRatsnest(const TOOL_EVENT &aEvent)
Show the ratsnest for a given net.
int InspectConstraints(const TOOL_EVENT &aEvent)
void doHideRatsnestNet(int aNetCode, bool aHide)
Bind handlers to corresponding TOOL_ACTIONs.
BOARD_ITEM * pickItemForInspection(const TOOL_EVENT &aEvent, const wxString &aPrompt, const std::vector< KICAD_T > &aTypes, BOARD_ITEM *aLockedHighlight)
wxString getItemDescription(BOARD_ITEM *aItem)
CONNECTIVITY_DATA * m_dynamicData
int ShowFootprintLinks(const TOOL_EVENT &aEvent)
void reportHeader(const wxString &aTitle, BOARD_ITEM *a, REPORTER *r)
void filterCollectorForInspection(GENERAL_COLLECTOR &aCollector, const VECTOR2I &aPos)
FOOTPRINT_DIFF_WIDGET * constructDiffPanel(wxPanel *aParentPanel)
int InspectClearance(const TOOL_EVENT &aEvent)
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
std::set< int > m_currentlyHighlighted
int UpdateLocalRatsnest(const TOOL_EVENT &aEvent)
Hide ratsnest for selected items. Called when there are no items selected.
int HideLocalRatsnest(const TOOL_EVENT &aEvent)
Show local ratsnest of a component.
int HighlightItem(const TOOL_EVENT &aEvent)
Update ratsnest for selected items.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition board_item.h:237
virtual bool IsConnected() const
Returns information if the object is derived from BOARD_CONNECTED_ITEM.
Definition board_item.h:139
virtual void Move(const VECTOR2I &aMoveVector)
Move this object.
Definition board_item.h:344
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Test to see if this object is on the given layer.
Definition board_item.h:319
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition board_item.h:257
virtual bool IsTented(PCB_LAYER_ID aLayer) const
Checks if the given object is tented (its copper shape is covered by solder mask) on a given side of ...
Definition board_item.h:178
virtual void RunOnChildren(const std::function< void(BOARD_ITEM *)> &aFunction, RECURSE_MODE aMode) const
Invoke a function on all children.
Definition board_item.h:213
virtual bool HasDrilledHole() const
Definition board_item.h:166
virtual bool IsOnCopperLayer() const
Definition board_item.h:156
virtual bool HasHole() const
Definition board_item.h:161
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:322
PROJECT * GetProject() const
Definition board.h:579
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition board.h:563
int GetCount() const
Return the number of objects in the list.
Definition collector.h:83
void Remove(int aIndex)
Remove the item at aIndex (first position is 0).
Definition collector.h:111
void Append(EDA_ITEM *item)
Add an item to the end of the list.
Definition collector.h:101
void AddMenu(ACTION_MENU *aMenu, const SELECTION_CONDITION &aCondition=SELECTION_CONDITIONS::ShowAlways, int aOrder=ANY_ORDER)
Add a submenu to the menu.
Dialog to show common board info.
wxPanel * AddBlankPage(const wxString &aTitle)
WX_HTML_REPORT_BOX * AddHTMLPage(const wxString &aTitle)
void SetUserItemID(const KIID &aID)
Dialog to show footprint library and symbol links.
bool Show(bool show) override
int ShowModal() override
wxString GetName() const
Definition drc_rule.h:195
int m_DisallowFlags
Definition drc_rule.h:230
ZONE_CONNECTION m_ZoneConnection
Definition drc_rule.h:231
MINOPTMAX< int > m_Value
Definition drc_rule.h:229
bool IsNull() const
Definition drc_rule.h:182
static int MatchDpSuffix(const wxString &aNetName, wxString &aComplementNet, wxString &aBaseDpName)
Check if the given net is a diff pair, returning its polarity and complement if so.
DIALOG_DRC * GetDRCDialog()
Definition drc_tool.h:64
std::unordered_set< EDA_ITEM * > & GetItems()
Definition eda_group.h:54
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:99
virtual wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const
Return a user-visible description string of this item.
Definition eda_item.cpp:154
const KIID m_Uuid
Definition eda_item.h:527
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:111
virtual bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const
Test if aPosition is inside or on the boundary of this item.
Definition eda_item.h:239
void DisplayDiff(FOOTPRINT *aBoardFootprint, std::shared_ptr< FOOTPRINT > &aLibFootprint)
Set the currently displayed symbol.
An interface to the global shared library manager that is schematic-specific and linked to one projec...
FOOTPRINT * LoadFootprint(const wxString &aNickname, const wxString &aName, bool aKeepUUID)
Load a FOOTPRINT having aName from the library given by aNickname.
bool FootprintNeedsUpdate(const FOOTPRINT *aLibFP, int aCompareFlags=0, REPORTER *aReporter=nullptr)
Return true if a board footprint differs from the library version.
const LIB_ID & GetFPID() const
Definition footprint.h:351
const SHAPE_POLY_SET & GetCourtyard(PCB_LAYER_ID aLayer) const
Used in DRC to test the courtyard area (a complex polygon).
A general implementation of a COLLECTORS_GUIDE.
Definition collectors.h:324
void SetIgnoreZoneFills(bool ignore)
Definition collectors.h:473
void SetPreferredLayer(PCB_LAYER_ID aLayer)
Definition collectors.h:390
void SetIgnoreNoNets(bool ignore)
Definition collectors.h:476
Used when the right click button is pressed, or when the select tool is in effect.
Definition collectors.h:207
void Collect(BOARD_ITEM *aItem, const std::vector< KICAD_T > &aScanList, const VECTOR2I &aRefPos, const COLLECTORS_GUIDE &aGuide)
Scan a BOARD_ITEM using this class's Inspector method, which does the collection.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
PCB specific render settings.
Definition pcb_painter.h:82
std::set< int > & GetHiddenNets()
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
const std::set< int > & GetHighlightNetCodes() const
Return the netcode of currently highlighted net.
PCB_LAYER_ID GetPrimaryHighContrastLayer() const
Return the board layer which is in high-contrast mode.
bool IsHighlightEnabled() const
Return current highlight setting.
void SetHighlight(bool aEnabled, int aNetcode=-1, bool aMulti=false)
Turns on/off highlighting.
virtual int GetTopLayer() const
Definition view.cpp:838
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition view.h:221
Definition kiid.h:49
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library tables.
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:49
const UTF8 & GetLibItemName() const
Definition lib_id.h:102
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:87
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:608
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition lset.cpp:313
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:599
static const LSET & PhysicalLayersMask()
Return a mask holding all layers which are physically realized.
Definition lset.cpp:697
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
Definition lset.h:63
T Min() const
Definition minoptmax.h:33
bool HasMax() const
Definition minoptmax.h:38
bool HasMin() const
Definition minoptmax.h:37
T Max() const
Definition minoptmax.h:34
T Opt() const
Definition minoptmax.h:35
bool HasOpt() const
Definition minoptmax.h:39
const wxString GetHumanReadableName() const
Gets the consolidated name of this netclass (which may be an aggregate).
Definition netclass.cpp:294
Handle the data for a net.
Definition netinfo.h:54
const wxString & GetNetname() const
Definition netinfo.h:112
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.
ACTION_MENU * create() const override
Return an instance of this class. It has to be overridden in inheriting classes.
Definition pad.h:55
const VECTOR2I & GetDrillSize() const
Definition pad.h:317
PAD_ATTRIB GetAttribute() const
Definition pad.h:563
static TOOL_ACTION highlightItem
static TOOL_ACTION toggleNetHighlight
static TOOL_ACTION highlightNet
static TOOL_ACTION hideNetInRatsnest
static TOOL_ACTION hideLocalRatsnest
static TOOL_ACTION showNetInRatsnest
static TOOL_ACTION toggleLastNetHighlight
static TOOL_ACTION inspectConstraints
static TOOL_ACTION clearHighlight
static TOOL_ACTION inspectClearance
static TOOL_ACTION updateLocalRatsnest
static TOOL_ACTION diffFootprint
static TOOL_ACTION showFootprintAssociations
static TOOL_ACTION highlightNetSelection
static TOOL_ACTION boardStatistics
static TOOL_ACTION localRatsnestTool
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
A set of BOARD_ITEMs (i.e., without duplicates).
Definition pcb_group.h:53
Generic tool for picking an item.
The selection tool: currently supports:
void GuessSelectionCandidates(GENERAL_COLLECTOR &aCollector, const VECTOR2I &aWhere) const
Try to guess best selection candidates in case multiple items are clicked, by doing some brain-dead h...
PCB_SELECTION & RequestSelection(CLIENT_SELECTION_FILTER aClientFilter)
Return the current selection, filtered according to aClientFilter.
bool Selectable(const BOARD_ITEM *aItem, bool checkVisibilityOnly=false) const
PCB_SELECTION_FILTER_OPTIONS & GetFilter()
Set up handlers for various events.
PCB_SELECTION & GetSelection()
void FilterCollectedItems(GENERAL_COLLECTOR &aCollector, bool aMultiSelect, PCB_SELECTION_FILTER_OPTIONS *aRejected=nullptr)
Apply the SELECTION_FITLER_OPTIONS to the collector.
T * frame() const
KIGFX::PCB_VIEW * view() const
PCB_TOOL_BASE(TOOL_ID aId, const std::string &aName)
Constructor.
BOARD * board() const
PCBNEW_SETTINGS::DISPLAY_OPTIONS & displayOptions() const
const PCB_SELECTION & selection() const
FOOTPRINT * footprint() const
void SetClickHandler(CLICK_HANDLER aHandler)
Set a handler for mouse click event.
Definition picker_tool.h:81
void SetSnapping(bool aSnap)
Definition picker_tool.h:66
void SetCursor(KICURSOR aCursor)
Definition picker_tool.h:64
void SetFinalizeHandler(FINALIZE_HANDLER aHandler)
Set a handler for the finalize event.
static FOOTPRINT_LIBRARY_ADAPTER * FootprintLibAdapter(PROJECT *aProject)
Container for project specific data.
Definition project.h:65
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:73
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition reporter.h:102
void BrightenItem(EDA_ITEM *aItem)
void UnbrightenItem(EDA_ITEM *aItem)
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
Extension of STATUS_POPUP for displaying a single line text.
T * getEditFrame() const
Return the application window object, casted to requested user type.
Definition tool_base.h:186
T * getModel() const
Return the model object if it matches the requested type.
Definition tool_base.h:198
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition tool_base.cpp:44
TOOL_MANAGER * m_toolMgr
Definition tool_base.h:220
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition tool_base.cpp:38
RESET_REASON
Determine the reason of reset for a tool.
Definition tool_base.h:78
Generic, UI-independent tool event.
Definition tool_event.h:171
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
T Parameter() const
Return a parameter assigned to the event.
Definition tool_event.h:473
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).
TOOL_MENU & GetToolMenu()
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Suspend execution of the tool until an event specified in aEventList arrives.
void Activate()
Run the tool.
CONDITIONAL_MENU & GetMenu()
Definition tool_menu.cpp:44
void RegisterSubMenu(std::shared_ptr< ACTION_MENU > aSubMenu)
Store a submenu of this menu model.
Definition tool_menu.cpp:50
wxString StringFromValue(double aValue, bool aAddUnitLabel=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
Converts aValue in internal units into a united string.
A slimmed down version of WX_HTML_REPORT_PANEL.
REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED) override
Report a string with a given severity.
void Flush()
Build the HTML messages page.
Handle a list of polygons defining a copper zone.
Definition zone.h:73
std::optional< int > GetLocalClearance() const override
Definition zone.cpp:846
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Test to see if this object is on the given layer.
Definition zone.cpp:644
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition zone.h:136
@ BULLSEYE
Definition cursors.h:58
@ DRCE_HOLE_CLEARANCE
Definition drc_item.h:55
@ DRCE_VIA_DIAMETER
Definition drc_item.h:62
@ DRCE_TRACK_WIDTH
Definition drc_item.h:56
@ DRCE_DRILL_OUT_OF_RANGE
Definition drc_item.h:61
@ DRCE_EDGE_CLEARANCE
Definition drc_item.h:47
@ DRCE_STARVED_THERMAL
Definition drc_item.h:50
@ DRCE_TRACK_SEGMENT_LENGTH
Definition drc_item.h:58
@ DRCE_TRACK_ANGLE
Definition drc_item.h:57
@ DRCE_CLEARANCE
Definition drc_item.h:44
@ DRCE_DRILLED_HOLES_TOO_CLOSE
Definition drc_item.h:53
@ DRCE_DIFF_PAIR_UNCOUPLED_LENGTH_TOO_LONG
Definition drc_item.h:108
@ DRCE_MICROVIA_DRILL_OUT_OF_RANGE
Definition drc_item.h:65
@ DRCE_TEXT_HEIGHT
Definition drc_item.h:101
@ DRCE_ASSERTION_FAILURE
Definition drc_item.h:89
@ DRCE_LIB_FOOTPRINT_MISMATCH
Definition drc_item.h:84
@ DRCE_TEXT_THICKNESS
Definition drc_item.h:102
@ DRCE_CONNECTION_WIDTH
Definition drc_item.h:60
@ DRCE_ANNULAR_WIDTH
Definition drc_item.h:59
@ ANNULAR_WIDTH_CONSTRAINT
Definition drc_rule.h:61
@ COURTYARD_CLEARANCE_CONSTRAINT
Definition drc_rule.h:55
@ VIA_DIAMETER_CONSTRAINT
Definition drc_rule.h:70
@ DIFF_PAIR_GAP_CONSTRAINT
Definition drc_rule.h:73
@ DISALLOW_CONSTRAINT
Definition drc_rule.h:69
@ TRACK_WIDTH_CONSTRAINT
Definition drc_rule.h:59
@ SILK_CLEARANCE_CONSTRAINT
Definition drc_rule.h:56
@ EDGE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:53
@ MIN_RESOLVED_SPOKES_CONSTRAINT
Definition drc_rule.h:65
@ TRACK_SEGMENT_LENGTH_CONSTRAINT
Definition drc_rule.h:60
@ TEXT_THICKNESS_CONSTRAINT
Definition drc_rule.h:58
@ PHYSICAL_HOLE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:78
@ CLEARANCE_CONSTRAINT
Definition drc_rule.h:49
@ THERMAL_SPOKE_WIDTH_CONSTRAINT
Definition drc_rule.h:64
@ CONNECTION_WIDTH_CONSTRAINT
Definition drc_rule.h:80
@ THERMAL_RELIEF_GAP_CONSTRAINT
Definition drc_rule.h:63
@ MAX_UNCOUPLED_CONSTRAINT
Definition drc_rule.h:74
@ HOLE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:51
@ SOLDER_PASTE_ABS_MARGIN_CONSTRAINT
Definition drc_rule.h:67
@ SOLDER_MASK_EXPANSION_CONSTRAINT
Definition drc_rule.h:66
@ TRACK_ANGLE_CONSTRAINT
Definition drc_rule.h:81
@ HOLE_SIZE_CONSTRAINT
Definition drc_rule.h:54
@ TEXT_HEIGHT_CONSTRAINT
Definition drc_rule.h:57
@ PHYSICAL_CLEARANCE_CONSTRAINT
Definition drc_rule.h:77
@ SOLDER_PASTE_REL_MARGIN_CONSTRAINT
Definition drc_rule.h:68
@ HOLE_TO_HOLE_CONSTRAINT
Definition drc_rule.h:52
#define _(s)
@ RECURSE
Definition eda_item.h:52
#define MALFORMED_COURTYARDS
bool IsFrontLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a front layer.
Definition layer_ids.h:780
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:677
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ F_CrtYd
Definition layer_ids.h:116
@ Edge_Cuts
Definition layer_ids.h:112
@ B_Mask
Definition layer_ids.h:98
@ B_Cu
Definition layer_ids.h:65
@ F_Mask
Definition layer_ids.h:97
@ Margin
Definition layer_ids.h:113
@ F_SilkS
Definition layer_ids.h:100
@ B_CrtYd
Definition layer_ids.h:115
@ UNDEFINED_LAYER
Definition layer_ids.h:61
@ B_SilkS
Definition layer_ids.h:101
@ F_Cu
Definition layer_ids.h:64
@ TARGET_OVERLAY
Items that may change while the view stays the same (noncached)
Definition definitions.h:39
void ReparentWindow(wxNonOwnedWindow *aWindow, wxTopLevelWindow *aParent)
Definition wxgtk/ui.cpp:174
wxPoint GetMousePosition()
Returns the mouse position in screen coordinates.
Definition wxgtk/ui.cpp:721
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:103
@ SMD
Smd pad, appears on the solder paste layer (default)
Definition padstack.h:99
Class to handle a set of BOARD_ITEMs.
std::vector< FAB_LAYER_COLOR > dummy
wxString EscapeHTML(const wxString &aString)
Return a new wxString escaped for embedding in HTML.
A filename or source description, a problem input line, a line number, a byte offset,...
This file contains data structures that are saved in the project file or project local settings file ...
int clearance
int delta
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:78
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:88
@ PCB_GENERATOR_T
class PCB_GENERATOR, generator on a layer
Definition typeinfo.h:91
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:97
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition typeinfo.h:111
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:93
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition typeinfo.h:108
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:92
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition typeinfo.h:90
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition typeinfo.h:86
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:87
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:98
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:96
Casted dyn_cast(From aObject)
A lightweight dynamic downcast.
Definition typeinfo.h:61
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694
@ THERMAL
Use thermal relief for pads.
Definition zones.h:50
@ NONE
Pads are not covered.
Definition zones.h:49