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-2024 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( " " ) + wxString::Format( _( "[netclass %s]" ),
201 cItem->GetEffectiveNetClass()->GetName() );
202 }
203
204 return msg;
205};
206
207
209{
210 r->Report( "" );
211 r->Report( _( "Report incomplete: could not compile custom design rules." )
212 + wxS( "&nbsp;&nbsp;" )
213 + wxS( "<a href='$CUSTOM_RULES'>" ) + _( "Show design rules." ) + wxS( "</a>" ) );
214}
215
216
217void BOARD_INSPECTION_TOOL::reportHeader( const wxString& aTitle, BOARD_ITEM* a, REPORTER* r )
218{
219 r->Report( wxT( "<h7>" ) + EscapeHTML( aTitle ) + wxT( "</h7>" ) );
220 r->Report( wxT( "<ul><li>" ) + EscapeHTML( getItemDescription( a ) ) + wxT( "</li></ul>" ) );
221}
222
223
224void BOARD_INSPECTION_TOOL::reportHeader( const wxString& aTitle, BOARD_ITEM* a, BOARD_ITEM* b,
225 REPORTER* r )
226{
227 r->Report( wxT( "<h7>" ) + EscapeHTML( aTitle ) + wxT( "</h7>" ) );
228 r->Report( wxT( "<ul><li>" ) + EscapeHTML( getItemDescription( a ) ) + wxT( "</li>" )
229 + wxT( "<li>" ) + EscapeHTML( getItemDescription( b ) ) + wxT( "</li></ul>" ) );
230}
231
232
233void BOARD_INSPECTION_TOOL::reportHeader( const wxString& aTitle, BOARD_ITEM* a, BOARD_ITEM* b,
234 PCB_LAYER_ID aLayer, REPORTER* r )
235{
236 wxString layerStr = _( "Layer" ) + wxS( " " ) + m_frame->GetBoard()->GetLayerName( aLayer );
237
238 r->Report( wxT( "<h7>" ) + EscapeHTML( aTitle ) + wxT( "</h7>" ) );
239 r->Report( wxT( "<ul><li>" ) + EscapeHTML( layerStr ) + wxT( "</li>" )
240 + wxT( "<li>" ) + EscapeHTML( getItemDescription( a ) ) + wxT( "</li>" )
241 + wxT( "<li>" ) + EscapeHTML( getItemDescription( b ) ) + wxT( "</li></ul>" ) );
242}
243
244
245wxString reportMin( PCB_BASE_FRAME* aFrame, DRC_CONSTRAINT& aConstraint )
246{
247 if( aConstraint.m_Value.HasMin() )
248 return aFrame->StringFromValue( aConstraint.m_Value.Min(), true );
249 else
250 return wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
251}
252
253
254wxString reportOpt( PCB_BASE_FRAME* aFrame, DRC_CONSTRAINT& aConstraint )
255{
256 if( aConstraint.m_Value.HasOpt() )
257 return aFrame->StringFromValue( aConstraint.m_Value.Opt(), true );
258 else
259 return wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
260}
261
262
263wxString reportMax( PCB_BASE_FRAME* aFrame, DRC_CONSTRAINT& aConstraint )
264{
265 if( aConstraint.m_Value.HasMax() )
266 return aFrame->StringFromValue( aConstraint.m_Value.Max(), true );
267 else
268 return wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
269}
270
271
272wxString BOARD_INSPECTION_TOOL::InspectDRCErrorMenuText( const std::shared_ptr<RC_ITEM>& aDRCItem )
273{
274 auto menuDescription =
275 [&]( const TOOL_ACTION& aAction )
276 {
277 wxString menuItemLabel = aAction.GetMenuLabel();
278 wxMenuBar* menuBar = m_frame->GetMenuBar();
279
280 for( size_t ii = 0; ii < menuBar->GetMenuCount(); ++ii )
281 {
282 for( wxMenuItem* menuItem : menuBar->GetMenu( ii )->GetMenuItems() )
283 {
284 if( menuItem->GetItemLabelText() == menuItemLabel )
285 {
286 wxString menuTitleLabel = menuBar->GetMenuLabelText( ii );
287
288 menuTitleLabel.Replace( wxS( "&" ), wxS( "&&" ) );
289 menuItemLabel.Replace( wxS( "&" ), wxS( "&&" ) );
290
291 return wxString::Format( _( "Run %s > %s" ),
292 menuTitleLabel,
293 menuItemLabel );
294 }
295 }
296 }
297
298 return wxString::Format( _( "Run %s" ), aAction.GetFriendlyName() );
299 };
300
301 if( aDRCItem->GetErrorCode() == DRCE_CLEARANCE
302 || aDRCItem->GetErrorCode() == DRCE_EDGE_CLEARANCE
303 || aDRCItem->GetErrorCode() == DRCE_HOLE_CLEARANCE
304 || aDRCItem->GetErrorCode() == DRCE_DRILLED_HOLES_TOO_CLOSE )
305 {
306 return menuDescription( PCB_ACTIONS::inspectClearance );
307 }
308 else if( aDRCItem->GetErrorCode() == DRCE_TEXT_HEIGHT
309 || aDRCItem->GetErrorCode() == DRCE_TEXT_THICKNESS
310 || aDRCItem->GetErrorCode() == DRCE_DIFF_PAIR_UNCOUPLED_LENGTH_TOO_LONG
311 || aDRCItem->GetErrorCode() == DRCE_TRACK_WIDTH
312 || aDRCItem->GetErrorCode() == DRCE_TRACK_ANGLE
313 || aDRCItem->GetErrorCode() == DRCE_TRACK_SEGMENT_LENGTH
314 || aDRCItem->GetErrorCode() == DRCE_VIA_DIAMETER
315 || aDRCItem->GetErrorCode() == DRCE_ANNULAR_WIDTH
316 || aDRCItem->GetErrorCode() == DRCE_DRILL_OUT_OF_RANGE
317 || aDRCItem->GetErrorCode() == DRCE_MICROVIA_DRILL_OUT_OF_RANGE
318 || aDRCItem->GetErrorCode() == DRCE_CONNECTION_WIDTH
319 || aDRCItem->GetErrorCode() == DRCE_ASSERTION_FAILURE )
320 {
321 return menuDescription( PCB_ACTIONS::inspectConstraints );
322 }
323 else if( aDRCItem->GetErrorCode() == DRCE_LIB_FOOTPRINT_MISMATCH )
324 {
325 return menuDescription( PCB_ACTIONS::diffFootprint );
326 }
327 else if( aDRCItem->GetErrorCode() == DRCE_DANGLING_TRACK
328 || aDRCItem->GetErrorCode() == DRCE_DANGLING_VIA )
329 {
330 return menuDescription( PCB_ACTIONS::cleanupTracksAndVias );
331 }
332
333 return wxEmptyString;
334}
335
336
337void BOARD_INSPECTION_TOOL::InspectDRCError( const std::shared_ptr<RC_ITEM>& aDRCItem )
338{
339 wxCHECK( m_frame, /* void */ );
340
341 BOARD_ITEM* a = m_frame->GetBoard()->GetItem( aDRCItem->GetMainItemID() );
342 BOARD_ITEM* b = m_frame->GetBoard()->GetItem( aDRCItem->GetAuxItemID() );
343 BOARD_CONNECTED_ITEM* ac = dynamic_cast<BOARD_CONNECTED_ITEM*>( a );
344 BOARD_CONNECTED_ITEM* bc = dynamic_cast<BOARD_CONNECTED_ITEM*>( b );
346
347 if( aDRCItem->GetErrorCode() == DRCE_LIB_FOOTPRINT_MISMATCH )
348 {
349 if( FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( a ) )
351
352 return;
353 }
354 else if( aDRCItem->GetErrorCode() == DRCE_DANGLING_TRACK
355 || aDRCItem->GetErrorCode() == DRCE_DANGLING_VIA )
356 {
358 return;
359 }
360
362 wxCHECK( dialog, /* void */ );
363
364 dialog->DeleteAllPages();
365
366 bool compileError = false;
367 bool courtyardError = false;
368 std::unique_ptr<DRC_ENGINE> drcEngine = makeDRCEngine( &compileError, &courtyardError );
369
370 WX_HTML_REPORT_BOX* r = nullptr;
371 DRC_CONSTRAINT constraint;
372 int clearance = 0;
373 wxString clearanceStr;
374
375 switch( aDRCItem->GetErrorCode() )
376 {
378 {
379 for( KIID id : aDRCItem->GetIDs() )
380 {
381 bc = dynamic_cast<BOARD_CONNECTED_ITEM*>( m_frame->GetBoard()->GetItem( id ) );
382
383 if( ac && bc && ac->GetNetCode() != bc->GetNetCode() )
384 break;
385 }
386
387 r = dialog->AddHTMLPage( _( "Uncoupled Length" ) );
388 reportHeader( _( "Diff pair uncoupled length resolution for:" ), ac, bc, r );
389
390 if( compileError )
392
393 constraint = drcEngine->EvalRules( MAX_UNCOUPLED_CONSTRAINT, a, b, layer, r );
394
395 r->Report( "" );
396 r->Report( wxString::Format( _( "Resolved max uncoupled length: %s." ),
397 reportMax( m_frame, constraint ) ) );
398 break;
399 }
400
401 case DRCE_TEXT_HEIGHT:
402 r = dialog->AddHTMLPage( _( "Text Height" ) );
403 reportHeader( _( "Text height resolution for:" ), a, r );
404
405 if( compileError )
407
408 constraint = drcEngine->EvalRules( TEXT_HEIGHT_CONSTRAINT, a, b, layer, r );
409
410 r->Report( "" );
411 r->Report( wxString::Format( _( "Resolved height constraints: min %s; max %s." ),
412 reportMin( m_frame, constraint ),
413 reportMax( m_frame, constraint ) ) );
414 break;
415
417 r = dialog->AddHTMLPage( _( "Text Thickness" ) );
418 reportHeader( _( "Text thickness resolution for:" ), a, r );
419
420 if( compileError )
422
423 constraint = drcEngine->EvalRules( TEXT_THICKNESS_CONSTRAINT, a, b, layer, r );
424
425 r->Report( "" );
426 r->Report( wxString::Format( _( "Resolved thickness constraints: min %s; max %s." ),
427 reportMin( m_frame, constraint ),
428 reportMax( m_frame, constraint ) ) );
429 break;
430
431 case DRCE_TRACK_WIDTH:
432 r = dialog->AddHTMLPage( _( "Track Width" ) );
433 reportHeader( _( "Track width resolution for:" ), a, r );
434
435 if( compileError )
437
438 constraint = drcEngine->EvalRules( TRACK_WIDTH_CONSTRAINT, a, b, layer, r );
439
440 r->Report( "" );
441 r->Report( wxString::Format( _( "Resolved width constraints: min %s; max %s." ),
442 reportMin( m_frame, constraint ),
443 reportMax( m_frame, constraint ) ) );
444 break;
445
446 case DRCE_TRACK_ANGLE:
447 r = dialog->AddHTMLPage( _( "Track Angle" ) );
448 reportHeader( _( "Track Angle resolution for:" ), a, r );
449
450 if( compileError )
452
453 constraint = drcEngine->EvalRules( TRACK_ANGLE_CONSTRAINT, a, b, layer, r );
454
455 r->Report( "" );
456 r->Report( wxString::Format( _( "Resolved angle constraints: min %s; max %s." ),
457 reportMin( m_frame, constraint ),
458 reportMax( m_frame, constraint ) ) );
459 break;
460
462 r = dialog->AddHTMLPage( _( "Track Segment Length" ) );
463 reportHeader( _( "Track segment length resolution for:" ), a, r );
464
465 if( compileError )
467
468 constraint = drcEngine->EvalRules( TRACK_SEGMENT_LENGTH_CONSTRAINT, a, b, layer, r );
469
470 r->Report( "" );
471 r->Report( wxString::Format( _( "Resolved segment length constraints: min %s; max %s." ),
472 reportMin( m_frame, constraint ),
473 reportMax( m_frame, constraint ) ) );
474 break;
475
477 r = dialog->AddHTMLPage( _( "Connection Width" ) );
478 reportHeader( _( "Connection width resolution for:" ), a, b, r );
479
480 if( compileError )
482
483 constraint = drcEngine->EvalRules( CONNECTION_WIDTH_CONSTRAINT, a, b, layer, r );
484
485 r->Report( "" );
486 r->Report( wxString::Format( _( "Resolved min connection width: %s." ),
487 reportMin( m_frame, constraint ) ) );
488 break;
489
491 r = dialog->AddHTMLPage( _( "Via Diameter" ) );
492 reportHeader( _( "Via diameter resolution for:" ), a, r );
493
494 if( compileError )
496
497 constraint = drcEngine->EvalRules( VIA_DIAMETER_CONSTRAINT, a, b, layer, r );
498
499 r->Report( "" );
500 r->Report( wxString::Format( _( "Resolved diameter constraints: min %s; max %s." ),
501 reportMin( m_frame, constraint ),
502 reportMax( m_frame, constraint ) ) );
503 break;
504
506 r = dialog->AddHTMLPage( _( "Via Annulus" ) );
507 reportHeader( _( "Via annular width resolution for:" ), a, r );
508
509 if( compileError )
511
512 constraint = drcEngine->EvalRules( ANNULAR_WIDTH_CONSTRAINT, a, b, layer, r );
513
514 r->Report( "" );
515 r->Report( wxString::Format( _( "Resolved annular width constraints: min %s; max %s." ),
516 reportMin( m_frame, constraint ),
517 reportMax( m_frame, constraint ) ) );
518 break;
519
522 r = dialog->AddHTMLPage( _( "Hole Size" ) );
523 reportHeader( _( "Hole size resolution for:" ), a, r );
524
525 if( compileError )
527
528 constraint = drcEngine->EvalRules( HOLE_SIZE_CONSTRAINT, a, b, layer, r );
529
530 r->Report( "" );
531 r->Report( wxString::Format( _( "Resolved hole size constraints: min %s; max %s." ),
532 reportMin( m_frame, constraint ),
533 reportMax( m_frame, constraint ) ) );
534 break;
535
537 r = dialog->AddHTMLPage( _( "Hole Clearance" ) );
538 reportHeader( _( "Hole clearance resolution for:" ), a, b, r );
539
540 if( compileError )
542
543 if( ac && bc && ac->GetNetCode() == bc->GetNetCode() )
544 {
545 r->Report( "" );
546 r->Report( _( "Items belong to the same net. Clearance is 0." ) );
547 }
548 else
549 {
550 constraint = drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, a, b, layer, r );
551 clearance = constraint.m_Value.Min();
552 clearanceStr = m_frame->StringFromValue( clearance, true );
553
554 r->Report( "" );
555 r->Report( wxString::Format( _( "Resolved min clearance: %s." ), clearanceStr ) );
556 }
557
558 r->Report( "" );
559 r->Report( "" );
560 r->Report( "" );
561 reportHeader( _( "Physical hole clearance resolution for:" ), a, b, layer, r );
562
563 constraint = drcEngine->EvalRules( PHYSICAL_HOLE_CLEARANCE_CONSTRAINT, a, b, layer, r );
564 clearance = constraint.m_Value.Min();
565 clearanceStr = m_frame->StringFromValue( clearance, true );
566
567 if( !drcEngine->HasRulesForConstraintType( PHYSICAL_HOLE_CLEARANCE_CONSTRAINT ) )
568 {
569 r->Report( "" );
570 r->Report( _( "No 'physical_hole_clearance' constraints defined." ) );
571 }
572 else
573 {
574 r->Report( "" );
575 r->Report( wxString::Format( _( "Resolved min clearance: %s." ), clearanceStr ) );
576 }
577
578 break;
579
581 r = dialog->AddHTMLPage( _( "Hole to Hole" ) );
582 reportHeader( _( "Hole-to-hole clearance resolution for:" ), a, b, r );
583
584 if( compileError )
586
587 constraint = drcEngine->EvalRules( HOLE_TO_HOLE_CONSTRAINT, a, b, UNDEFINED_LAYER, r );
588 clearance = constraint.m_Value.Min();
589 clearanceStr = m_frame->StringFromValue( clearance, true );
590
591 r->Report( "" );
592 r->Report( wxString::Format( _( "Resolved min clearance: %s." ), clearanceStr ) );
593 break;
594
596 r = dialog->AddHTMLPage( _( "Edge Clearance" ) );
597 reportHeader( _( "Edge clearance resolution for:" ), a, b, r );
598
599 if( compileError )
601
602 constraint = drcEngine->EvalRules( EDGE_CLEARANCE_CONSTRAINT, a, b, layer, r );
603 clearance = constraint.m_Value.Min();
604 clearanceStr = m_frame->StringFromValue( clearance, true );
605
606 r->Report( "" );
607 r->Report( wxString::Format( _( "Resolved min clearance: %s." ), clearanceStr ) );
608 break;
609
610 case DRCE_CLEARANCE:
611 if( a->Type() == PCB_TRACE_T || a->Type() == PCB_ARC_T )
612 {
613 layer = a->GetLayer();
614 }
615 else if( b->Type() == PCB_TRACE_T || b->Type() == PCB_ARC_T )
616 {
617 layer = b->GetLayer();
618 }
619 else if( a->Type() == PCB_PAD_T
620 && static_cast<PAD*>( a )->GetAttribute() == PAD_ATTRIB::SMD )
621 {
622 PAD* pad = static_cast<PAD*>( a );
623
624 if( pad->IsOnLayer( F_Cu ) )
625 layer = F_Cu;
626 else
627 layer = B_Cu;
628 }
629 else if( b->Type() == PCB_PAD_T
630 && static_cast<PAD*>( a )->GetAttribute() == PAD_ATTRIB::SMD )
631 {
632 PAD* pad = static_cast<PAD*>( b );
633
634 if( pad->IsOnLayer( F_Cu ) )
635 layer = F_Cu;
636 else
637 layer = B_Cu;
638 }
639
640 r = dialog->AddHTMLPage( _( "Clearance" ) );
641 reportHeader( _( "Clearance resolution for:" ), a, b, layer, r );
642
643 if( compileError )
645
646 if( ac && bc && ac->GetNetCode() == bc->GetNetCode() )
647 {
648 r->Report( "" );
649 r->Report( _( "Items belong to the same net. Clearance is 0." ) );
650 }
651 else
652 {
653 constraint = drcEngine->EvalRules( CLEARANCE_CONSTRAINT, a, b, layer, r );
654 clearance = constraint.m_Value.Min();
655 clearanceStr = m_frame->StringFromValue( clearance, true );
656
657 r->Report( "" );
658 r->Report( wxString::Format( _( "Resolved min clearance: %s." ), clearanceStr ) );
659 }
660
661 r->Report( "" );
662 r->Report( "" );
663 r->Report( "" );
664 reportHeader( _( "Physical clearance resolution for:" ), a, b, layer, r );
665
666 constraint = drcEngine->EvalRules( PHYSICAL_CLEARANCE_CONSTRAINT, a, b, layer, r );
667 clearance = constraint.m_Value.Min();
668 clearanceStr = m_frame->StringFromValue( clearance, true );
669
670 if( !drcEngine->HasRulesForConstraintType( PHYSICAL_CLEARANCE_CONSTRAINT ) )
671 {
672 r->Report( "" );
673 r->Report( _( "No 'physical_clearance' constraints defined." ) );
674 }
675 else
676 {
677 r->Report( "" );
678 r->Report( wxString::Format( _( "Resolved min clearance: %s." ), clearanceStr ) );
679 }
680
681 break;
682
684 r = dialog->AddHTMLPage( _( "Assertions" ) );
685 reportHeader( _( "Assertions for:" ), a, r );
686
687 if( compileError )
689
690 drcEngine->ProcessAssertions( a, []( const DRC_CONSTRAINT* c ){}, r );
691 break;
692
693 default:
694 return;
695 }
696
697 r->Flush();
698
699 dialog->Raise();
700 dialog->Show( true );
701}
702
703
705{
706 wxCHECK( m_frame, 0 );
707
709
710 wxCHECK( selTool, 0 );
711
712 const PCB_SELECTION& selection = selTool->GetSelection();
713
714 if( selection.Size() != 2 )
715 {
716 m_frame->ShowInfoBarError( _( "Select two items for a clearance resolution report." ) );
717 return 0;
718 }
719
721 return 0;
722
723 BOARD_ITEM* a = static_cast<BOARD_ITEM*>( selection.GetItem( 0 ) );
724 BOARD_ITEM* b = static_cast<BOARD_ITEM*>( selection.GetItem( 1 ) );
725
726 if( a->Type() == PCB_GROUP_T )
727 {
728 PCB_GROUP* ag = static_cast<PCB_GROUP*>( a );
729
730 if( ag->GetItems().empty() )
731 {
732 m_frame->ShowInfoBarError( _( "Cannot generate clearance report on empty group." ) );
733 return 0;
734 }
735
736 a = *ag->GetItems().begin();
737 }
738
739 if( b->Type() == PCB_GROUP_T )
740 {
741 PCB_GROUP* bg = static_cast<PCB_GROUP*>( b );
742
743 if( bg->GetItems().empty() )
744 {
745 m_frame->ShowInfoBarError( _( "Cannot generate clearance report on empty group." ) );
746 return 0;
747 }
748
749 b = *bg->GetItems().begin();
750 }
751
752 // a or b could be null after group tests above.
753 if( !a || !b )
754 return 0;
755
756 auto checkFootprint =
757 [&]( FOOTPRINT* footprint ) -> BOARD_ITEM*
758 {
759 PAD* foundPad = nullptr;
760
761 for( PAD* pad : footprint->Pads() )
762 {
763 if( !foundPad || pad->SameLogicalPadAs( foundPad ) )
764 foundPad = pad;
765 else
766 return footprint;
767 }
768
769 if( !foundPad )
770 return footprint;
771
772 return foundPad;
773 };
774
775 if( a->Type() == PCB_FOOTPRINT_T )
776 a = checkFootprint( static_cast<FOOTPRINT*>( a ) );
777
778 if( b->Type() == PCB_FOOTPRINT_T )
779 b = checkFootprint( static_cast<FOOTPRINT*>( b ) );
780
781 // a or b could be null after footprint tests above.
782 if( !a || !b )
783 return 0;
784
786
787 wxCHECK( dialog, 0 );
788
789 dialog->DeleteAllPages();
790
791 if( a->Type() != PCB_ZONE_T && b->Type() == PCB_ZONE_T )
792 std::swap( a, b );
793 else if( !a->IsConnected() && b->IsConnected() )
794 std::swap( a, b );
795
796 WX_HTML_REPORT_BOX* r = nullptr;
798 LSET layerIntersection = a->GetLayerSet() & b->GetLayerSet();
799 LSET copperIntersection = layerIntersection & LSET::AllCuMask();
800 BOARD_CONNECTED_ITEM* ac = dynamic_cast<BOARD_CONNECTED_ITEM*>( a );
801 BOARD_CONNECTED_ITEM* bc = dynamic_cast<BOARD_CONNECTED_ITEM*>( b );
802 ZONE* zone = dynamic_cast<ZONE*>( a );
803 PAD* pad = dynamic_cast<PAD*>( b );
804 FOOTPRINT* aFP = dynamic_cast<FOOTPRINT*>( a );
805 FOOTPRINT* bFP = dynamic_cast<FOOTPRINT*>( b );
806 DRC_CONSTRAINT constraint;
807 int clearance = 0;
808
809 bool compileError = false;
810 bool courtyardError = false;
811 std::unique_ptr<DRC_ENGINE> drcEngine = makeDRCEngine( &compileError, &courtyardError );
812
813 if( copperIntersection.any() && zone && pad && zone->GetNetCode() == pad->GetNetCode() )
814 {
816
817 if( zone->IsOnLayer( active ) )
818 layer = active;
819 else if( zone->GetLayerSet().count() > 0 )
820 layer = zone->GetLayerSet().Seq().front();
821
822 r = dialog->AddHTMLPage( _( "Zone" ) );
823 reportHeader( _( "Zone connection resolution for:" ), a, b, layer, r );
824
825 constraint = drcEngine->EvalZoneConnection( pad, zone, layer, r );
826
827 if( constraint.m_ZoneConnection == ZONE_CONNECTION::THERMAL )
828 {
829 r->Report( "" );
830 r->Report( "" );
831 reportHeader( _( "Thermal-relief gap resolution for:" ), a, b, layer, r );
832
833 constraint = drcEngine->EvalRules( THERMAL_RELIEF_GAP_CONSTRAINT, pad, zone, layer, r );
834 int gap = constraint.m_Value.Min();
835
836 if( compileError )
838
839 r->Report( "" );
840 r->Report( wxString::Format( _( "Resolved thermal relief gap: %s." ),
841 m_frame->StringFromValue( gap, true ) ) );
842
843 r->Report( "" );
844 r->Report( "" );
845 reportHeader( _( "Thermal-relief spoke width resolution for:" ), a, b, layer, r );
846
847 constraint = drcEngine->EvalRules( THERMAL_SPOKE_WIDTH_CONSTRAINT, pad, zone, layer, r );
848 int width = constraint.m_Value.Opt();
849
850 if( compileError )
852
853 r->Report( "" );
854 r->Report( wxString::Format( _( "Resolved spoke width: %s." ),
855 m_frame->StringFromValue( width, true ) ) );
856
857 r->Report( "" );
858 r->Report( "" );
859 reportHeader( _( "Thermal-relief min spoke count resolution for:" ), a, b, layer, r );
860
861 constraint = drcEngine->EvalRules( MIN_RESOLVED_SPOKES_CONSTRAINT, pad, zone, layer, r );
862 int minSpokes = constraint.m_Value.Min();
863
864 if( compileError )
866
867 r->Report( "" );
868 r->Report( wxString::Format( _( "Resolved min spoke count: %d." ),
869 minSpokes ) );
870
871 std::shared_ptr<CONNECTIVITY_DATA> connectivity = pad->GetBoard()->GetConnectivity();
872 }
873 else if( constraint.m_ZoneConnection == ZONE_CONNECTION::NONE )
874 {
875 r->Report( "" );
876 r->Report( "" );
877 reportHeader( _( "Zone clearance resolution for:" ), a, b, layer, r );
878
879 clearance = zone->GetLocalClearance().value();
880 r->Report( "" );
881 r->Report( wxString::Format( _( "Zone clearance: %s." ),
882 m_frame->StringFromValue( clearance, true ) ) );
883
884 constraint = drcEngine->EvalRules( PHYSICAL_CLEARANCE_CONSTRAINT, pad, zone, layer, r );
885
886 if( constraint.m_Value.Min() > clearance )
887 {
888 clearance = constraint.m_Value.Min();
889
890 r->Report( "" );
891 r->Report( wxString::Format( _( "Overridden by larger physical clearance from %s;"
892 "clearance: %s." ),
893 EscapeHTML( constraint.GetName() ),
894 m_frame->StringFromValue( clearance, true ) ) );
895 }
896
897 if( !pad->FlashLayer( layer ) )
898 {
899 constraint = drcEngine->EvalRules( PHYSICAL_HOLE_CLEARANCE_CONSTRAINT, pad, zone,
900 layer, r );
901
902 if( constraint.m_Value.Min() > clearance )
903 {
904 clearance = constraint.m_Value.Min();
905
906 r->Report( "" );
907 r->Report( wxString::Format( _( "Overridden by larger physical hole clearance "
908 "from %s; clearance: %s." ),
909 EscapeHTML( constraint.GetName() ),
910 m_frame->StringFromValue( clearance, true ) ) );
911 }
912 }
913
914 if( compileError )
916
917 r->Report( "" );
918 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
919 m_frame->StringFromValue( clearance, true ) ) );
920 }
921 else
922 {
923 r->Report( "" );
924 r->Report( "" );
925 reportHeader( _( "Zone clearance resolution for:" ), a, b, layer, r );
926
927 if( compileError )
929
930 // Report a 0 clearance for solid connections
931 r->Report( "" );
932 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
933 m_frame->StringFromValue( 0, true ) ) );
934 }
935
936 r->Flush();
937 }
938 else if( copperIntersection.any() && !aFP && !bFP )
939 {
940 PCB_LAYER_ID layer = active;
941
942 if( !copperIntersection.test( layer ) )
943 layer = copperIntersection.Seq().front();
944
945 r = dialog->AddHTMLPage( m_frame->GetBoard()->GetLayerName( layer ) );
946 reportHeader( _( "Clearance resolution for:" ), a, b, layer, r );
947
948 if( ac && bc && ac->GetNetCode() > 0 && ac->GetNetCode() == bc->GetNetCode() )
949 {
950 // Same nets....
951 r->Report( _( "Items belong to the same net. Min clearance is 0." ) );
952 }
953 else
954 {
955 // Different nets (or one or both unconnected)....
956 constraint = drcEngine->EvalRules( CLEARANCE_CONSTRAINT, a, b, layer, r );
957 clearance = constraint.m_Value.Min();
958
959 if( compileError )
961
962 r->Report( "" );
963
964 if( constraint.IsNull() )
965 {
966 r->Report( _( "Min clearance is 0." ) );
967 }
968 else if( clearance < 0 )
969 {
970 r->Report( wxString::Format( _( "Resolved clearance: %s; clearance will not be "
971 "tested." ),
972 m_frame->StringFromValue( clearance, true ) ) );
973 }
974 else
975 {
976 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
977 m_frame->StringFromValue( clearance, true ) ) );
978 }
979 }
980
981 r->Flush();
982 }
983
984 if( ac && bc )
985 {
986 NETINFO_ITEM* refNet = ac->GetNet();
987 wxString coupledNet;
988 wxString dummy;
989
990 if( DRC_ENGINE::MatchDpSuffix( refNet->GetNetname(), coupledNet, dummy )
991 && bc->GetNetname() == coupledNet )
992 {
993 r = dialog->AddHTMLPage( _( "Diff Pair" ) );
994 reportHeader( _( "Diff-pair gap resolution for:" ), ac, bc, active, r );
995
996 constraint = drcEngine->EvalRules( DIFF_PAIR_GAP_CONSTRAINT, ac, bc, active, r );
997
998 r->Report( "" );
999 r->Report( wxString::Format( _( "Resolved gap constraints: min %s; opt %s; max %s." ),
1000 reportMin( m_frame, constraint ),
1001 reportOpt( m_frame, constraint ),
1002 reportMax( m_frame, constraint ) ) );
1003
1004 r->Report( "" );
1005 r->Report( "" );
1006 r->Report( "" );
1007 reportHeader( _( "Diff-pair max uncoupled length resolution for:" ), ac, bc,
1008 active, r );
1009
1010 if( !drcEngine->HasRulesForConstraintType( MAX_UNCOUPLED_CONSTRAINT ) )
1011 {
1012 r->Report( "" );
1013 r->Report( _( "No 'diff_pair_uncoupled' constraints defined." ) );
1014 }
1015 else
1016 {
1017 constraint = drcEngine->EvalRules( MAX_UNCOUPLED_CONSTRAINT, ac, bc, active, r );
1018
1019 r->Report( "" );
1020 r->Report( wxString::Format( _( "Resolved max uncoupled length: %s." ),
1021 reportMax( m_frame, constraint ) ) );
1022 }
1023 r->Flush();
1024 }
1025 }
1026
1027 auto isOnCorrespondingLayer=
1028 [&]( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer, wxString* aWarning )
1029 {
1030 if( aItem->IsOnLayer( aLayer ) )
1031 return true;
1032
1033 PCB_LAYER_ID correspondingMask = IsFrontLayer( aLayer ) ? F_Mask : B_Mask;
1034 PCB_LAYER_ID correspondingCopper = IsFrontLayer( aLayer ) ? F_Cu : B_Cu;
1035
1036 if( aItem->IsOnLayer( aLayer ) )
1037 return true;
1038
1039 if( aItem->IsOnLayer( correspondingMask ) )
1040 return true;
1041
1042 if( aItem->IsTented( correspondingMask ) && aItem->IsOnLayer( correspondingCopper ) )
1043 {
1044 *aWarning = wxString::Format( _( "Note: %s is tented; clearance will only be "
1045 "applied to holes." ),
1046 getItemDescription( aItem ) );
1047 return true;
1048 }
1049
1050 return false;
1051 };
1052
1053 for( PCB_LAYER_ID layer : { F_SilkS, B_SilkS } )
1054 {
1055 wxString warning;
1056
1057 if( ( a->IsOnLayer( layer ) && isOnCorrespondingLayer( b, layer, &warning ) )
1058 || ( b->IsOnLayer( layer ) && isOnCorrespondingLayer( a, layer, &warning ) ) )
1059 {
1060 r = dialog->AddHTMLPage( m_frame->GetBoard()->GetLayerName( layer ) );
1061 reportHeader( _( "Silkscreen clearance resolution for:" ), a, b, layer, r );
1062
1063 constraint = drcEngine->EvalRules( SILK_CLEARANCE_CONSTRAINT, a, b, layer, r );
1064 clearance = constraint.m_Value.Min();
1065
1066 if( compileError )
1067 reportCompileError( r );
1068
1069 r->Report( "" );
1070
1071 if( !warning.IsEmpty() )
1072 r->Report( warning );
1073
1074 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1075 m_frame->StringFromValue( clearance, true ) ) );
1076
1077 r->Flush();
1078 }
1079 }
1080
1081 for( PCB_LAYER_ID layer : { F_CrtYd, B_CrtYd } )
1082 {
1083 bool aCourtyard = aFP && !aFP->GetCourtyard( layer ).IsEmpty();
1084 bool bCourtyard = bFP && !bFP->GetCourtyard( layer ).IsEmpty();
1085
1086 if( aCourtyard && bCourtyard )
1087 {
1088 r = dialog->AddHTMLPage( m_frame->GetBoard()->GetLayerName( layer ) );
1089 reportHeader( _( "Courtyard clearance resolution for:" ), a, b, layer, r );
1090
1091 constraint = drcEngine->EvalRules( COURTYARD_CLEARANCE_CONSTRAINT, a, b, layer, r );
1092 clearance = constraint.m_Value.Min();
1093
1094 if( compileError )
1095 reportCompileError( r );
1096
1097 r->Report( "" );
1098 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1099 m_frame->StringFromValue( clearance, true ) ) );
1100
1101 r->Flush();
1102 }
1103 }
1104
1105 if( a->HasHole() || b->HasHole() )
1106 {
1108 bool pageAdded = false;
1109
1110 if( a->HasHole() && b->IsOnLayer( active ) && IsCopperLayer( active ) )
1111 layer = active;
1112 else if( b->HasHole() && a->IsOnLayer( active ) && IsCopperLayer( active ) )
1113 layer = active;
1114 else if( a->HasHole() && b->IsOnCopperLayer() )
1115 layer = b->GetLayer();
1116 else if( b->HasHole() && b->IsOnCopperLayer() )
1117 layer = a->GetLayer();
1118
1119 if( layer >= 0 )
1120 {
1121 if( !pageAdded )
1122 {
1123 r = dialog->AddHTMLPage( _( "Hole" ) );
1124 pageAdded = true;
1125 }
1126 else
1127 {
1128 r->Report( "" );
1129 r->Report( "" );
1130 r->Report( "" );
1131 }
1132
1133 reportHeader( _( "Hole clearance resolution for:" ), a, b, layer, r );
1134
1135 constraint = drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, a, b, layer, r );
1136 clearance = constraint.m_Value.Min();
1137
1138 if( compileError )
1139 reportCompileError( r );
1140
1141 r->Report( "" );
1142 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1143 m_frame->StringFromValue( clearance, true ) ) );
1144
1145 r->Flush();
1146 }
1147
1148 if( a->HasDrilledHole() || b->HasDrilledHole() )
1149 {
1150 if( !pageAdded )
1151 {
1152 r = dialog->AddHTMLPage( _( "Hole" ) );
1153 pageAdded = true;
1154 }
1155 else
1156 {
1157 r->Report( "" );
1158 r->Report( "" );
1159 r->Report( "" );
1160 }
1161
1162 reportHeader( _( "Hole-to-hole clearance resolution for:" ), a, b, r );
1163
1164 constraint = drcEngine->EvalRules( HOLE_TO_HOLE_CONSTRAINT, a, b, UNDEFINED_LAYER, r );
1165 clearance = constraint.m_Value.Min();
1166
1167 if( compileError )
1168 reportCompileError( r );
1169
1170 r->Report( "" );
1171 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1172 m_frame->StringFromValue( clearance, true ) ) );
1173
1174 r->Flush();
1175 }
1176 }
1177
1178 for( PCB_LAYER_ID edgeLayer : { Edge_Cuts, Margin } )
1179 {
1181
1182 if( a->IsOnLayer( edgeLayer ) && b->Type() != PCB_FOOTPRINT_T )
1183 {
1184 if( b->IsOnLayer( active ) && IsCopperLayer( active ) )
1185 layer = active;
1186 else if( IsCopperLayer( b->GetLayer() ) )
1187 layer = b->GetLayer();
1188 }
1189 else if( b->IsOnLayer( edgeLayer ) && a->Type() != PCB_FOOTPRINT_T )
1190 {
1191 if( a->IsOnLayer( active ) && IsCopperLayer( active ) )
1192 layer = active;
1193 else if( IsCopperLayer( a->GetLayer() ) )
1194 layer = a->GetLayer();
1195 }
1196
1197 if( layer >= 0 )
1198 {
1199 wxString layerName = m_frame->GetBoard()->GetLayerName( edgeLayer );
1200 r = dialog->AddHTMLPage( layerName + wxS( " " ) + _( "Clearance" ) );
1201 reportHeader( _( "Edge clearance resolution for:" ), a, b, layer, r );
1202
1203 constraint = drcEngine->EvalRules( EDGE_CLEARANCE_CONSTRAINT, a, b, layer, r );
1204 clearance = constraint.m_Value.Min();
1205
1206 if( compileError )
1207 reportCompileError( r );
1208
1209 r->Report( "" );
1210 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1211 m_frame->StringFromValue( clearance, true ) ) );
1212
1213 r->Flush();
1214 }
1215 }
1216
1217 r = dialog->AddHTMLPage( _( "Physical Clearances" ) );
1218
1219 auto reportPhysicalClearance =
1220 [&]( PCB_LAYER_ID aLayer )
1221 {
1222 reportHeader( _( "Physical clearance resolution for:" ), a, b, aLayer, r );
1223
1224 constraint = drcEngine->EvalRules( PHYSICAL_CLEARANCE_CONSTRAINT, a, b, aLayer, r );
1225 clearance = constraint.m_Value.Min();
1226
1227 if( compileError )
1228 {
1229 reportCompileError( r );
1230 }
1231 else if( !drcEngine->HasRulesForConstraintType( PHYSICAL_CLEARANCE_CONSTRAINT ) )
1232 {
1233 r->Report( "" );
1234 r->Report( _( "No 'physical_clearance' constraints defined." ) );
1235 }
1236 else
1237 {
1238 r->Report( "" );
1239 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1240 m_frame->StringFromValue( clearance, true ) ) );
1241 }
1242
1243 r->Report( "" );
1244 r->Report( "" );
1245 r->Report( "" );
1246 };
1247
1248 if( layerIntersection.any() )
1249 {
1250 PCB_LAYER_ID layer = active;
1251
1252 if( !layerIntersection.test( layer ) )
1253 layer = layerIntersection.Seq().front();
1254
1255 reportPhysicalClearance( layer );
1256 }
1257
1258 if( aFP && b->IsOnLayer( Edge_Cuts ) )
1259 {
1260 if( !aFP->GetCourtyard( F_CrtYd ).IsEmpty() )
1261 reportPhysicalClearance( F_CrtYd );
1262
1263 if( !aFP->GetCourtyard( B_CrtYd ).IsEmpty() )
1264 reportPhysicalClearance( B_CrtYd );
1265 }
1266 else if( bFP && a->IsOnLayer( Edge_Cuts ) )
1267 {
1268 if( !bFP->GetCourtyard( F_CrtYd ).IsEmpty() )
1269 reportPhysicalClearance( F_CrtYd );
1270
1271 if( !bFP->GetCourtyard( B_CrtYd ).IsEmpty() )
1272 reportPhysicalClearance( B_CrtYd );
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 // PADSTACKS TODO: once we have padstacks we'll need to run this per-layer....
1417 constraint = EVAL_RULES( HOLE_SIZE_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
1418
1419 if( compileError )
1420 reportCompileError( r );
1421
1422 r->Report( "" );
1423 r->Report( wxString::Format( _( "Resolved hole size constraints: min %s; opt %s; max %s." ),
1424 reportMin( m_frame, constraint ),
1425 reportOpt( m_frame, constraint ),
1426 reportMax( m_frame, constraint ) ) );
1427
1428 r->Flush();
1429 }
1430
1431 if( item->Type() == PCB_FIELD_T || item->Type() == PCB_TEXT_T || item->Type() == PCB_TEXTBOX_T )
1432 {
1433 r = dialog->AddHTMLPage( _( "Text Size" ) );
1434 reportHeader( _( "Text height resolution for:" ), item, r );
1435
1436 constraint = EVAL_RULES( TEXT_HEIGHT_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
1437
1438 if( compileError )
1439 reportCompileError( r );
1440
1441 r->Report( "" );
1442 r->Report( wxString::Format( _( "Resolved height constraints: min %s; opt %s; max %s." ),
1443 reportMin( m_frame, constraint ),
1444 reportOpt( m_frame, constraint ),
1445 reportMax( m_frame, constraint ) ) );
1446
1447 r->Report( "" );
1448 r->Report( "" );
1449 r->Report( "" );
1450 reportHeader( _( "Text thickness resolution for:" ), item, r );
1451
1452 constraint = EVAL_RULES( TEXT_THICKNESS_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
1453
1454 if( compileError )
1455 reportCompileError( r );
1456
1457 r->Report( "" );
1458 r->Report( wxString::Format( _( "Resolved thickness constraints: min %s; opt %s; max %s." ),
1459 reportMin( m_frame, constraint ),
1460 reportOpt( m_frame, constraint ),
1461 reportMax( m_frame, constraint ) ) );
1462
1463 r->Flush();
1464 }
1465
1466 r = dialog->AddHTMLPage( _( "Keepouts" ) );
1467 reportHeader( _( "Keepout resolution for:" ), item, r );
1468
1469 constraint = EVAL_RULES( DISALLOW_CONSTRAINT, item, nullptr, item->GetLayer(), r );
1470
1471 if( compileError )
1472 reportCompileError( r );
1473
1474 if( courtyardError )
1475 {
1476 r->Report( "" );
1477 r->Report( _( "Report may be incomplete: some footprint courtyards are malformed." )
1478 + wxS( "&nbsp;&nbsp;" )
1479 + wxS( "<a href='$DRC'>" ) + _( "Run DRC for a full analysis." )
1480 + wxS( "</a>" ) );
1481 }
1482
1483 r->Report( "" );
1484
1485 if( constraint.m_DisallowFlags )
1486 r->Report( _( "Item <b>disallowed</b> at current location." ) );
1487 else
1488 r->Report( _( "Item allowed at current location." ) );
1489
1490 r->Flush();
1491
1492 r = dialog->AddHTMLPage( _( "Assertions" ) );
1493 reportHeader( _( "Assertions for:" ), item, r );
1494
1495 if( compileError )
1496 reportCompileError( r );
1497
1498 if( courtyardError )
1499 {
1500 r->Report( "" );
1501 r->Report( _( "Report may be incomplete: some footprint courtyards are malformed." )
1502 + wxS( "&nbsp;&nbsp;" )
1503 + wxS( "<a href='$DRC'>" ) + _( "Run DRC for a full analysis." )
1504 + wxS( "</a>" ) );
1505 }
1506
1507 drcEngine->ProcessAssertions( item, []( const DRC_CONSTRAINT* c ){}, r );
1508 r->Flush();
1509
1510 dialog->Raise();
1511 dialog->Show( true );
1512 return 0;
1513}
1514
1515
1517{
1518 wxCHECK( m_frame, 0 );
1519
1521
1522 wxCHECK( selTool, 0 );
1523
1524 const PCB_SELECTION& selection = selTool->RequestSelection(
1525 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
1526 {
1527 // Iterate from the back so we don't have to worry about removals.
1528 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
1529 {
1530 BOARD_ITEM* item = aCollector[ i ];
1531
1532 if( !dynamic_cast<FOOTPRINT*>( item ) )
1533 aCollector.Remove( item );
1534 }
1535 },
1536 false /* ignore locked flag */ );
1537
1538 if( selection.Size() == 1 )
1539 DiffFootprint( static_cast<FOOTPRINT*>( selection.GetItem( 0 ) ) );
1540 else
1541 m_frame->ShowInfoBarError( _( "Select a footprint to diff with its library equivalent." ) );
1542
1543 return 0;
1544}
1545
1546
1548{
1549 wxCHECK( m_frame, 0 );
1550
1552
1553 wxCHECK( selTool, 0 );
1554
1555 const PCB_SELECTION& selection = selTool->GetSelection();
1556
1557 if( selection.Size() != 1 || selection.Front()->Type() != PCB_FOOTPRINT_T )
1558 {
1559 m_frame->ShowInfoBarError( _( "Select a footprint for a footprint associations report." ) );
1560 return 0;
1561 }
1562
1564
1565 dlg.ShowModal();
1566
1567 return 0;
1568}
1569
1570
1572{
1574
1575 wxCHECK( dialog, /* void */ );
1576
1577 dialog->DeleteAllPages();
1578
1579 LIB_ID fpID = aFootprint->GetFPID();
1580 wxString libName = fpID.GetLibNickname();
1581 wxString fpName = fpID.GetLibItemName();
1582 WX_HTML_REPORT_BOX* r = nullptr;
1583
1584 r = dialog->AddHTMLPage( _( "Summary" ) );
1585
1586 r->Report( wxS( "<h7>" ) + _( "Board vs library diff for:" ) + wxS( "</h7>" ) );
1587 r->Report( wxS( "<ul><li>" ) + EscapeHTML( getItemDescription( aFootprint ) ) + wxS( "</li>" )
1588 + wxS( "<li>" ) + _( "Library: " ) + EscapeHTML( libName ) + wxS( "</li>" )
1589 + wxS( "<li>" ) + _( "Library item: " ) + EscapeHTML( fpName ) + wxS( "</li></ul>" ) );
1590
1591 r->Report( "" );
1592
1593 PROJECT* project = aFootprint->GetBoard()->GetProject();
1595 const LIB_TABLE_ROW* libTableRow = nullptr;
1596
1597 try
1598 {
1599 libTableRow = libTable->FindRow( libName );
1600 }
1601 catch( const IO_ERROR& )
1602 {
1603 }
1604
1605 if( !libTableRow )
1606 {
1607 r->Report( _( "The library is not included in the current configuration." )
1608 + wxS( "&nbsp;&nbsp;&nbsp" )
1609 + wxS( "<a href='$CONFIG'>" ) + _( "Manage Footprint Libraries" )
1610 + wxS( "</a>" ) );
1611
1612 }
1613 else if( !libTable->HasLibrary( libName, true ) )
1614 {
1615 r->Report( _( "The library is not enabled in the current configuration." )
1616 + wxS( "&nbsp;&nbsp;&nbsp" )
1617 + wxS( "<a href='$CONFIG'>" ) + _( "Manage Footprint Libraries" )
1618 + wxS( "</a>" ) );
1619
1620 }
1621 else
1622 {
1623 std::shared_ptr<FOOTPRINT> libFootprint;
1624
1625 try
1626 {
1627 libFootprint.reset( libTable->FootprintLoad( libName, fpName, true ) );
1628 }
1629 catch( const IO_ERROR& )
1630 {
1631 }
1632
1633 if( !libFootprint )
1634 {
1635 r->Report( wxString::Format( _( "The library no longer contains the item %s." ),
1636 fpName) );
1637 }
1638 else
1639 {
1640 if( !aFootprint->FootprintNeedsUpdate( libFootprint.get(), 0, r ) )
1641 r->Report( _( "No relevant differences detected." ) );
1642
1643 wxPanel* panel = dialog->AddBlankPage( _( "Visual" ) );
1645
1646 diff->DisplayDiff( aFootprint, libFootprint );
1647 }
1648 }
1649
1650 r->Flush();
1651
1652 dialog->Raise();
1653 dialog->Show( true );
1654}
1655
1656
1658{
1659 wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
1660
1661 FOOTPRINT_DIFF_WIDGET* diffWidget = new FOOTPRINT_DIFF_WIDGET( aParentPanel, m_frame->Kiway() );
1662
1663 sizer->Add( diffWidget, 1, wxEXPAND | wxALL, 5 );
1664 aParentPanel->SetSizer( sizer );
1665 aParentPanel->Layout();
1666
1667 return diffWidget;
1668}
1669
1670
1672{
1673 BOARD_ITEM* item = aEvent.Parameter<BOARD_ITEM*>();
1674
1675 m_frame->m_probingSchToPcb = true; // recursion guard
1676 {
1678
1679 if( item )
1681 }
1682 m_frame->m_probingSchToPcb = false;
1683
1684 bool request3DviewRedraw = frame()->GetPcbNewSettings()->m_Display.m_Live3DRefresh;
1685
1686 if( item && item->Type() != PCB_FOOTPRINT_T )
1687 request3DviewRedraw = false;
1688
1689 // Update 3D viewer highlighting
1690 if( request3DviewRedraw )
1691 m_frame->Update3DView( false, true );
1692
1693 return 0;
1694}
1695
1696
1697 bool BOARD_INSPECTION_TOOL::highlightNet( const VECTOR2D& aPosition, bool aUseSelection )
1698{
1699 BOARD* board = static_cast<BOARD*>( m_toolMgr->GetModel() );
1702
1703 int net = -1;
1704 bool enableHighlight = false;
1705
1706 if( aUseSelection )
1707 {
1708 const PCB_SELECTION& selection = selectionTool->GetSelection();
1709 std::set<int> netcodes;
1710
1711 for( EDA_ITEM* item : selection )
1712 {
1713 if( BOARD_CONNECTED_ITEM* ci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
1714 netcodes.insert( ci->GetNetCode() );
1715 }
1716
1717 enableHighlight = !netcodes.empty();
1718
1719 if( enableHighlight && netcodes.size() > 1 )
1720 {
1721 // If we are doing a multi-highlight, cross-probing back and other stuff is not
1722 // yet supported
1723 settings->SetHighlight( netcodes );
1725
1726 for( int multiNet : netcodes )
1727 board->SetHighLightNet( multiNet, true );
1728
1729 board->HighLightON();
1731 m_currentlyHighlighted = netcodes;
1732 return true;
1733 }
1734 else if( enableHighlight )
1735 {
1736 net = *netcodes.begin();
1737 }
1738 }
1739
1740 // If we didn't get a net to highlight from the selection, use the cursor
1741 if( net < 0 )
1742 {
1744 guide.SetIgnoreZoneFills( false );
1745
1746 PCB_LAYER_ID activeLayer = static_cast<PCB_LAYER_ID>( view()->GetTopLayer() );
1747 guide.SetPreferredLayer( activeLayer );
1748
1749 GENERAL_COLLECTOR collector;
1750 collector.Collect( board, { PCB_PAD_T, PCB_VIA_T, PCB_TRACE_T, PCB_ARC_T, PCB_SHAPE_T }, aPosition,
1751 guide );
1752
1753 if( collector.GetCount() == 0 )
1754 collector.Collect( board, { PCB_ZONE_T }, aPosition, guide );
1755
1756 // Apply the active selection filter, except we want to allow picking locked items for
1757 // highlighting even if the user has disabled them for selection
1758 PCB_SELECTION_FILTER_OPTIONS& filter = selectionTool->GetFilter();
1759
1760 bool saved = filter.lockedItems;
1761 filter.lockedItems = true;
1762
1763 selectionTool->FilterCollectedItems( collector, true );
1764
1765 filter.lockedItems = saved;
1766
1767 // Clear the previous highlight
1768 //m_frame->SendMessageToEESCHEMA( nullptr );
1769
1770 bool highContrast = settings->GetHighContrast();
1771 PCB_LAYER_ID contrastLayer = settings->GetPrimaryHighContrastLayer();
1772
1773 for( int i = collector.GetCount() - 1; i >= 0; i-- )
1774 {
1775 LSET itemLayers = collector[i]->GetLayerSet();
1776
1777 if( ( itemLayers & LSET::AllCuMask() ).none() ||
1778 ( highContrast && !itemLayers.Contains( contrastLayer ) ) )
1779 {
1780 collector.Remove( i );
1781 continue;
1782 }
1783 }
1784
1785 enableHighlight = ( collector.GetCount() > 0 );
1786
1787 // Obtain net code for the clicked item
1788 if( enableHighlight )
1789 {
1790 BOARD_CONNECTED_ITEM* targetItem = static_cast<BOARD_CONNECTED_ITEM*>( collector[0] );
1791
1792 if( targetItem->Type() == PCB_PAD_T )
1793 m_frame->SendCrossProbeItem( targetItem );
1794
1795 net = targetItem->GetNetCode();
1796 }
1797 }
1798
1799 const std::set<int>& netcodes = settings->GetHighlightNetCodes();
1800
1801 // Toggle highlight when the same net was picked
1802 if( !aUseSelection && netcodes.size() == 1 && netcodes.contains( net ) )
1803 enableHighlight = !settings->IsHighlightEnabled();
1804
1805 if( enableHighlight != settings->IsHighlightEnabled() || !netcodes.count( net ) )
1806 {
1807 if( !netcodes.empty() )
1808 m_lastHighlighted = netcodes;
1809
1810 settings->SetHighlight( enableHighlight, net );
1811 m_toolMgr->GetView()->UpdateAllLayersColor();
1812 }
1813
1814 // Store the highlighted netcode in the current board (for dialogs for instance)
1815 if( enableHighlight && net >= 0 )
1816 {
1817 m_currentlyHighlighted = netcodes;
1818 board->SetHighLightNet( net );
1819 board->HighLightON();
1820
1821 NETINFO_ITEM* netinfo = board->FindNet( net );
1822
1823 if( netinfo )
1824 {
1825 std::vector<MSG_PANEL_ITEM> items;
1826 netinfo->GetMsgPanelInfo( m_frame, items );
1827 m_frame->SetMsgPanel( items );
1828 m_frame->SendCrossProbeNetName( netinfo->GetNetname() );
1829 }
1830 }
1831 else
1832 {
1833 m_currentlyHighlighted.clear();
1834 board->ResetNetHighLight();
1835 m_frame->SetMsgPanel( board );
1836 m_frame->SendCrossProbeNetName( "" );
1837 }
1838
1839 return true;
1840}
1841
1842
1844{
1845 int netcode = aEvent.Parameter<int>();
1847 const std::set<int>& highlighted = settings->GetHighlightNetCodes();
1848
1849 if( netcode > 0 )
1850 {
1851 m_lastHighlighted = highlighted;
1852 settings->SetHighlight( true, netcode );
1854 m_currentlyHighlighted.clear();
1855 m_currentlyHighlighted.insert( netcode );
1856 }
1857 else if( aEvent.IsAction( &PCB_ACTIONS::highlightNetSelection ) )
1858 {
1859 // Highlight selection (cursor position will be ignored)
1860 highlightNet( getViewControls()->GetMousePosition(), true );
1861 }
1862 else if( aEvent.IsAction( &PCB_ACTIONS::toggleLastNetHighlight ) )
1863 {
1864 std::set<int> temp = highlighted;
1865 settings->SetHighlight( m_lastHighlighted );
1868 m_lastHighlighted = std::move( temp );
1869 }
1870 else if( aEvent.IsAction( &PCB_ACTIONS::toggleNetHighlight ) )
1871 {
1872 bool turnOn = highlighted.empty() && !m_currentlyHighlighted.empty();
1873 settings->SetHighlight( m_currentlyHighlighted, turnOn );
1875 }
1876 else // Highlight the net belonging to the item under the cursor
1877 {
1878 highlightNet( getViewControls()->GetMousePosition(), false );
1879 }
1880
1881 return 0;
1882}
1883
1884
1886{
1887 BOARD* board = static_cast<BOARD*>( m_toolMgr->GetModel() );
1889
1890 m_currentlyHighlighted.clear();
1891 m_lastHighlighted.clear();
1892
1894 settings->SetHighlight( false );
1898 return 0;
1899}
1900
1901
1903{
1905 BOARD* board = getModel<BOARD>();
1906
1907 // Deactivate other tools; particularly important if another PICKER is currently running
1908 Activate();
1909
1910 picker->SetCursor( KICURSOR::BULLSEYE );
1911
1912 picker->SetClickHandler(
1913 [this, board]( const VECTOR2D& pt ) -> bool
1914 {
1916
1920
1921 PCB_SELECTION& selection = selectionTool->GetSelection();
1922
1923 if( selection.Empty() )
1924 {
1927 selection = selectionTool->GetSelection();
1928 }
1929
1930 if( selection.Empty() )
1931 {
1932 // Clear the previous local ratsnest if we click off all items
1933 for( FOOTPRINT* fp : board->Footprints() )
1934 {
1935 for( PAD* pad : fp->Pads() )
1936 pad->SetLocalRatsnestVisible( displayOptions().m_ShowGlobalRatsnest );
1937 }
1938 }
1939 else
1940 {
1941 for( EDA_ITEM* item : selection )
1942 {
1943 if( PAD* pad = dyn_cast<PAD*>( item) )
1944 {
1945 pad->SetLocalRatsnestVisible( !pad->GetLocalRatsnestVisible() );
1946 }
1947 else if( FOOTPRINT* fp = dyn_cast<FOOTPRINT*>( item) )
1948 {
1949 if( !fp->Pads().empty() )
1950 {
1951 bool enable = !fp->Pads()[0]->GetLocalRatsnestVisible();
1952
1953 for( PAD* childPad : fp->Pads() )
1954 childPad->SetLocalRatsnestVisible( enable );
1955 }
1956 }
1957 }
1958 }
1959
1961
1962 return true;
1963 } );
1964
1965 picker->SetFinalizeHandler(
1966 [this, board]( int aCondition )
1967 {
1968 if( aCondition != PCB_PICKER_TOOL::END_ACTIVATE )
1969 {
1970 for( FOOTPRINT* fp : board->Footprints() )
1971 {
1972 for( PAD* pad : fp->Pads() )
1973 pad->SetLocalRatsnestVisible( displayOptions().m_ShowGlobalRatsnest );
1974 }
1975 }
1976 } );
1977
1979
1980 return 0;
1981}
1982
1983
1985{
1986 VECTOR2I delta = aEvent.Parameter<VECTOR2I>();
1987
1988 if( delta == VECTOR2I() )
1989 {
1990 // We can delete the existing map to force a recalculation
1991 delete m_dynamicData;
1992 m_dynamicData = nullptr;
1993 }
1994
1995 auto selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1996 auto& selection = selectionTool->GetSelection();
1997 auto connectivity = getModel<BOARD>()->GetConnectivity();
1998
1999 if( selection.Empty() )
2000 {
2001 connectivity->ClearLocalRatsnest();
2002 delete m_dynamicData;
2003 m_dynamicData = nullptr;
2004 }
2005 else
2006 {
2008 }
2009
2010 return 0;
2011}
2012
2013
2015{
2016 getModel<BOARD>()->GetConnectivity()->ClearLocalRatsnest();
2017 delete m_dynamicData;
2018 m_dynamicData = nullptr;
2019
2020 return 0;
2021}
2022
2023
2025{
2027 SELECTION& selection = selectionTool->GetSelection();
2028 std::shared_ptr<CONNECTIVITY_DATA> connectivity = board()->GetConnectivity();
2029 std::vector<BOARD_ITEM*> items;
2030 std::deque<EDA_ITEM*> queued_items( selection.begin(), selection.end() );
2031
2032 for( std::size_t i = 0; i < queued_items.size(); ++i )
2033 {
2034 if( !queued_items[i]->IsBOARD_ITEM() )
2035 continue;
2036
2037 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( queued_items[i] );
2038
2039 wxCHECK2( item, continue );
2040
2041 if( item->Type() == PCB_FOOTPRINT_T )
2042 {
2043 for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
2044 {
2045 if( pad->GetLocalRatsnestVisible() || displayOptions().m_ShowModuleRatsnest )
2046 items.push_back( pad );
2047 }
2048 }
2049 else if( item->Type() == PCB_GROUP_T || item->Type() == PCB_GENERATOR_T )
2050 {
2051 item->RunOnDescendants( [ &queued_items ]( BOARD_ITEM *aItem )
2052 {
2053 queued_items.push_back( aItem );
2054 } );
2055 }
2056 else if( BOARD_CONNECTED_ITEM* boardItem = dyn_cast<BOARD_CONNECTED_ITEM*>( item ) )
2057 {
2058 if( boardItem->GetLocalRatsnestVisible() || displayOptions().m_ShowModuleRatsnest )
2059 items.push_back( boardItem );
2060 }
2061 }
2062
2063 if( items.empty() || std::none_of( items.begin(), items.end(),
2064 []( const BOARD_ITEM* aItem )
2065 {
2066 return( aItem->Type() == PCB_TRACE_T
2067 || aItem->Type() == PCB_PAD_T
2068 || aItem->Type() == PCB_ARC_T
2069 || aItem->Type() == PCB_ZONE_T
2070 || aItem->Type() == PCB_FOOTPRINT_T
2071 || aItem->Type() == PCB_VIA_T
2072 || aItem->Type() == PCB_SHAPE_T );
2073 } ) )
2074 {
2075 return;
2076 }
2077
2078 if( !m_dynamicData )
2079 {
2080 m_dynamicData = new CONNECTIVITY_DATA( board()->GetConnectivity(), items, true );
2081 connectivity->BlockRatsnestItems( items );
2082 }
2083 else
2084 {
2085 m_dynamicData->Move( aDelta );
2086 }
2087
2088 connectivity->ComputeLocalRatsnest( items, m_dynamicData );
2089}
2090
2091
2093{
2094 doHideRatsnestNet( aEvent.Parameter<int>(), true );
2095 return 0;
2096}
2097
2098
2100{
2101 doHideRatsnestNet( aEvent.Parameter<int>(), false );
2102 return 0;
2103}
2104
2105
2106void BOARD_INSPECTION_TOOL::doHideRatsnestNet( int aNetCode, bool aHide )
2107{
2110
2112 SELECTION& selection = selectionTool->GetSelection();
2113
2114 if( aNetCode <= 0 && !selection.Empty() )
2115 {
2116 for( EDA_ITEM* item : selection )
2117 {
2118 if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
2119 {
2120 if( bci->GetNetCode() > 0 )
2121 doHideRatsnestNet( bci->GetNetCode(), aHide );
2122 }
2123 }
2124
2125 return;
2126 }
2127
2128 if( aHide )
2129 rs->GetHiddenNets().insert( aNetCode );
2130 else
2131 rs->GetHiddenNets().erase( aNetCode );
2132
2134 {
2137
2138 m_frame->GetAppearancePanel()->OnNetVisibilityChanged( aNetCode, !aHide );
2139 }
2140}
2141
2142
2144{
2148
2154
2161
2164}
#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:195
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: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:80
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:238
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:320
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:47
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:258
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 bool HasDrilledHole() const
Definition: board_item.h:161
virtual bool IsOnCopperLayer() const
Definition: board_item.h:151
virtual void RunOnDescendants(const std::function< void(BOARD_ITEM *)> &aFunction, int aDepth=0) const
Invoke a function on all descendants.
Definition: board_item.h:213
virtual bool HasHole() const
Definition: board_item.h:156
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:290
void SetHighLightNet(int aNetCode, bool aMulti=false)
Select the netcode to be highlighted.
Definition: board.cpp:2724
BOARD_ITEM * GetItem(const KIID &aID) const
Definition: board.cpp:1406
const ZONES & Zones() const
Definition: board.h:335
void ResetNetHighLight()
Reset all high light data to the init state.
Definition: board.cpp:2715
const FOOTPRINTS & Footprints() const
Definition: board.h:331
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:577
PROJECT * GetProject() const
Definition: board.h:491
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:890
void HighLightON(bool aValue=true)
Enable or disable net highlighting.
Definition: board.cpp:2737
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition: board.h:475
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:159
int m_DisallowFlags
Definition: drc_rule.h:190
ZONE_CONNECTION m_ZoneConnection
Definition: drc_rule.h:191
MINOPTMAX< int > m_Value
Definition: drc_rule.h:189
bool IsNull() const
Definition: drc_rule.h:146
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:89
virtual wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const
Return a user-visible description string of this item.
Definition: eda_item.cpp:111
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:130
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:2964
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:2975
void DisplayDiff(FOOTPRINT *aBoardFootprint, std::shared_ptr< FOOTPRINT > &aLibFootprint)
Set the currently displayed symbol.
ZONES & Zones()
Definition: footprint.h:211
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:205
const LIB_ID & GetFPID() const
Definition: footprint.h:247
void BuildCourtyardCaches(OUTLINE_ERROR_HANDLER *aErrorHandler=nullptr)
Build complex polygons of the courtyard areas from graphic items on the courtyard layers.
Definition: footprint.cpp:2863
const SHAPE_POLY_SET & GetCourtyard(PCB_LAYER_ID aLayer) const
Used in DRC to test the courtyard area (a complex polygon).
Definition: footprint.cpp:2840
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:319
void SetIgnoreZoneFills(bool ignore)
Definition: collectors.h:467
void SetPreferredLayer(PCB_LAYER_ID aLayer)
Definition: collectors.h:384
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:202
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:482
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:78
std::set< int > & GetHiddenNets()
Definition: pcb_painter.h:131
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:100
void UpdateAllLayersColor()
Apply the new coloring scheme to all layers.
Definition: view.cpp:804
virtual int GetTopLayer() const
Definition: view.cpp:862
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:221
void MarkTargetDirty(int aTarget)
Set or clear target 'dirty' flag.
Definition: view.h:625
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:36
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:676
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:410
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
Definition: lset.h:60
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
Gets the consolidated name of this netclass (which may be an aggregate)
Definition: netclass.cpp:151
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:307
PAD_ATTRIB GetAttribute() const
Definition: pad.h:442
static TOOL_ACTION highlightItem
Definition: pcb_actions.h:559
static TOOL_ACTION toggleNetHighlight
Definition: pcb_actions.h:557
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:555
static TOOL_ACTION hideNetInRatsnest
Definition: pcb_actions.h:562
static TOOL_ACTION hideLocalRatsnest
Definition: pcb_actions.h:565
static TOOL_ACTION showNetInRatsnest
Definition: pcb_actions.h:563
static TOOL_ACTION cleanupTracksAndVias
Definition: pcb_actions.h:423
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:68
static TOOL_ACTION toggleLastNetHighlight
Definition: pcb_actions.h:556
static TOOL_ACTION inspectConstraints
Definition: pcb_actions.h:549
static TOOL_ACTION clearHighlight
Definition: pcb_actions.h:554
static TOOL_ACTION inspectClearance
Definition: pcb_actions.h:548
static TOOL_ACTION updateLocalRatsnest
Definition: pcb_actions.h:566
static TOOL_ACTION diffFootprint
Definition: pcb_actions.h:550
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:551
static TOOL_ACTION highlightNetSelection
Definition: pcb_actions.h:558
static TOOL_ACTION boardStatistics
Definition: pcb_actions.h:544
static TOOL_ACTION localRatsnestTool
Definition: pcb_actions.h:564
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:52
std::unordered_set< BOARD_ITEM * > & GetItems()
Definition: pcb_group.h:69
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:73
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:104
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:64
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:72
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:75
ITER begin()
Definition: selection.h:74
EDA_ITEM * Front() const
Definition: selection.h:172
int Size() const
Returns the number of selected parts.
Definition: selection.h:116
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:110
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
Represent a single user action.
Definition: tool_action.h:269
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:218
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:82
T Parameter() const
Return a parameter assigned to the event.
Definition: tool_event.h:460
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:398
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:391
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:44
void RegisterSubMenu(std::shared_ptr< ACTION_MENU > aSubMenu)
Store a submenu of this menu model.
Definition: tool_menu.cpp:50
wxString StringFromValue(double aValue, bool aAddUnitLabel=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
Converts aValue in internal units into a united string.
A slimmed down version of WX_HTML_REPORT_PANEL.
REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED) override
Report a string with a given severity.
void Flush()
Build the HTML messages page.
Handle a list of polygons defining a copper zone.
Definition: zone.h:73
std::optional< int > GetLocalClearance() const override
Definition: zone.cpp:528
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Test to see if this object is on the given layer.
Definition: zone.cpp:375
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: zone.h:130
@ 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_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:67
@ DIFF_PAIR_GAP_CONSTRAINT
Definition: drc_rule.h:70
@ DISALLOW_CONSTRAINT
Definition: drc_rule.h:66
@ 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:75
@ CLEARANCE_CONSTRAINT
Definition: drc_rule.h:49
@ THERMAL_SPOKE_WIDTH_CONSTRAINT
Definition: drc_rule.h:64
@ CONNECTION_WIDTH_CONSTRAINT
Definition: drc_rule.h:77
@ THERMAL_RELIEF_GAP_CONSTRAINT
Definition: drc_rule.h:63
@ MAX_UNCOUPLED_CONSTRAINT
Definition: drc_rule.h:71
@ HOLE_CLEARANCE_CONSTRAINT
Definition: drc_rule.h:51
@ TRACK_ANGLE_CONSTRAINT
Definition: drc_rule.h:78
@ HOLE_SIZE_CONSTRAINT
Definition: drc_rule.h:54
@ TEXT_HEIGHT_CONSTRAINT
Definition: drc_rule.h:57
@ PHYSICAL_CLEARANCE_CONSTRAINT
Definition: drc_rule.h:74
@ 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:622
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:532
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:50
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Class to handle a set of BOARD_ITEMs.
std::function< void(const VECTOR2I &, GENERAL_COLLECTOR &, PCB_SELECTION_TOOL *)> CLIENT_SELECTION_FILTER
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 ...
constexpr 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:691