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