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 <pcb_group.h>
26#include <tool/tool_manager.h>
29#include <tools/edit_tool.h>
30#include <pcb_painter.h>
32#include <drc/drc_engine.h>
37#include <string_utils.h>
39#include <fp_lib_table.h>
40#include <pcb_shape.h>
41#include <pcbnew_settings.h>
45#include <drc/drc_item.h>
46#include <pad.h>
47#include <project_pcb.h>
48#include <view/view_controls.h>
49
50
52 PCB_TOOL_BASE( "pcbnew.InspectionTool" ),
53 m_frame( nullptr )
54{
55 m_dynamicData = nullptr;
56}
57
58
60{
61public:
63 {
64 SetIcon( BITMAPS::show_ratsnest );
65 SetTitle( _( "Net Inspection Tools" ) );
66
69 AppendSeparator();
72 }
73
74private:
75 ACTION_MENU* create() const override
76 {
77 return new NET_CONTEXT_MENU();
78 }
79};
80
81
83{
85
86 std::shared_ptr<NET_CONTEXT_MENU> netSubMenu = std::make_shared<NET_CONTEXT_MENU>();
87 netSubMenu->SetTool( this );
88
89 // Only show the net menu if all items in the selection are connectable
90 auto showNetMenuFunc =
91 []( const SELECTION& aSelection )
92 {
93 if( aSelection.Empty() )
94 return false;
95
96 for( const EDA_ITEM* item : aSelection )
97 {
98 switch( item->Type() )
99 {
100 case PCB_TRACE_T:
101 case PCB_ARC_T:
102 case PCB_VIA_T:
103 case PCB_PAD_T:
104 case PCB_ZONE_T:
105 continue;
106
107 case PCB_SHAPE_T:
108 {
109 if( !static_cast<const PCB_SHAPE*>( item )->IsOnCopperLayer() )
110 return false;
111 else
112 continue;
113 }
114
115 default:
116 return false;
117 }
118 }
119
120 return true;
121 };
122
123 CONDITIONAL_MENU& menu = selectionTool->GetToolMenu().GetMenu();
124
125 selectionTool->GetToolMenu().RegisterSubMenu( netSubMenu );
126
127 menu.AddMenu( netSubMenu.get(), showNetMenuFunc, 100 );
128
129 return true;
130}
131
132
134{
135 m_frame = getEditFrame<PCB_EDIT_FRAME>();
136}
137
138
140{
142 dialog.ShowModal();
143 return 0;
144}
145
146
147std::unique_ptr<DRC_ENGINE> BOARD_INSPECTION_TOOL::makeDRCEngine( bool* aCompileError,
148 bool* aCourtyardError )
149{
150 auto engine = std::make_unique<DRC_ENGINE>( m_frame->GetBoard(),
152
153 try
154 {
155 engine->InitEngine( m_frame->GetDesignRulesPath() );
156 }
157 catch( PARSE_ERROR& )
158 {
159 if( aCompileError )
160 *aCompileError = true;
161 }
162
163 for( ZONE* zone : m_frame->GetBoard()->Zones() )
164 zone->CacheBoundingBox();
165
167 {
168 for( ZONE* zone : footprint->Zones() )
169 zone->CacheBoundingBox();
170
172
173 if( aCourtyardError && ( footprint->GetFlags() & MALFORMED_COURTYARDS ) != 0 )
174 *aCourtyardError = true;
175 }
176
177 return engine;
178}
179
180
181bool isNPTHPad( BOARD_ITEM* aItem )
182{
183 return aItem->Type() == PCB_PAD_T
184 && static_cast<PAD*>( aItem )->GetAttribute() == PAD_ATTRIB::NPTH;
185}
186
187
189{
190 // Null items have no description
191 if( !aItem )
192 return wxString();
193
194 wxString msg = aItem->GetItemDescription( m_frame, true );
195
196 if( aItem->IsConnected() && !isNPTHPad( aItem ) )
197 {
198 BOARD_CONNECTED_ITEM* cItem = static_cast<BOARD_CONNECTED_ITEM*>( aItem );
199
200 msg += wxS( " " )
201 + wxString::Format( _( "[netclass %s]" ),
203 }
204
205 return msg;
206};
207
208
210{
211 r->Report( "" );
212 r->Report( _( "Report incomplete: could not compile custom design rules." )
213 + wxS( "&nbsp;&nbsp;" )
214 + wxS( "<a href='$CUSTOM_RULES'>" ) + _( "Show design rules." ) + wxS( "</a>" ) );
215}
216
217
218void BOARD_INSPECTION_TOOL::reportHeader( const wxString& aTitle, BOARD_ITEM* a, REPORTER* r )
219{
220 r->Report( wxT( "<h7>" ) + EscapeHTML( aTitle ) + wxT( "</h7>" ) );
221 r->Report( wxT( "<ul><li>" ) + EscapeHTML( getItemDescription( a ) ) + wxT( "</li></ul>" ) );
222}
223
224
225void BOARD_INSPECTION_TOOL::reportHeader( const wxString& aTitle, BOARD_ITEM* a, BOARD_ITEM* b,
226 REPORTER* r )
227{
228 r->Report( wxT( "<h7>" ) + EscapeHTML( aTitle ) + wxT( "</h7>" ) );
229 r->Report( wxT( "<ul><li>" ) + EscapeHTML( getItemDescription( a ) ) + wxT( "</li>" )
230 + wxT( "<li>" ) + EscapeHTML( getItemDescription( b ) ) + wxT( "</li></ul>" ) );
231}
232
233
234void BOARD_INSPECTION_TOOL::reportHeader( const wxString& aTitle, BOARD_ITEM* a, BOARD_ITEM* b,
235 PCB_LAYER_ID aLayer, REPORTER* r )
236{
237 wxString layerStr = _( "Layer" ) + wxS( " " ) + m_frame->GetBoard()->GetLayerName( aLayer );
238
239 r->Report( wxT( "<h7>" ) + EscapeHTML( aTitle ) + wxT( "</h7>" ) );
240 r->Report( wxT( "<ul><li>" ) + EscapeHTML( layerStr ) + wxT( "</li>" )
241 + wxT( "<li>" ) + EscapeHTML( getItemDescription( a ) ) + wxT( "</li>" )
242 + wxT( "<li>" ) + EscapeHTML( getItemDescription( b ) ) + wxT( "</li></ul>" ) );
243}
244
245
246wxString reportMin( PCB_BASE_FRAME* aFrame, DRC_CONSTRAINT& aConstraint )
247{
248 if( aConstraint.m_Value.HasMin() )
249 return aFrame->StringFromValue( aConstraint.m_Value.Min(), true );
250 else
251 return wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
252}
253
254
255wxString reportOpt( PCB_BASE_FRAME* aFrame, DRC_CONSTRAINT& aConstraint )
256{
257 if( aConstraint.m_Value.HasOpt() )
258 return aFrame->StringFromValue( aConstraint.m_Value.Opt(), true );
259 else
260 return wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
261}
262
263
264wxString reportMax( PCB_BASE_FRAME* aFrame, DRC_CONSTRAINT& aConstraint )
265{
266 if( aConstraint.m_Value.HasMax() )
267 return aFrame->StringFromValue( aConstraint.m_Value.Max(), true );
268 else
269 return wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
270}
271
272
273wxString BOARD_INSPECTION_TOOL::InspectDRCErrorMenuText( const std::shared_ptr<RC_ITEM>& aDRCItem )
274{
275 auto menuDescription =
276 [&]( const TOOL_ACTION& aAction )
277 {
278 wxString menuItemLabel = aAction.GetMenuLabel();
279 wxMenuBar* menuBar = m_frame->GetMenuBar();
280
281 for( size_t ii = 0; ii < menuBar->GetMenuCount(); ++ii )
282 {
283 for( wxMenuItem* menuItem : menuBar->GetMenu( ii )->GetMenuItems() )
284 {
285 if( menuItem->GetItemLabelText() == menuItemLabel )
286 {
287 wxString menuTitleLabel = menuBar->GetMenuLabelText( ii );
288
289 menuTitleLabel.Replace( wxS( "&" ), wxS( "&&" ) );
290 menuItemLabel.Replace( wxS( "&" ), wxS( "&&" ) );
291
292 return wxString::Format( _( "Run %s > %s" ),
293 menuTitleLabel,
294 menuItemLabel );
295 }
296 }
297 }
298
299 return wxString::Format( _( "Run %s" ), aAction.GetFriendlyName() );
300 };
301
302 if( aDRCItem->GetErrorCode() == DRCE_CLEARANCE
303 || aDRCItem->GetErrorCode() == DRCE_EDGE_CLEARANCE
304 || aDRCItem->GetErrorCode() == DRCE_HOLE_CLEARANCE
305 || aDRCItem->GetErrorCode() == DRCE_DRILLED_HOLES_TOO_CLOSE
306 || aDRCItem->GetErrorCode() == DRCE_STARVED_THERMAL )
307 {
308 return menuDescription( PCB_ACTIONS::inspectClearance );
309 }
310 else if( aDRCItem->GetErrorCode() == DRCE_TEXT_HEIGHT
311 || aDRCItem->GetErrorCode() == DRCE_TEXT_THICKNESS
312 || aDRCItem->GetErrorCode() == DRCE_DIFF_PAIR_UNCOUPLED_LENGTH_TOO_LONG
313 || aDRCItem->GetErrorCode() == DRCE_TRACK_WIDTH
314 || aDRCItem->GetErrorCode() == DRCE_TRACK_ANGLE
315 || aDRCItem->GetErrorCode() == DRCE_TRACK_SEGMENT_LENGTH
316 || aDRCItem->GetErrorCode() == DRCE_VIA_DIAMETER
317 || aDRCItem->GetErrorCode() == DRCE_ANNULAR_WIDTH
318 || aDRCItem->GetErrorCode() == DRCE_DRILL_OUT_OF_RANGE
319 || aDRCItem->GetErrorCode() == DRCE_MICROVIA_DRILL_OUT_OF_RANGE
320 || aDRCItem->GetErrorCode() == DRCE_CONNECTION_WIDTH
321 || aDRCItem->GetErrorCode() == DRCE_ASSERTION_FAILURE )
322 {
323 return menuDescription( PCB_ACTIONS::inspectConstraints );
324 }
325 else if( aDRCItem->GetErrorCode() == DRCE_LIB_FOOTPRINT_MISMATCH )
326 {
327 return menuDescription( PCB_ACTIONS::diffFootprint );
328 }
329 else if( aDRCItem->GetErrorCode() == DRCE_DANGLING_TRACK
330 || aDRCItem->GetErrorCode() == DRCE_DANGLING_VIA )
331 {
332 return menuDescription( PCB_ACTIONS::cleanupTracksAndVias );
333 }
334
335 return wxEmptyString;
336}
337
338
339void BOARD_INSPECTION_TOOL::InspectDRCError( const std::shared_ptr<RC_ITEM>& aDRCItem )
340{
341 wxCHECK( m_frame, /* void */ );
342
343 BOARD_ITEM* a = m_frame->GetBoard()->ResolveItem( aDRCItem->GetMainItemID() );
344 BOARD_ITEM* b = m_frame->GetBoard()->ResolveItem( aDRCItem->GetAuxItemID() );
345 BOARD_CONNECTED_ITEM* ac = dynamic_cast<BOARD_CONNECTED_ITEM*>( a );
346 BOARD_CONNECTED_ITEM* bc = dynamic_cast<BOARD_CONNECTED_ITEM*>( b );
348
349 if( aDRCItem->GetErrorCode() == DRCE_LIB_FOOTPRINT_MISMATCH )
350 {
351 if( FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( a ) )
353
354 return;
355 }
356 else if( aDRCItem->GetErrorCode() == DRCE_DANGLING_TRACK
357 || aDRCItem->GetErrorCode() == DRCE_DANGLING_VIA )
358 {
360 return;
361 }
362
364 wxCHECK( dialog, /* void */ );
365
366 dialog->DeleteAllPages();
367
368 bool compileError = false;
369 bool courtyardError = false;
370 std::unique_ptr<DRC_ENGINE> drcEngine = makeDRCEngine( &compileError, &courtyardError );
371
372 WX_HTML_REPORT_BOX* r = nullptr;
373 DRC_CONSTRAINT constraint;
374 int clearance = 0;
375 wxString clearanceStr;
376
377 switch( aDRCItem->GetErrorCode() )
378 {
380 {
381 for( KIID id : aDRCItem->GetIDs() )
382 {
383 bc = dynamic_cast<BOARD_CONNECTED_ITEM*>( m_frame->GetBoard()->ResolveItem( id, true ) );
384
385 if( ac && bc && ac->GetNetCode() != bc->GetNetCode() )
386 break;
387 }
388
389 r = dialog->AddHTMLPage( _( "Uncoupled Length" ) );
390 reportHeader( _( "Diff pair uncoupled length resolution for:" ), ac, bc, r );
391
392 if( compileError )
394
395 constraint = drcEngine->EvalRules( MAX_UNCOUPLED_CONSTRAINT, a, b, layer, r );
396
397 r->Report( "" );
398 r->Report( wxString::Format( _( "Resolved max uncoupled length: %s." ),
399 reportMax( m_frame, constraint ) ) );
400 break;
401 }
402
403 case DRCE_TEXT_HEIGHT:
404 r = dialog->AddHTMLPage( _( "Text Height" ) );
405 reportHeader( _( "Text height resolution for:" ), a, r );
406
407 if( compileError )
409
410 constraint = drcEngine->EvalRules( TEXT_HEIGHT_CONSTRAINT, a, b, layer, r );
411
412 r->Report( "" );
413 r->Report( wxString::Format( _( "Resolved height constraints: min %s; max %s." ),
414 reportMin( m_frame, constraint ),
415 reportMax( m_frame, constraint ) ) );
416 break;
417
419 r = dialog->AddHTMLPage( _( "Text Thickness" ) );
420 reportHeader( _( "Text thickness resolution for:" ), a, r );
421
422 if( compileError )
424
425 constraint = drcEngine->EvalRules( TEXT_THICKNESS_CONSTRAINT, a, b, layer, r );
426
427 r->Report( "" );
428 r->Report( wxString::Format( _( "Resolved thickness constraints: min %s; max %s." ),
429 reportMin( m_frame, constraint ),
430 reportMax( m_frame, constraint ) ) );
431 break;
432
433 case DRCE_TRACK_WIDTH:
434 r = dialog->AddHTMLPage( _( "Track Width" ) );
435 reportHeader( _( "Track width resolution for:" ), a, r );
436
437 if( compileError )
439
440 constraint = drcEngine->EvalRules( TRACK_WIDTH_CONSTRAINT, a, b, layer, r );
441
442 r->Report( "" );
443 r->Report( wxString::Format( _( "Resolved width constraints: min %s; max %s." ),
444 reportMin( m_frame, constraint ),
445 reportMax( m_frame, constraint ) ) );
446 break;
447
448 case DRCE_TRACK_ANGLE:
449 r = dialog->AddHTMLPage( _( "Track Angle" ) );
450 reportHeader( _( "Track Angle resolution for:" ), a, r );
451
452 if( compileError )
454
455 constraint = drcEngine->EvalRules( TRACK_ANGLE_CONSTRAINT, a, b, layer, r );
456
457 r->Report( "" );
458 r->Report( wxString::Format( _( "Resolved angle constraints: min %s; max %s." ),
459 reportMin( m_frame, constraint ),
460 reportMax( m_frame, constraint ) ) );
461 break;
462
464 r = dialog->AddHTMLPage( _( "Track Segment Length" ) );
465 reportHeader( _( "Track segment length resolution for:" ), a, r );
466
467 if( compileError )
469
470 constraint = drcEngine->EvalRules( TRACK_SEGMENT_LENGTH_CONSTRAINT, a, b, layer, r );
471
472 r->Report( "" );
473 r->Report( wxString::Format( _( "Resolved segment length constraints: min %s; max %s." ),
474 reportMin( m_frame, constraint ),
475 reportMax( m_frame, constraint ) ) );
476 break;
477
479 r = dialog->AddHTMLPage( _( "Connection Width" ) );
480 reportHeader( _( "Connection width resolution for:" ), a, b, r );
481
482 if( compileError )
484
485 constraint = drcEngine->EvalRules( CONNECTION_WIDTH_CONSTRAINT, a, b, layer, r );
486
487 r->Report( "" );
488 r->Report( wxString::Format( _( "Resolved min connection width: %s." ),
489 reportMin( m_frame, constraint ) ) );
490 break;
491
493 r = dialog->AddHTMLPage( _( "Via Diameter" ) );
494 reportHeader( _( "Via diameter resolution for:" ), a, r );
495
496 if( compileError )
498
499 constraint = drcEngine->EvalRules( VIA_DIAMETER_CONSTRAINT, a, b, layer, r );
500
501 r->Report( "" );
502 r->Report( wxString::Format( _( "Resolved diameter constraints: min %s; max %s." ),
503 reportMin( m_frame, constraint ),
504 reportMax( m_frame, constraint ) ) );
505 break;
506
508 r = dialog->AddHTMLPage( _( "Via Annulus" ) );
509 reportHeader( _( "Via annular width resolution for:" ), a, r );
510
511 if( compileError )
513
514 constraint = drcEngine->EvalRules( ANNULAR_WIDTH_CONSTRAINT, a, b, layer, r );
515
516 r->Report( "" );
517 r->Report( wxString::Format( _( "Resolved annular width constraints: min %s; max %s." ),
518 reportMin( m_frame, constraint ),
519 reportMax( m_frame, constraint ) ) );
520 break;
521
524 r = dialog->AddHTMLPage( _( "Hole Size" ) );
525 reportHeader( _( "Hole size resolution for:" ), a, r );
526
527 if( compileError )
529
530 constraint = drcEngine->EvalRules( HOLE_SIZE_CONSTRAINT, a, b, layer, r );
531
532 r->Report( "" );
533 r->Report( wxString::Format( _( "Resolved hole size constraints: min %s; max %s." ),
534 reportMin( m_frame, constraint ),
535 reportMax( m_frame, constraint ) ) );
536 break;
537
539 r = dialog->AddHTMLPage( _( "Hole Clearance" ) );
540 reportHeader( _( "Hole clearance resolution for:" ), a, b, r );
541
542 if( compileError )
544
545 if( ac && bc && ac->GetNetCode() == bc->GetNetCode() )
546 {
547 r->Report( "" );
548 r->Report( _( "Items belong to the same net. Clearance is 0." ) );
549 }
550 else
551 {
552 constraint = drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, a, b, layer, r );
553 clearance = constraint.m_Value.Min();
554 clearanceStr = m_frame->StringFromValue( clearance, true );
555
556 r->Report( "" );
557 r->Report( wxString::Format( _( "Resolved min clearance: %s." ), clearanceStr ) );
558 }
559
560 r->Report( "" );
561 r->Report( "" );
562 r->Report( "" );
563 reportHeader( _( "Physical hole clearance resolution for:" ), a, b, layer, r );
564
565 constraint = drcEngine->EvalRules( PHYSICAL_HOLE_CLEARANCE_CONSTRAINT, a, b, layer, r );
566 clearance = constraint.m_Value.Min();
567 clearanceStr = m_frame->StringFromValue( clearance, true );
568
569 if( !drcEngine->HasRulesForConstraintType( PHYSICAL_HOLE_CLEARANCE_CONSTRAINT ) )
570 {
571 r->Report( "" );
572 r->Report( _( "No 'physical_hole_clearance' constraints defined." ) );
573 }
574 else
575 {
576 r->Report( "" );
577 r->Report( wxString::Format( _( "Resolved min clearance: %s." ), clearanceStr ) );
578 }
579
580 break;
581
583 r = dialog->AddHTMLPage( _( "Hole to Hole" ) );
584 reportHeader( _( "Hole-to-hole clearance resolution for:" ), a, b, r );
585
586 if( compileError )
588
589 constraint = drcEngine->EvalRules( HOLE_TO_HOLE_CONSTRAINT, a, b, UNDEFINED_LAYER, r );
590 clearance = constraint.m_Value.Min();
591 clearanceStr = m_frame->StringFromValue( clearance, true );
592
593 r->Report( "" );
594 r->Report( wxString::Format( _( "Resolved min clearance: %s." ), clearanceStr ) );
595 break;
596
598 r = dialog->AddHTMLPage( _( "Edge Clearance" ) );
599 reportHeader( _( "Edge clearance resolution for:" ), a, b, r );
600
601 if( compileError )
603
604 constraint = drcEngine->EvalRules( EDGE_CLEARANCE_CONSTRAINT, a, b, layer, r );
605 clearance = constraint.m_Value.Min();
606 clearanceStr = m_frame->StringFromValue( clearance, true );
607
608 r->Report( "" );
609 r->Report( wxString::Format( _( "Resolved min clearance: %s." ), clearanceStr ) );
610 break;
611
612 case DRCE_CLEARANCE:
613 if( a->Type() == PCB_TRACE_T || a->Type() == PCB_ARC_T )
614 {
615 layer = a->GetLayer();
616 }
617 else if( b->Type() == PCB_TRACE_T || b->Type() == PCB_ARC_T )
618 {
619 layer = b->GetLayer();
620 }
621 else if( a->Type() == PCB_PAD_T
622 && static_cast<PAD*>( a )->GetAttribute() == PAD_ATTRIB::SMD )
623 {
624 PAD* pad = static_cast<PAD*>( a );
625
626 if( pad->IsOnLayer( F_Cu ) )
627 layer = F_Cu;
628 else
629 layer = B_Cu;
630 }
631 else if( b->Type() == PCB_PAD_T
632 && static_cast<PAD*>( a )->GetAttribute() == PAD_ATTRIB::SMD )
633 {
634 PAD* pad = static_cast<PAD*>( b );
635
636 if( pad->IsOnLayer( F_Cu ) )
637 layer = F_Cu;
638 else
639 layer = B_Cu;
640 }
641
642 r = dialog->AddHTMLPage( _( "Clearance" ) );
643 reportHeader( _( "Clearance resolution for:" ), a, b, layer, r );
644
645 if( compileError )
647
648 if( ac && bc && ac->GetNetCode() == bc->GetNetCode() )
649 {
650 r->Report( "" );
651 r->Report( _( "Items belong to the same net. Clearance is 0." ) );
652 }
653 else
654 {
655 constraint = drcEngine->EvalRules( CLEARANCE_CONSTRAINT, a, b, layer, r );
656 clearance = constraint.m_Value.Min();
657 clearanceStr = m_frame->StringFromValue( clearance, true );
658
659 r->Report( "" );
660 r->Report( wxString::Format( _( "Resolved min clearance: %s." ), clearanceStr ) );
661 }
662
663 r->Report( "" );
664 r->Report( "" );
665 r->Report( "" );
666 reportHeader( _( "Physical clearance resolution for:" ), a, b, layer, r );
667
668 constraint = drcEngine->EvalRules( PHYSICAL_CLEARANCE_CONSTRAINT, a, b, layer, r );
669 clearance = constraint.m_Value.Min();
670 clearanceStr = m_frame->StringFromValue( clearance, true );
671
672 if( !drcEngine->HasRulesForConstraintType( PHYSICAL_CLEARANCE_CONSTRAINT ) )
673 {
674 r->Report( "" );
675 r->Report( _( "No 'physical_clearance' constraints defined." ) );
676 }
677 else
678 {
679 r->Report( "" );
680 r->Report( wxString::Format( _( "Resolved min clearance: %s." ), clearanceStr ) );
681 }
682
683 break;
684
686 r = dialog->AddHTMLPage( _( "Assertions" ) );
687 reportHeader( _( "Assertions for:" ), a, r );
688
689 if( compileError )
691
692 drcEngine->ProcessAssertions( a, []( const DRC_CONSTRAINT* c ){}, r );
693 break;
694
695 default:
696 return;
697 }
698
699 r->Flush();
700
701 dialog->Raise();
702 dialog->Show( true );
703}
704
705
707{
708 wxCHECK( m_frame, 0 );
709
711
712 wxCHECK( selTool, 0 );
713
714 const PCB_SELECTION& selection = selTool->GetSelection();
715
716 if( selection.Size() != 2 )
717 {
718 m_frame->ShowInfoBarError( _( "Select two items for a clearance resolution report." ) );
719 return 0;
720 }
721
723 return 0;
724
725 BOARD_ITEM* a = static_cast<BOARD_ITEM*>( selection.GetItem( 0 ) );
726 BOARD_ITEM* b = static_cast<BOARD_ITEM*>( selection.GetItem( 1 ) );
727
728 if( a->Type() == PCB_GROUP_T )
729 {
730 PCB_GROUP* ag = static_cast<PCB_GROUP*>( a );
731
732 if( ag->GetItems().empty() )
733 {
734 m_frame->ShowInfoBarError( _( "Cannot generate clearance report on empty group." ) );
735 return 0;
736 }
737
738 a = static_cast<BOARD_ITEM*>( *ag->GetItems().begin() );
739 }
740
741 if( b->Type() == PCB_GROUP_T )
742 {
743 PCB_GROUP* bg = static_cast<PCB_GROUP*>( b );
744
745 if( bg->GetItems().empty() )
746 {
747 m_frame->ShowInfoBarError( _( "Cannot generate clearance report on empty group." ) );
748 return 0;
749 }
750
751 b = static_cast<BOARD_ITEM*>( *bg->GetItems().begin() );
752 }
753
754 // a or b could be null after group tests above.
755 if( !a || !b )
756 return 0;
757
758 auto checkFootprint =
759 [&]( FOOTPRINT* footprint ) -> BOARD_ITEM*
760 {
761 PAD* foundPad = nullptr;
762
763 for( PAD* pad : footprint->Pads() )
764 {
765 if( !foundPad || pad->SameLogicalPadAs( foundPad ) )
766 foundPad = pad;
767 else
768 return footprint;
769 }
770
771 if( !foundPad )
772 return footprint;
773
774 return foundPad;
775 };
776
777 if( a->Type() == PCB_FOOTPRINT_T )
778 a = checkFootprint( static_cast<FOOTPRINT*>( a ) );
779
780 if( b->Type() == PCB_FOOTPRINT_T )
781 b = checkFootprint( static_cast<FOOTPRINT*>( b ) );
782
783 // a or b could be null after footprint tests above.
784 if( !a || !b )
785 return 0;
786
788
789 wxCHECK( dialog, 0 );
790
791 dialog->DeleteAllPages();
792
793 if( a->Type() != PCB_ZONE_T && b->Type() == PCB_ZONE_T )
794 std::swap( a, b );
795 else if( !a->IsConnected() && b->IsConnected() )
796 std::swap( a, b );
797
798 WX_HTML_REPORT_BOX* r = nullptr;
800 LSET layerIntersection = a->GetLayerSet() & b->GetLayerSet();
801 LSET copperIntersection = layerIntersection & LSET::AllCuMask();
802 BOARD_CONNECTED_ITEM* ac = dynamic_cast<BOARD_CONNECTED_ITEM*>( a );
803 BOARD_CONNECTED_ITEM* bc = dynamic_cast<BOARD_CONNECTED_ITEM*>( b );
804 ZONE* zone = dynamic_cast<ZONE*>( a );
805 PAD* pad = dynamic_cast<PAD*>( b );
806 FOOTPRINT* aFP = dynamic_cast<FOOTPRINT*>( a );
807 FOOTPRINT* bFP = dynamic_cast<FOOTPRINT*>( b );
808 DRC_CONSTRAINT constraint;
809 int clearance = 0;
810
811 bool compileError = false;
812 bool courtyardError = false;
813 std::unique_ptr<DRC_ENGINE> drcEngine = makeDRCEngine( &compileError, &courtyardError );
814
815 if( copperIntersection.any() && zone && pad && zone->GetNetCode() == pad->GetNetCode() )
816 {
818
819 if( zone->IsOnLayer( active ) )
820 layer = active;
821 else if( zone->GetLayerSet().count() > 0 )
822 layer = zone->GetLayerSet().Seq().front();
823
824 r = dialog->AddHTMLPage( _( "Zone" ) );
825 reportHeader( _( "Zone connection resolution for:" ), a, b, layer, r );
826
827 constraint = drcEngine->EvalZoneConnection( pad, zone, layer, r );
828
829 if( constraint.m_ZoneConnection == ZONE_CONNECTION::THERMAL )
830 {
831 r->Report( "" );
832 r->Report( "" );
833 reportHeader( _( "Thermal-relief gap resolution for:" ), a, b, layer, r );
834
835 constraint = drcEngine->EvalRules( THERMAL_RELIEF_GAP_CONSTRAINT, pad, zone, layer, r );
836 int gap = constraint.m_Value.Min();
837
838 if( compileError )
840
841 r->Report( "" );
842 r->Report( wxString::Format( _( "Resolved thermal relief gap: %s." ),
843 m_frame->StringFromValue( gap, true ) ) );
844
845 r->Report( "" );
846 r->Report( "" );
847 reportHeader( _( "Thermal-relief spoke width resolution for:" ), a, b, layer, r );
848
849 constraint = drcEngine->EvalRules( THERMAL_SPOKE_WIDTH_CONSTRAINT, pad, zone, layer, r );
850 int width = constraint.m_Value.Opt();
851
852 if( compileError )
854
855 r->Report( "" );
856 r->Report( wxString::Format( _( "Resolved spoke width: %s." ),
857 m_frame->StringFromValue( width, true ) ) );
858
859 r->Report( "" );
860 r->Report( "" );
861 reportHeader( _( "Thermal-relief min spoke count resolution for:" ), a, b, layer, r );
862
863 constraint = drcEngine->EvalRules( MIN_RESOLVED_SPOKES_CONSTRAINT, pad, zone, layer, r );
864 int minSpokes = constraint.m_Value.Min();
865
866 if( compileError )
868
869 r->Report( "" );
870 r->Report( wxString::Format( _( "Resolved min spoke count: %d." ),
871 minSpokes ) );
872
873 std::shared_ptr<CONNECTIVITY_DATA> connectivity = pad->GetBoard()->GetConnectivity();
874 }
875 else if( constraint.m_ZoneConnection == ZONE_CONNECTION::NONE )
876 {
877 r->Report( "" );
878 r->Report( "" );
879 reportHeader( _( "Zone clearance resolution for:" ), a, b, layer, r );
880
881 clearance = zone->GetLocalClearance().value();
882 r->Report( "" );
883 r->Report( wxString::Format( _( "Zone clearance: %s." ),
884 m_frame->StringFromValue( clearance, true ) ) );
885
886 constraint = drcEngine->EvalRules( PHYSICAL_CLEARANCE_CONSTRAINT, pad, zone, layer, r );
887
888 if( constraint.m_Value.Min() > clearance )
889 {
890 clearance = constraint.m_Value.Min();
891
892 r->Report( "" );
893 r->Report( wxString::Format( _( "Overridden by larger physical clearance from %s;"
894 "clearance: %s." ),
895 EscapeHTML( constraint.GetName() ),
896 m_frame->StringFromValue( clearance, true ) ) );
897 }
898
899 if( !pad->FlashLayer( layer ) )
900 {
901 constraint = drcEngine->EvalRules( PHYSICAL_HOLE_CLEARANCE_CONSTRAINT, pad, zone,
902 layer, r );
903
904 if( constraint.m_Value.Min() > clearance )
905 {
906 clearance = constraint.m_Value.Min();
907
908 r->Report( "" );
909 r->Report( wxString::Format( _( "Overridden by larger physical hole clearance "
910 "from %s; clearance: %s." ),
911 EscapeHTML( constraint.GetName() ),
912 m_frame->StringFromValue( clearance, true ) ) );
913 }
914 }
915
916 if( compileError )
918
919 r->Report( "" );
920 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
921 m_frame->StringFromValue( clearance, true ) ) );
922 }
923 else
924 {
925 r->Report( "" );
926 r->Report( "" );
927 reportHeader( _( "Zone clearance resolution for:" ), a, b, layer, r );
928
929 if( compileError )
931
932 // Report a 0 clearance for solid connections
933 r->Report( "" );
934 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
935 m_frame->StringFromValue( 0, true ) ) );
936 }
937
938 r->Flush();
939 }
940 else if( copperIntersection.any() && !aFP && !bFP )
941 {
942 PCB_LAYER_ID layer = active;
943
944 if( !copperIntersection.test( layer ) )
945 layer = copperIntersection.Seq().front();
946
947 r = dialog->AddHTMLPage( m_frame->GetBoard()->GetLayerName( layer ) );
948 reportHeader( _( "Clearance resolution for:" ), a, b, layer, r );
949
950 if( ac && bc && ac->GetNetCode() > 0 && ac->GetNetCode() == bc->GetNetCode() )
951 {
952 // Same nets....
953 r->Report( _( "Items belong to the same net. Min clearance is 0." ) );
954 }
955 else
956 {
957 // Different nets (or one or both unconnected)....
958 constraint = drcEngine->EvalRules( CLEARANCE_CONSTRAINT, a, b, layer, r );
959 clearance = constraint.m_Value.Min();
960
961 if( compileError )
963
964 r->Report( "" );
965
966 if( constraint.IsNull() )
967 {
968 r->Report( _( "Min clearance is 0." ) );
969 }
970 else if( clearance < 0 )
971 {
972 r->Report( wxString::Format( _( "Resolved clearance: %s; clearance will not be "
973 "tested." ),
974 m_frame->StringFromValue( clearance, true ) ) );
975 }
976 else
977 {
978 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
979 m_frame->StringFromValue( clearance, true ) ) );
980 }
981 }
982
983 r->Flush();
984 }
985
986 if( ac && bc )
987 {
988 NETINFO_ITEM* refNet = ac->GetNet();
989 wxString coupledNet;
990 wxString dummy;
991
992 if( DRC_ENGINE::MatchDpSuffix( refNet->GetNetname(), coupledNet, dummy )
993 && bc->GetNetname() == coupledNet )
994 {
995 r = dialog->AddHTMLPage( _( "Diff Pair" ) );
996 reportHeader( _( "Diff-pair gap resolution for:" ), ac, bc, active, r );
997
998 constraint = drcEngine->EvalRules( DIFF_PAIR_GAP_CONSTRAINT, ac, bc, active, r );
999
1000 r->Report( "" );
1001 r->Report( wxString::Format( _( "Resolved gap constraints: min %s; opt %s; max %s." ),
1002 reportMin( m_frame, constraint ),
1003 reportOpt( m_frame, constraint ),
1004 reportMax( m_frame, constraint ) ) );
1005
1006 r->Report( "" );
1007 r->Report( "" );
1008 r->Report( "" );
1009 reportHeader( _( "Diff-pair max uncoupled length resolution for:" ), ac, bc,
1010 active, r );
1011
1012 if( !drcEngine->HasRulesForConstraintType( MAX_UNCOUPLED_CONSTRAINT ) )
1013 {
1014 r->Report( "" );
1015 r->Report( _( "No 'diff_pair_uncoupled' constraints defined." ) );
1016 }
1017 else
1018 {
1019 constraint = drcEngine->EvalRules( MAX_UNCOUPLED_CONSTRAINT, ac, bc, active, r );
1020
1021 r->Report( "" );
1022 r->Report( wxString::Format( _( "Resolved max uncoupled length: %s." ),
1023 reportMax( m_frame, constraint ) ) );
1024 }
1025 r->Flush();
1026 }
1027 }
1028
1029 auto isOnCorrespondingLayer=
1030 [&]( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer, wxString* aWarning )
1031 {
1032 if( aItem->IsOnLayer( aLayer ) )
1033 return true;
1034
1035 PCB_LAYER_ID correspondingMask = IsFrontLayer( aLayer ) ? F_Mask : B_Mask;
1036 PCB_LAYER_ID correspondingCopper = IsFrontLayer( aLayer ) ? F_Cu : B_Cu;
1037
1038 if( aItem->IsOnLayer( aLayer ) )
1039 return true;
1040
1041 if( aItem->IsOnLayer( correspondingMask ) )
1042 return true;
1043
1044 if( aItem->IsTented( correspondingMask ) && aItem->IsOnLayer( correspondingCopper ) )
1045 {
1046 *aWarning = wxString::Format( _( "Note: %s is tented; clearance will only be "
1047 "applied to holes." ),
1048 getItemDescription( aItem ) );
1049 return true;
1050 }
1051
1052 return false;
1053 };
1054
1055 for( PCB_LAYER_ID layer : { F_SilkS, B_SilkS } )
1056 {
1057 wxString warning;
1058
1059 if( ( a->IsOnLayer( layer ) && isOnCorrespondingLayer( b, layer, &warning ) )
1060 || ( b->IsOnLayer( layer ) && isOnCorrespondingLayer( a, layer, &warning ) ) )
1061 {
1062 r = dialog->AddHTMLPage( m_frame->GetBoard()->GetLayerName( layer ) );
1063 reportHeader( _( "Silkscreen clearance resolution for:" ), a, b, layer, r );
1064
1065 constraint = drcEngine->EvalRules( SILK_CLEARANCE_CONSTRAINT, a, b, layer, r );
1066 clearance = constraint.m_Value.Min();
1067
1068 if( compileError )
1069 reportCompileError( r );
1070
1071 r->Report( "" );
1072
1073 if( !warning.IsEmpty() )
1074 r->Report( warning );
1075
1076 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1077 m_frame->StringFromValue( clearance, true ) ) );
1078
1079 r->Flush();
1080 }
1081 }
1082
1083 for( PCB_LAYER_ID layer : { F_CrtYd, B_CrtYd } )
1084 {
1085 bool aCourtyard = aFP && !aFP->GetCourtyard( layer ).IsEmpty();
1086 bool bCourtyard = bFP && !bFP->GetCourtyard( layer ).IsEmpty();
1087
1088 if( aCourtyard && bCourtyard )
1089 {
1090 r = dialog->AddHTMLPage( m_frame->GetBoard()->GetLayerName( layer ) );
1091 reportHeader( _( "Courtyard clearance resolution for:" ), a, b, layer, r );
1092
1093 constraint = drcEngine->EvalRules( COURTYARD_CLEARANCE_CONSTRAINT, a, b, layer, r );
1094 clearance = constraint.m_Value.Min();
1095
1096 if( compileError )
1097 reportCompileError( r );
1098
1099 r->Report( "" );
1100 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1101 m_frame->StringFromValue( clearance, true ) ) );
1102
1103 r->Flush();
1104 }
1105 }
1106
1107 if( a->HasHole() || b->HasHole() )
1108 {
1110 bool pageAdded = false;
1111
1112 if( a->HasHole() && b->IsOnLayer( active ) && IsCopperLayer( active ) )
1113 layer = active;
1114 else if( b->HasHole() && a->IsOnLayer( active ) && IsCopperLayer( active ) )
1115 layer = active;
1116 else if( a->HasHole() && b->IsOnCopperLayer() )
1117 layer = b->GetLayer();
1118 else if( b->HasHole() && b->IsOnCopperLayer() )
1119 layer = a->GetLayer();
1120
1121 if( layer >= 0 )
1122 {
1123 r = dialog->AddHTMLPage( _( "Hole" ) );
1124 pageAdded = true;
1125
1126 reportHeader( _( "Hole clearance resolution for:" ), a, b, layer, r );
1127
1128 constraint = drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, a, b, layer, r );
1129 clearance = constraint.m_Value.Min();
1130
1131 if( compileError )
1132 reportCompileError( r );
1133
1134 r->Report( "" );
1135 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1136 m_frame->StringFromValue( clearance, true ) ) );
1137
1138 r->Flush();
1139 }
1140
1141 if( a->HasDrilledHole() || b->HasDrilledHole() )
1142 {
1143 if( !pageAdded )
1144 {
1145 r = dialog->AddHTMLPage( _( "Hole" ) );
1146 pageAdded = true;
1147 }
1148 else
1149 {
1150 r->Report( "" );
1151 r->Report( "" );
1152 r->Report( "" );
1153 }
1154
1155 reportHeader( _( "Hole-to-hole clearance resolution for:" ), a, b, r );
1156
1157 constraint = drcEngine->EvalRules( HOLE_TO_HOLE_CONSTRAINT, a, b, UNDEFINED_LAYER, r );
1158 clearance = constraint.m_Value.Min();
1159
1160 if( compileError )
1161 reportCompileError( r );
1162
1163 r->Report( "" );
1164 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1165 m_frame->StringFromValue( clearance, true ) ) );
1166
1167 r->Flush();
1168 }
1169 }
1170
1171 for( PCB_LAYER_ID edgeLayer : { Edge_Cuts, Margin } )
1172 {
1174
1175 if( a->IsOnLayer( edgeLayer ) && b->Type() != PCB_FOOTPRINT_T )
1176 {
1177 if( b->IsOnLayer( active ) && IsCopperLayer( active ) )
1178 layer = active;
1179 else if( IsCopperLayer( b->GetLayer() ) )
1180 layer = b->GetLayer();
1181 }
1182 else if( b->IsOnLayer( edgeLayer ) && a->Type() != PCB_FOOTPRINT_T )
1183 {
1184 if( a->IsOnLayer( active ) && IsCopperLayer( active ) )
1185 layer = active;
1186 else if( IsCopperLayer( a->GetLayer() ) )
1187 layer = a->GetLayer();
1188 }
1189
1190 if( layer >= 0 )
1191 {
1192 wxString layerName = m_frame->GetBoard()->GetLayerName( edgeLayer );
1193 r = dialog->AddHTMLPage( layerName + wxS( " " ) + _( "Clearance" ) );
1194 reportHeader( _( "Edge clearance resolution for:" ), a, b, layer, r );
1195
1196 constraint = drcEngine->EvalRules( EDGE_CLEARANCE_CONSTRAINT, a, b, layer, r );
1197 clearance = constraint.m_Value.Min();
1198
1199 if( compileError )
1200 reportCompileError( r );
1201
1202 r->Report( "" );
1203 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1204 m_frame->StringFromValue( clearance, true ) ) );
1205
1206 r->Flush();
1207 }
1208 }
1209
1210 r = dialog->AddHTMLPage( _( "Physical Clearances" ) );
1211
1212 if( compileError )
1213 {
1214 reportCompileError( r );
1215 }
1216 else if( !drcEngine->HasRulesForConstraintType( PHYSICAL_CLEARANCE_CONSTRAINT ) )
1217 {
1218 r->Report( "" );
1219 r->Report( _( "No 'physical_clearance' constraints defined." ) );
1220 }
1221 else
1222 {
1223 LSET reportLayers = layerIntersection;
1224 bool reported = false;
1225
1226 if( a->IsOnLayer( Edge_Cuts ) )
1227 {
1228 LSET edgeInteractingLayers = bFP ? LSET( { F_CrtYd, B_CrtYd } )
1230 reportLayers |= edgeInteractingLayers;
1231 }
1232
1233 if( b->IsOnLayer( Edge_Cuts ) )
1234 {
1235 LSET edgeInteractingLayers = aFP ? LSET( { F_CrtYd, B_CrtYd } )
1237 reportLayers |= edgeInteractingLayers;
1238 }
1239
1240 for( PCB_LAYER_ID layer : reportLayers )
1241 {
1242 reported = true;
1243 reportHeader( _( "Physical clearance resolution for:" ), a, b, layer, r );
1244
1245 constraint = drcEngine->EvalRules( PHYSICAL_CLEARANCE_CONSTRAINT, a, b, layer, r );
1246 clearance = constraint.m_Value.Min();
1247
1248 if( constraint.IsNull() )
1249 {
1250 r->Report( "" );
1251 r->Report( wxString::Format( _( "No 'physical_clearance' constraints in effect on %s." ),
1252 m_frame->GetBoard()->GetLayerName( layer ) ) );
1253 }
1254 else
1255 {
1256 r->Report( "" );
1257 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1258 m_frame->StringFromValue( clearance, true ) ) );
1259 }
1260
1261 r->Report( "" );
1262 r->Report( "" );
1263 r->Report( "" );
1264 }
1265
1266 if( !reported )
1267 {
1268 reportHeader( _( "Physical clearance resolution for:" ), a, b, r );
1269 r->Report( "" );
1270 r->Report( _( "Items share no relevant layers. No 'physical_clearance' constraints will "
1271 "be applied." ) );
1272 }
1273 }
1274
1275 if( a->HasHole() || b->HasHole() )
1276 {
1277 PCB_LAYER_ID layer;
1278
1279 if( a->HasHole() && b->IsOnLayer( active ) )
1280 layer = active;
1281 else if( b->HasHole() && a->IsOnLayer( active ) )
1282 layer = active;
1283 else if( a->HasHole() )
1284 layer = b->GetLayer();
1285 else
1286 layer = a->GetLayer();
1287
1288 reportHeader( _( "Physical hole clearance resolution for:" ), a, b, layer, r );
1289
1290 constraint = drcEngine->EvalRules( PHYSICAL_HOLE_CLEARANCE_CONSTRAINT, a, b, layer, r );
1291 clearance = constraint.m_Value.Min();
1292
1293 if( compileError )
1294 {
1295 reportCompileError( r );
1296 }
1297 else if( !drcEngine->HasRulesForConstraintType( PHYSICAL_HOLE_CLEARANCE_CONSTRAINT ) )
1298 {
1299 r->Report( "" );
1300 r->Report( _( "No 'physical_hole_clearance' constraints defined." ) );
1301 }
1302 else
1303 {
1304 r->Report( "" );
1305 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1306 m_frame->StringFromValue( clearance, true ) ) );
1307 }
1308 }
1309
1310 r->Flush();
1311
1312 dialog->Raise();
1313 dialog->Show( true );
1314 return 0;
1315}
1316
1317
1319{
1320#define EVAL_RULES( constraint, a, b, layer, r ) drcEngine->EvalRules( constraint, a, b, layer, r )
1321
1322 wxCHECK( m_frame, 0 );
1323
1325
1326 wxCHECK( selTool, 0 );
1327
1328 const PCB_SELECTION& selection = selTool->GetSelection();
1329
1330 if( selection.Size() != 1 )
1331 {
1332 m_frame->ShowInfoBarError( _( "Select an item for a constraints resolution report." ) );
1333 return 0;
1334 }
1335
1337
1338 wxCHECK( dialog, 0 );
1339
1340 dialog->DeleteAllPages();
1341
1342 if( !selection.GetItem( 0 )->IsBOARD_ITEM() )
1343 return 0;
1344
1345 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( selection.GetItem( 0 ) );
1346 DRC_CONSTRAINT constraint;
1347
1348 bool compileError = false;
1349 bool courtyardError = false;
1350 std::unique_ptr<DRC_ENGINE> drcEngine = makeDRCEngine( &compileError, &courtyardError );
1351
1352 WX_HTML_REPORT_BOX* r = nullptr;
1353
1354 if( item->Type() == PCB_TRACE_T )
1355 {
1356 r = dialog->AddHTMLPage( _( "Track Width" ) );
1357 reportHeader( _( "Track width resolution for:" ), item, r );
1358
1359 constraint = EVAL_RULES( TRACK_WIDTH_CONSTRAINT, item, nullptr, item->GetLayer(), r );
1360
1361 if( compileError )
1362 reportCompileError( r );
1363
1364 r->Report( "" );
1365 r->Report( wxString::Format( _( "Resolved width constraints: min %s; opt %s; max %s." ),
1366 reportMin( m_frame, constraint ),
1367 reportOpt( m_frame, constraint ),
1368 reportMax( m_frame, constraint ) ) );
1369
1370 r->Flush();
1371 }
1372
1373 if( item->Type() == PCB_VIA_T )
1374 {
1375 r = dialog->AddHTMLPage( _( "Via Diameter" ) );
1376 reportHeader( _( "Via diameter resolution for:" ), item, r );
1377
1378 // PADSTACKS TODO: once we have padstacks we'll need to run this per-layer....
1379 constraint = EVAL_RULES( VIA_DIAMETER_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
1380
1381 if( compileError )
1382 reportCompileError( r );
1383
1384 r->Report( "" );
1385 r->Report( wxString::Format( _( "Resolved diameter constraints: min %s; opt %s; max %s." ),
1386 reportMin( m_frame, constraint ),
1387 reportOpt( m_frame, constraint ),
1388 reportMax( m_frame, constraint ) ) );
1389
1390 r->Flush();
1391
1392 r = dialog->AddHTMLPage( _( "Via Annular Width" ) );
1393 reportHeader( _( "Via annular width resolution for:" ), item, r );
1394
1395 // PADSTACKS TODO: once we have padstacks we'll need to run this per-layer....
1396 constraint = EVAL_RULES( ANNULAR_WIDTH_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
1397
1398 if( compileError )
1399 reportCompileError( r );
1400
1401 r->Report( "" );
1402 r->Report( wxString::Format( _( "Resolved annular width constraints: min %s; opt %s; max %s." ),
1403 reportMin( m_frame, constraint ),
1404 reportOpt( m_frame, constraint ),
1405 reportMax( m_frame, constraint ) ) );
1406
1407 r->Flush();
1408 }
1409
1410 if( ( item->Type() == PCB_PAD_T && static_cast<PAD*>( item )->GetDrillSize().x > 0 )
1411 || item->Type() == PCB_VIA_T )
1412 {
1413 r = dialog->AddHTMLPage( _( "Hole Size" ) );
1414 reportHeader( _( "Hole size resolution for:" ), item, r );
1415
1416 constraint = EVAL_RULES( HOLE_SIZE_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
1417
1418 if( compileError )
1419 reportCompileError( r );
1420
1421 r->Report( "" );
1422 r->Report( wxString::Format( _( "Resolved hole size constraints: min %s; opt %s; max %s." ),
1423 reportMin( m_frame, constraint ),
1424 reportOpt( m_frame, constraint ),
1425 reportMax( m_frame, constraint ) ) );
1426
1427 r->Flush();
1428 }
1429
1430 if( item->Type() == PCB_PAD_T || item->Type() == PCB_SHAPE_T || dynamic_cast<PCB_TRACK*>( item ) )
1431 {
1432 r = dialog->AddHTMLPage( _( "Solder Mask" ) );
1433 reportHeader( _( "Solder mask expansion resolution for:" ), item, r );
1434
1435 constraint = EVAL_RULES( SOLDER_MASK_EXPANSION_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
1436
1437 if( compileError )
1438 reportCompileError( r );
1439
1440 r->Report( "" );
1441 r->Report( wxString::Format( _( "Resolved solder mask expansion: %s." ),
1442 reportOpt( m_frame, constraint ) ) );
1443
1444 r->Flush();
1445 }
1446
1447 if( item->Type() == PCB_PAD_T )
1448 {
1449 r = dialog->AddHTMLPage( _( "Solder Paste" ) );
1450 reportHeader( _( "Solder paste absolute clearance resolution for:" ), item, r );
1451
1452 constraint = EVAL_RULES( SOLDER_PASTE_ABS_MARGIN_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
1453
1454 if( compileError )
1455 reportCompileError( r );
1456
1457 r->Report( "" );
1458 r->Report( wxString::Format( _( "Resolved solder paste absolute clearance: %s." ),
1459 reportOpt( m_frame, constraint ) ) );
1460
1461 reportHeader( _( "Solder paste relative clearance resolution for:" ), item, r );
1462
1463 constraint = EVAL_RULES( SOLDER_PASTE_REL_MARGIN_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
1464
1465 if( compileError )
1466 reportCompileError( r );
1467
1468 r->Report( "" );
1469 r->Report( "" );
1470 r->Report( "" );
1471 r->Report( wxString::Format( _( "Resolved solder paste relative clearance: %s." ),
1472 reportOpt( m_frame, constraint ) ) );
1473
1474 r->Flush();
1475 }
1476
1477 if( item->Type() == PCB_FIELD_T || item->Type() == PCB_TEXT_T || item->Type() == PCB_TEXTBOX_T )
1478 {
1479 r = dialog->AddHTMLPage( _( "Text Size" ) );
1480 reportHeader( _( "Text height resolution for:" ), item, r );
1481
1482 constraint = EVAL_RULES( TEXT_HEIGHT_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
1483
1484 if( compileError )
1485 reportCompileError( r );
1486
1487 r->Report( "" );
1488 r->Report( wxString::Format( _( "Resolved height constraints: min %s; opt %s; max %s." ),
1489 reportMin( m_frame, constraint ),
1490 reportOpt( m_frame, constraint ),
1491 reportMax( m_frame, constraint ) ) );
1492
1493 r->Report( "" );
1494 r->Report( "" );
1495 r->Report( "" );
1496 reportHeader( _( "Text thickness resolution for:" ), item, r );
1497
1498 constraint = EVAL_RULES( TEXT_THICKNESS_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
1499
1500 if( compileError )
1501 reportCompileError( r );
1502
1503 r->Report( "" );
1504 r->Report( wxString::Format( _( "Resolved thickness constraints: min %s; opt %s; max %s." ),
1505 reportMin( m_frame, constraint ),
1506 reportOpt( m_frame, constraint ),
1507 reportMax( m_frame, constraint ) ) );
1508
1509 r->Flush();
1510 }
1511
1512 r = dialog->AddHTMLPage( _( "Keepouts" ) );
1513 reportHeader( _( "Keepout resolution for:" ), item, r );
1514
1515 constraint = EVAL_RULES( DISALLOW_CONSTRAINT, item, nullptr, item->GetLayer(), r );
1516
1517 if( compileError )
1518 reportCompileError( r );
1519
1520 if( courtyardError )
1521 {
1522 r->Report( "" );
1523 r->Report( _( "Report may be incomplete: some footprint courtyards are malformed." )
1524 + wxS( "&nbsp;&nbsp;" )
1525 + wxS( "<a href='$DRC'>" ) + _( "Run DRC for a full analysis." )
1526 + wxS( "</a>" ) );
1527 }
1528
1529 r->Report( "" );
1530
1531 if( constraint.m_DisallowFlags )
1532 r->Report( _( "Item <b>disallowed</b> at current location." ) );
1533 else
1534 r->Report( _( "Item allowed at current location." ) );
1535
1536 r->Flush();
1537
1538 r = dialog->AddHTMLPage( _( "Assertions" ) );
1539 reportHeader( _( "Assertions for:" ), item, r );
1540
1541 if( compileError )
1542 reportCompileError( r );
1543
1544 if( courtyardError )
1545 {
1546 r->Report( "" );
1547 r->Report( _( "Report may be incomplete: some footprint courtyards are malformed." )
1548 + wxS( "&nbsp;&nbsp;" )
1549 + wxS( "<a href='$DRC'>" ) + _( "Run DRC for a full analysis." )
1550 + wxS( "</a>" ) );
1551 }
1552
1553 drcEngine->ProcessAssertions( item, []( const DRC_CONSTRAINT* c ){}, r );
1554 r->Flush();
1555
1556 dialog->Raise();
1557 dialog->Show( true );
1558 return 0;
1559}
1560
1561
1563{
1564 wxCHECK( m_frame, 0 );
1565
1567
1568 wxCHECK( selTool, 0 );
1569
1570 const PCB_SELECTION& selection = selTool->RequestSelection(
1571 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
1572 {
1573 // Iterate from the back so we don't have to worry about removals.
1574 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
1575 {
1576 BOARD_ITEM* item = aCollector[ i ];
1577
1578 if( !dynamic_cast<FOOTPRINT*>( item ) )
1579 aCollector.Remove( item );
1580 }
1581 },
1582 false /* ignore locked flag */ );
1583
1584 if( selection.Size() == 1 )
1585 DiffFootprint( static_cast<FOOTPRINT*>( selection.GetItem( 0 ) ) );
1586 else
1587 m_frame->ShowInfoBarError( _( "Select a footprint to diff with its library equivalent." ) );
1588
1589 return 0;
1590}
1591
1592
1594{
1595 wxCHECK( m_frame, 0 );
1596
1598
1599 wxCHECK( selTool, 0 );
1600
1601 const PCB_SELECTION& selection = selTool->GetSelection();
1602
1603 if( selection.Size() != 1 || selection.Front()->Type() != PCB_FOOTPRINT_T )
1604 {
1605 m_frame->ShowInfoBarError( _( "Select a footprint for a footprint associations report." ) );
1606 return 0;
1607 }
1608
1610
1611 dlg.ShowModal();
1612
1613 return 0;
1614}
1615
1616
1618{
1620
1621 wxCHECK( dialog, /* void */ );
1622
1623 dialog->DeleteAllPages();
1624
1625 LIB_ID fpID = aFootprint->GetFPID();
1626 wxString libName = fpID.GetLibNickname();
1627 wxString fpName = fpID.GetLibItemName();
1628 WX_HTML_REPORT_BOX* r = nullptr;
1629
1630 r = dialog->AddHTMLPage( _( "Summary" ) );
1631
1632 r->Report( wxS( "<h7>" ) + _( "Board vs library diff for:" ) + wxS( "</h7>" ) );
1633 r->Report( wxS( "<ul><li>" ) + EscapeHTML( getItemDescription( aFootprint ) ) + wxS( "</li>" )
1634 + wxS( "<li>" ) + _( "Library: " ) + EscapeHTML( libName ) + wxS( "</li>" )
1635 + wxS( "<li>" ) + _( "Library item: " ) + EscapeHTML( fpName ) + wxS( "</li></ul>" ) );
1636
1637 r->Report( "" );
1638
1639 PROJECT* project = aFootprint->GetBoard()->GetProject();
1641 const LIB_TABLE_ROW* libTableRow = nullptr;
1642
1643 try
1644 {
1645 libTableRow = libTable->FindRow( libName );
1646 }
1647 catch( const IO_ERROR& )
1648 {
1649 }
1650
1651 if( !libTableRow )
1652 {
1653 r->Report( _( "The library is not included in the current configuration." )
1654 + wxS( "&nbsp;&nbsp;&nbsp" )
1655 + wxS( "<a href='$CONFIG'>" ) + _( "Manage Footprint Libraries" )
1656 + wxS( "</a>" ) );
1657
1658 }
1659 else if( !libTable->HasLibrary( libName, true ) )
1660 {
1661 r->Report( _( "The library is not enabled in the current configuration." )
1662 + wxS( "&nbsp;&nbsp;&nbsp" )
1663 + wxS( "<a href='$CONFIG'>" ) + _( "Manage Footprint Libraries" )
1664 + wxS( "</a>" ) );
1665
1666 }
1667 else
1668 {
1669 std::shared_ptr<FOOTPRINT> libFootprint;
1670
1671 try
1672 {
1673 libFootprint.reset( libTable->FootprintLoad( libName, fpName, true ) );
1674 }
1675 catch( const IO_ERROR& )
1676 {
1677 }
1678
1679 if( !libFootprint )
1680 {
1681 r->Report( wxString::Format( _( "The library no longer contains the item %s." ),
1682 fpName) );
1683 }
1684 else
1685 {
1686 if( !aFootprint->FootprintNeedsUpdate( libFootprint.get(), 0, r ) )
1687 r->Report( _( "No relevant differences detected." ) );
1688
1689 wxPanel* panel = dialog->AddBlankPage( _( "Visual" ) );
1691
1692 diff->DisplayDiff( aFootprint, libFootprint );
1693 }
1694 }
1695
1696 r->Flush();
1697
1698 dialog->Raise();
1699 dialog->Show( true );
1700}
1701
1702
1704{
1705 wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
1706
1707 FOOTPRINT_DIFF_WIDGET* diffWidget = new FOOTPRINT_DIFF_WIDGET( aParentPanel, m_frame->Kiway() );
1708
1709 sizer->Add( diffWidget, 1, wxEXPAND | wxALL, 5 );
1710 aParentPanel->SetSizer( sizer );
1711 aParentPanel->Layout();
1712
1713 return diffWidget;
1714}
1715
1716
1718{
1719 BOARD_ITEM* item = aEvent.Parameter<BOARD_ITEM*>();
1720
1721 m_frame->m_probingSchToPcb = true; // recursion guard
1722 {
1724
1725 if( item )
1727 }
1728 m_frame->m_probingSchToPcb = false;
1729
1730 bool request3DviewRedraw = frame()->GetPcbNewSettings()->m_Display.m_Live3DRefresh;
1731
1732 if( item && item->Type() != PCB_FOOTPRINT_T )
1733 request3DviewRedraw = false;
1734
1735 // Update 3D viewer highlighting
1736 if( request3DviewRedraw )
1737 m_frame->Update3DView( false, true );
1738
1739 return 0;
1740}
1741
1742
1743 bool BOARD_INSPECTION_TOOL::highlightNet( const VECTOR2D& aPosition, bool aUseSelection )
1744{
1745 BOARD* board = static_cast<BOARD*>( m_toolMgr->GetModel() );
1748
1749 int net = -1;
1750 bool enableHighlight = false;
1751
1752 if( aUseSelection )
1753 {
1754 const PCB_SELECTION& selection = selectionTool->GetSelection();
1755 std::set<int> netcodes;
1756
1757 for( EDA_ITEM* item : selection )
1758 {
1759 if( BOARD_CONNECTED_ITEM* ci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
1760 netcodes.insert( ci->GetNetCode() );
1761 }
1762
1763 enableHighlight = !netcodes.empty();
1764
1765 if( enableHighlight && netcodes.size() > 1 )
1766 {
1767 // If we are doing a multi-highlight, cross-probing back and other stuff is not
1768 // yet supported
1769 settings->SetHighlight( netcodes );
1771
1772 for( int multiNet : netcodes )
1773 board->SetHighLightNet( multiNet, true );
1774
1775 board->HighLightON();
1777 m_currentlyHighlighted = netcodes;
1778 return true;
1779 }
1780 else if( enableHighlight )
1781 {
1782 net = *netcodes.begin();
1783 }
1784 }
1785
1786 // If we didn't get a net to highlight from the selection, use the cursor
1787 if( net < 0 )
1788 {
1790 guide.SetIgnoreZoneFills( false );
1791 guide.SetIgnoreNoNets( true );
1792
1793 PCB_LAYER_ID activeLayer = static_cast<PCB_LAYER_ID>( view()->GetTopLayer() );
1794 guide.SetPreferredLayer( activeLayer );
1795
1796 GENERAL_COLLECTOR collector;
1797 collector.Collect( board, { PCB_PAD_T, PCB_VIA_T, PCB_TRACE_T, PCB_ARC_T, PCB_SHAPE_T }, aPosition,
1798 guide );
1799
1800 if( collector.GetCount() == 0 )
1801 collector.Collect( board, { PCB_ZONE_T }, aPosition, guide );
1802
1803 // Apply the active selection filter, except we want to allow picking locked items for
1804 // highlighting even if the user has disabled them for selection
1805 PCB_SELECTION_FILTER_OPTIONS& filter = selectionTool->GetFilter();
1806
1807 bool saved = filter.lockedItems;
1808 filter.lockedItems = true;
1809
1810 selectionTool->FilterCollectedItems( collector, true );
1811
1812 filter.lockedItems = saved;
1813
1814 // Clear the previous highlight
1815 //m_frame->SendMessageToEESCHEMA( nullptr );
1816
1817 bool highContrast = settings->GetHighContrast();
1818 PCB_LAYER_ID contrastLayer = settings->GetPrimaryHighContrastLayer();
1819
1820 for( int i = collector.GetCount() - 1; i >= 0; i-- )
1821 {
1822 LSET itemLayers = collector[i]->GetLayerSet();
1823
1824 if( ( itemLayers & LSET::AllCuMask() ).none() ||
1825 ( highContrast && !itemLayers.Contains( contrastLayer ) ) )
1826 {
1827 collector.Remove( i );
1828 continue;
1829 }
1830 }
1831
1832 enableHighlight = ( collector.GetCount() > 0 );
1833
1834 // Obtain net code for the clicked item
1835 if( enableHighlight )
1836 {
1837 BOARD_CONNECTED_ITEM* targetItem = static_cast<BOARD_CONNECTED_ITEM*>( collector[0] );
1838
1839 if( targetItem->Type() == PCB_PAD_T )
1840 m_frame->SendCrossProbeItem( targetItem );
1841
1842 net = targetItem->GetNetCode();
1843 }
1844 }
1845
1846 const std::set<int>& netcodes = settings->GetHighlightNetCodes();
1847
1848 // Toggle highlight when the same net was picked
1849 if( !aUseSelection && netcodes.size() == 1 && netcodes.contains( net ) )
1850 enableHighlight = !settings->IsHighlightEnabled();
1851
1852 if( enableHighlight != settings->IsHighlightEnabled() || !netcodes.count( net ) )
1853 {
1854 if( !netcodes.empty() )
1855 m_lastHighlighted = netcodes;
1856
1857 settings->SetHighlight( enableHighlight, net );
1858 m_toolMgr->GetView()->UpdateAllLayersColor();
1859 }
1860
1861 // Store the highlighted netcode in the current board (for dialogs for instance)
1862 if( enableHighlight && net >= 0 )
1863 {
1864 m_currentlyHighlighted = netcodes;
1865 board->SetHighLightNet( net );
1866 board->HighLightON();
1867
1868 NETINFO_ITEM* netinfo = board->FindNet( net );
1869
1870 if( netinfo )
1871 {
1872 std::vector<MSG_PANEL_ITEM> items;
1873 netinfo->GetMsgPanelInfo( m_frame, items );
1874 m_frame->SetMsgPanel( items );
1875 m_frame->SendCrossProbeNetName( netinfo->GetNetname() );
1876 }
1877 }
1878 else
1879 {
1880 m_currentlyHighlighted.clear();
1881 board->ResetNetHighLight();
1882 m_frame->SetMsgPanel( board );
1883 m_frame->SendCrossProbeNetName( "" );
1884 }
1885
1886 return true;
1887}
1888
1889
1891{
1892 int netcode = aEvent.Parameter<int>();
1894 const std::set<int>& highlighted = settings->GetHighlightNetCodes();
1895
1896 if( netcode > 0 )
1897 {
1898 m_lastHighlighted = highlighted;
1899 settings->SetHighlight( true, netcode );
1901 m_currentlyHighlighted.clear();
1902 m_currentlyHighlighted.insert( netcode );
1903 }
1904 else if( aEvent.IsAction( &PCB_ACTIONS::highlightNetSelection ) )
1905 {
1906 // Highlight selection (cursor position will be ignored)
1907 highlightNet( getViewControls()->GetMousePosition(), true );
1908 }
1909 else if( aEvent.IsAction( &PCB_ACTIONS::toggleLastNetHighlight ) )
1910 {
1911 std::set<int> temp = highlighted;
1912 settings->SetHighlight( m_lastHighlighted );
1915 m_lastHighlighted = std::move( temp );
1916 }
1917 else if( aEvent.IsAction( &PCB_ACTIONS::toggleNetHighlight ) )
1918 {
1919 bool turnOn = highlighted.empty() && !m_currentlyHighlighted.empty();
1920 settings->SetHighlight( m_currentlyHighlighted, turnOn );
1922 }
1923 else // Highlight the net belonging to the item under the cursor
1924 {
1925 highlightNet( getViewControls()->GetMousePosition(), false );
1926 }
1927
1928 return 0;
1929}
1930
1931
1933{
1934 BOARD* board = static_cast<BOARD*>( m_toolMgr->GetModel() );
1936
1937 m_currentlyHighlighted.clear();
1938 m_lastHighlighted.clear();
1939
1941 settings->SetHighlight( false );
1945 return 0;
1946}
1947
1948
1950{
1952 BOARD* board = getModel<BOARD>();
1953
1954 // Deactivate other tools; particularly important if another PICKER is currently running
1955 Activate();
1956
1957 picker->SetCursor( KICURSOR::BULLSEYE );
1958 picker->SetSnapping( false );
1959 picker->ClearHandlers();
1960
1961 picker->SetClickHandler(
1962 [this, board]( const VECTOR2D& pt ) -> bool
1963 {
1965
1969
1970 PCB_SELECTION& selection = selectionTool->GetSelection();
1971
1972 if( selection.Empty() )
1973 {
1976 selection = selectionTool->GetSelection();
1977 }
1978
1979 if( selection.Empty() )
1980 {
1981 // Clear the previous local ratsnest if we click off all items
1982 for( FOOTPRINT* fp : board->Footprints() )
1983 {
1984 for( PAD* pad : fp->Pads() )
1985 pad->SetLocalRatsnestVisible( displayOptions().m_ShowGlobalRatsnest );
1986 }
1987 }
1988 else
1989 {
1990 for( EDA_ITEM* item : selection )
1991 {
1992 if( PAD* pad = dyn_cast<PAD*>( item) )
1993 {
1994 pad->SetLocalRatsnestVisible( !pad->GetLocalRatsnestVisible() );
1995 }
1996 else if( FOOTPRINT* fp = dyn_cast<FOOTPRINT*>( item) )
1997 {
1998 if( !fp->Pads().empty() )
1999 {
2000 bool enable = !fp->Pads()[0]->GetLocalRatsnestVisible();
2001
2002 for( PAD* childPad : fp->Pads() )
2003 childPad->SetLocalRatsnestVisible( enable );
2004 }
2005 }
2006 }
2007 }
2008
2010
2011 return true;
2012 } );
2013
2014 picker->SetFinalizeHandler(
2015 [this, board]( int aCondition )
2016 {
2017 if( aCondition != PCB_PICKER_TOOL::END_ACTIVATE )
2018 {
2019 for( FOOTPRINT* fp : board->Footprints() )
2020 {
2021 for( PAD* pad : fp->Pads() )
2022 pad->SetLocalRatsnestVisible( displayOptions().m_ShowGlobalRatsnest );
2023 }
2024 }
2025 } );
2026
2028
2029 return 0;
2030}
2031
2032
2034{
2035 VECTOR2I delta = aEvent.Parameter<VECTOR2I>();
2036
2037 if( delta == VECTOR2I() )
2038 {
2039 // We can delete the existing map to force a recalculation
2040 delete m_dynamicData;
2041 m_dynamicData = nullptr;
2042 }
2043
2044 auto selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
2045 auto& selection = selectionTool->GetSelection();
2046 auto connectivity = getModel<BOARD>()->GetConnectivity();
2047
2048 if( selection.Empty() )
2049 {
2050 connectivity->ClearLocalRatsnest();
2051 delete m_dynamicData;
2052 m_dynamicData = nullptr;
2053 }
2054 else
2055 {
2057 }
2058
2059 return 0;
2060}
2061
2062
2064{
2065 getModel<BOARD>()->GetConnectivity()->ClearLocalRatsnest();
2066 delete m_dynamicData;
2067 m_dynamicData = nullptr;
2068
2069 return 0;
2070}
2071
2072
2074{
2076 SELECTION& selection = selectionTool->GetSelection();
2077 std::shared_ptr<CONNECTIVITY_DATA> connectivity = board()->GetConnectivity();
2078 std::vector<BOARD_ITEM*> items;
2079 std::deque<EDA_ITEM*> queued_items( selection.begin(), selection.end() );
2080
2081 for( std::size_t i = 0; i < queued_items.size(); ++i )
2082 {
2083 if( !queued_items[i]->IsBOARD_ITEM() )
2084 continue;
2085
2086 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( queued_items[i] );
2087
2088 wxCHECK2( item, continue );
2089
2090 if( item->Type() == PCB_FOOTPRINT_T )
2091 {
2092 for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
2093 {
2094 if( pad->GetLocalRatsnestVisible() || displayOptions().m_ShowModuleRatsnest )
2095 items.push_back( pad );
2096 }
2097 }
2098 else if( item->Type() == PCB_GROUP_T || item->Type() == PCB_GENERATOR_T )
2099 {
2100 item->RunOnChildren( [ &queued_items ]( BOARD_ITEM *aItem )
2101 {
2102 queued_items.push_back( aItem );
2103 },
2104 RECURSE_MODE::RECURSE );
2105 }
2106 else if( BOARD_CONNECTED_ITEM* boardItem = dyn_cast<BOARD_CONNECTED_ITEM*>( item ) )
2107 {
2108 if( boardItem->GetLocalRatsnestVisible() || displayOptions().m_ShowModuleRatsnest )
2109 items.push_back( boardItem );
2110 }
2111 }
2112
2113 if( items.empty() || std::none_of( items.begin(), items.end(),
2114 []( const BOARD_ITEM* aItem )
2115 {
2116 return( aItem->Type() == PCB_TRACE_T
2117 || aItem->Type() == PCB_PAD_T
2118 || aItem->Type() == PCB_ARC_T
2119 || aItem->Type() == PCB_ZONE_T
2120 || aItem->Type() == PCB_FOOTPRINT_T
2121 || aItem->Type() == PCB_VIA_T
2122 || aItem->Type() == PCB_SHAPE_T );
2123 } ) )
2124 {
2125 return;
2126 }
2127
2128 if( !m_dynamicData )
2129 {
2130 m_dynamicData = new CONNECTIVITY_DATA( board()->GetConnectivity(), items, true );
2131 connectivity->BlockRatsnestItems( items );
2132 }
2133 else
2134 {
2135 m_dynamicData->Move( aDelta );
2136 }
2137
2138 connectivity->ComputeLocalRatsnest( items, m_dynamicData );
2139}
2140
2141
2143{
2144 doHideRatsnestNet( aEvent.Parameter<int>(), true );
2145 return 0;
2146}
2147
2148
2150{
2151 doHideRatsnestNet( aEvent.Parameter<int>(), false );
2152 return 0;
2153}
2154
2155
2156void BOARD_INSPECTION_TOOL::doHideRatsnestNet( int aNetCode, bool aHide )
2157{
2160
2162 SELECTION& selection = selectionTool->GetSelection();
2163
2164 if( aNetCode <= 0 && !selection.Empty() )
2165 {
2166 for( EDA_ITEM* item : selection )
2167 {
2168 if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
2169 {
2170 if( bci->GetNetCode() > 0 )
2171 doHideRatsnestNet( bci->GetNetCode(), aHide );
2172 }
2173 }
2174
2175 return;
2176 }
2177
2178 if( aHide )
2179 rs->GetHiddenNets().insert( aNetCode );
2180 else
2181 rs->GetHiddenNets().erase( aNetCode );
2182
2184 {
2187
2188 m_frame->GetAppearancePanel()->OnNetVisibilityChanged( aNetCode, !aHide );
2189 }
2190}
2191
2192
2194{
2198
2204
2211
2214}
std::function< void(const VECTOR2I &, GENERAL_COLLECTOR &, PCB_SELECTION_TOOL *)> CLIENT_SELECTION_FILTER
Definition: actions.h:38
#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:224
static TOOL_ACTION selectionCursor
Select a single item under the cursor position.
Definition: actions.h:214
static TOOL_ACTION pickerTool
Definition: actions.h:250
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: actions.h:221
Define the structure of a menu based on ACTIONs.
Definition: action_menu.h:49
void SetTitle(const wxString &aTitle) override
Set title for the menu.
Definition: action_menu.cpp:92
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
Definition: action_menu.cpp:78
wxMenuItem * Add(const wxString &aLabel, int aId, BITMAPS aIcon)
Add a wxWidgets-style entry to the menu.
void OnNetVisibilityChanged(int aNetCode, bool aVisibility)
Notifies the panel when a net has been hidden or shown via the external tool.
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)
int LocalRatsnestTool(const TOOL_EVENT &aEvent)
Hide the ratsnest for a given net.
std::set< int > m_lastHighlighted
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.
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)
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:79
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:232
virtual bool IsConnected() const
Returns information if the object is derived from BOARD_CONNECTED_ITEM.
Definition: board_item.h:134
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Test to see if this object is on the given layer.
Definition: board_item.h:314
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:79
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:252
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:173
virtual void RunOnChildren(const std::function< void(BOARD_ITEM *)> &aFunction, RECURSE_MODE aMode) const
Invoke a function on all children.
Definition: board_item.h:208
virtual bool HasDrilledHole() const
Definition: board_item.h:161
virtual bool IsOnCopperLayer() const
Definition: board_item.h:151
virtual bool HasHole() const
Definition: board_item.h:156
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:317
void SetHighLightNet(int aNetCode, bool aMulti=false)
Select the netcode to be highlighted.
Definition: board.cpp:2842
const ZONES & Zones() const
Definition: board.h:362
void ResetNetHighLight()
Reset all high light data to the init state.
Definition: board.cpp:2833
const FOOTPRINTS & Footprints() const
Definition: board.h:358
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:680
PROJECT * GetProject() const
Definition: board.h:538
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:1024
void HighLightON(bool aValue=true)
Enable or disable net highlighting.
Definition: board.cpp:2855
BOARD_ITEM * ResolveItem(const KIID &aID, bool aAllowNullptrReturn=false) const
Definition: board.cpp:1583
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition: board.h:522
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:83
void AddMenu(ACTION_MENU *aMenu, const SELECTION_CONDITION &aCondition=SELECTION_CONDITIONS::ShowAlways, int aOrder=ANY_ORDER)
Add a submenu to the menu.
void Move(const VECTOR2I &aDelta)
Moves the connectivity list anchors.
Dialog to show common board info.
wxPanel * AddBlankPage(const wxString &aTitle)
WX_HTML_REPORT_BOX * AddHTMLPage(const wxString &aTitle)
Dialog to show footprint library and symbol links.
bool Show(bool show) override
int ShowModal() override
wxString GetName() const
Definition: drc_rule.h:168
int m_DisallowFlags
Definition: drc_rule.h:203
ZONE_CONNECTION m_ZoneConnection
Definition: drc_rule.h:204
MINOPTMAX< int > m_Value
Definition: drc_rule.h:202
bool IsNull() const
Definition: drc_rule.h:155
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.
void ShowInfoBarError(const wxString &aErrorMsg, bool aShowCloseButton=false, WX_INFOBAR::MESSAGE_TYPE aType=WX_INFOBAR::MESSAGE_TYPE::GENERIC)
Show the WX_INFOBAR displayed on the top of the canvas with a message and an error icon on the left o...
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
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
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:110
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:145
static void PadFilter(const VECTOR2I &, GENERAL_COLLECTOR &aCollector, PCB_SELECTION_TOOL *sTool)
A selection filter which prunes the selection to contain only items of type PCB_PAD_T.
Definition: edit_tool.cpp:3176
static void FootprintFilter(const VECTOR2I &, GENERAL_COLLECTOR &aCollector, PCB_SELECTION_TOOL *sTool)
A selection filter which prunes the selection to contain only items of type #PCB_MODULE_T.
Definition: edit_tool.cpp:3186
void DisplayDiff(FOOTPRINT *aBoardFootprint, std::shared_ptr< FOOTPRINT > &aLibFootprint)
Set the currently displayed symbol.
ZONES & Zones()
Definition: footprint.h:215
bool FootprintNeedsUpdate(const FOOTPRINT *aLibFP, int aCompareFlags=0, REPORTER *aReporter=nullptr)
Return true if a board footprint differs from the library version.
std::deque< PAD * > & Pads()
Definition: footprint.h:209
const LIB_ID & GetFPID() const
Definition: footprint.h:251
void BuildCourtyardCaches(OUTLINE_ERROR_HANDLER *aErrorHandler=nullptr)
Build complex polygons of the courtyard areas from graphic items on the courtyard layers.
Definition: footprint.cpp:3081
const SHAPE_POLY_SET & GetCourtyard(PCB_LAYER_ID aLayer) const
Used in DRC to test the courtyard area (a complex polygon).
Definition: footprint.cpp:3058
const FP_LIB_TABLE_ROW * FindRow(const wxString &aNickName, bool aCheckIfEnabled=false)
Return an FP_LIB_TABLE_ROW if aNickName is found in this table or in any chained fall back table frag...
FOOTPRINT * FootprintLoad(const wxString &aNickname, const wxString &aFootprintName, bool aKeepUUID=false)
Load a footprint having aFootprintName from the library given by aNickname.
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.
Definition: collectors.cpp:505
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:77
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:80
std::set< int > & GetHiddenNets()
Definition: pcb_painter.h:140
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 GetHighContrast() const
void SetHighlight(bool aEnabled, int aNetcode=-1, bool aMulti=false)
Turns on/off highlighting.
bool IsBOARD_ITEM() const
Definition: view_item.h:102
void UpdateAllLayersColor()
Apply the new coloring scheme to all layers.
Definition: view.cpp:775
virtual int GetTopLayer() const
Definition: view.cpp:830
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:220
void MarkTargetDirty(int aTarget)
Set or clear target 'dirty' flag.
Definition: view.h:639
Definition: kiid.h:49
KIWAY & Kiway() const
Return a reference to the KIWAY that this object has an opportunity to participate in.
Definition: kiway_holder.h:55
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
Hold a record identifying a library accessed by the appropriate plug in object in the LIB_TABLE.
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library table.
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:296
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition: lset.cpp:591
static const LSET & PhysicalLayersMask()
Return a mask holding all layers which are physically realized.
Definition: lset.cpp:680
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:288
Handle the data for a net.
Definition: netinfo.h:56
const wxString & GetNetname() const
Definition: netinfo.h:114
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:54
const VECTOR2I & GetDrillSize() const
Definition: pad.h:305
PAD_ATTRIB GetAttribute() const
Definition: pad.h:440
static TOOL_ACTION highlightItem
Definition: pcb_actions.h:570
static TOOL_ACTION toggleNetHighlight
Definition: pcb_actions.h:568
static TOOL_ACTION highlightNet
Definition: pcb_actions.h:566
static TOOL_ACTION hideNetInRatsnest
Definition: pcb_actions.h:573
static TOOL_ACTION hideLocalRatsnest
Definition: pcb_actions.h:576
static TOOL_ACTION showNetInRatsnest
Definition: pcb_actions.h:574
static TOOL_ACTION cleanupTracksAndVias
Definition: pcb_actions.h:437
static TOOL_ACTION toggleLastNetHighlight
Definition: pcb_actions.h:567
static TOOL_ACTION inspectConstraints
Definition: pcb_actions.h:559
static TOOL_ACTION clearHighlight
Definition: pcb_actions.h:565
static TOOL_ACTION inspectClearance
Definition: pcb_actions.h:558
static TOOL_ACTION updateLocalRatsnest
Definition: pcb_actions.h:577
static TOOL_ACTION diffFootprint
Definition: pcb_actions.h:560
static TOOL_ACTION showFootprintAssociations
Definition: pcb_actions.h:561
static TOOL_ACTION highlightNetSelection
Definition: pcb_actions.h:569
static TOOL_ACTION boardStatistics
Definition: pcb_actions.h:554
static TOOL_ACTION localRatsnestTool
Definition: pcb_actions.h:575
wxString GetDesignRulesPath()
Return the absolute path to the design rules file for the currently-loaded board.
APPEARANCE_CONTROLS * GetAppearancePanel()
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
virtual PCB_LAYER_ID GetActiveLayer() const
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
BOARD * GetBoard() const
GENERAL_COLLECTORS_GUIDE GetCollectorsGuide()
virtual void Update3DView(bool aMarkDirty, bool aRefresh, const wxString *aTitle=nullptr)
Update the 3D view, if the viewer is opened by this frame.
void RedrawRatsnest()
Return the bounding box of the view that should be used if model is not valid.
DIALOG_BOOK_REPORTER * GetInspectDrcErrorDialog()
void SendCrossProbeItem(BOARD_ITEM *aSyncItem)
Send a message to the schematic editor so that it may move its cursor to an item with the same refere...
DIALOG_BOOK_REPORTER * GetFootprintDiffDialog()
DIALOG_BOOK_REPORTER * GetInspectClearanceDialog()
void SendCrossProbeNetName(const wxString &aNetName)
Send a net name to Eeschema for highlighting.
DIALOG_BOOK_REPORTER * GetInspectConstraintsDialog()
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:
PCB_SELECTION & RequestSelection(CLIENT_SELECTION_FILTER aClientFilter, bool aConfirmLockedItems=false)
Return the current selection, filtered according to aClientFilter.
void FilterCollectedItems(GENERAL_COLLECTOR &aCollector, bool aMultiSelect)
Apply the SELECTION_FITLER_OPTIONS to the collector.
PCB_SELECTION_FILTER_OPTIONS & GetFilter()
Set up handlers for various events.
PCB_SELECTION & GetSelection()
T * frame() const
KIGFX::PCB_VIEW * view() const
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 ClearHandlers()
Definition: picker_tool.h:68
void SetCursor(KICURSOR aCursor)
Definition: picker_tool.h:64
void SetFinalizeHandler(FINALIZE_HANDLER aHandler)
Set a handler for the finalize event.
Definition: picker_tool.h:112
static FP_LIB_TABLE * PcbFootprintLibs(PROJECT *aProject)
Return the table of footprint libraries without Kiway.
Definition: project_pcb.cpp:37
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
virtual KIGFX::VIEW_ITEM * GetItem(unsigned int aIdx) const override
Definition: selection.cpp:75
ITER end()
Definition: selection.h:80
ITER begin()
Definition: selection.h:79
EDA_ITEM * Front() const
Definition: selection.h:177
int Size() const
Returns the number of selected parts.
Definition: selection.h:121
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:115
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
Represent a single user action.
Definition: tool_action.h:304
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:168
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
Definition: tool_event.cpp:82
T Parameter() const
Return a parameter assigned to the event.
Definition: tool_event.h:465
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()
void Activate()
Run the tool.
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:150
EDA_ITEM * GetModel() const
Definition: tool_manager.h:402
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:395
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:814
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Test to see if this object is on the given layer.
Definition: zone.cpp:615
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: zone.h:136
@ DRCE_HOLE_CLEARANCE
Definition: drc_item.h:54
@ DRCE_VIA_DIAMETER
Definition: drc_item.h:61
@ DRCE_TRACK_WIDTH
Definition: drc_item.h:55
@ DRCE_DRILL_OUT_OF_RANGE
Definition: drc_item.h:60
@ DRCE_EDGE_CLEARANCE
Definition: drc_item.h:46
@ DRCE_STARVED_THERMAL
Definition: drc_item.h:49
@ DRCE_TRACK_SEGMENT_LENGTH
Definition: drc_item.h:57
@ DRCE_TRACK_ANGLE
Definition: drc_item.h:56
@ DRCE_CLEARANCE
Definition: drc_item.h:43
@ DRCE_DRILLED_HOLES_TOO_CLOSE
Definition: drc_item.h:52
@ DRCE_DIFF_PAIR_UNCOUPLED_LENGTH_TOO_LONG
Definition: drc_item.h:107
@ DRCE_MICROVIA_DRILL_OUT_OF_RANGE
Definition: drc_item.h:64
@ DRCE_DANGLING_VIA
Definition: drc_item.h:50
@ DRCE_DANGLING_TRACK
Definition: drc_item.h:51
@ DRCE_TEXT_HEIGHT
Definition: drc_item.h:99
@ DRCE_ASSERTION_FAILURE
Definition: drc_item.h:88
@ DRCE_LIB_FOOTPRINT_MISMATCH
Definition: drc_item.h:83
@ DRCE_TEXT_THICKNESS
Definition: drc_item.h:100
@ DRCE_CONNECTION_WIDTH
Definition: drc_item.h:59
@ DRCE_ANNULAR_WIDTH
Definition: drc_item.h:58
@ 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)
#define MALFORMED_COURTYARDS
bool IsFrontLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a front layer.
Definition: layer_ids.h:767
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition: layer_ids.h:665
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
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
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,...
Definition: ki_exception.h:120
This file contains data structures that are saved in the project file or project local settings file ...
int clearance
int delta
@ 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:110
@ 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:107
@ 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
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695