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