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