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
25
26#include <bitmaps.h>
27#include <collectors.h>
28#include <footprint.h>
29#include <pcb_group.h>
30#include <tool/tool_manager.h>
33#include <tools/edit_tool.h>
34#include <tools/drc_tool.h>
35#include <pcb_painter.h>
37#include <drc/drc_engine.h>
42#include <dialogs/dialog_drc.h>
43#include <kiplatform/ui.h>
44#include <status_popup.h>
45#include <string_utils.h>
47#include <pcb_painter.h>
48#include <pcb_shape.h>
52#include <wx/choice.h>
53#include <wx/sizer.h>
54#include <wx/stattext.h>
55#include <drc/drc_item.h>
56#include <pad.h>
57#include <pcb_track.h>
58#include <project_pcb.h>
59#include <view/view_controls.h>
60
61
63 PCB_TOOL_BASE( "pcbnew.InspectionTool" ),
64 m_frame( nullptr )
65{
66 m_dynamicData = nullptr;
67}
68
69
71{
72public:
85
86private:
87 ACTION_MENU* create() const override
88 {
89 return new NET_CONTEXT_MENU();
90 }
91};
92
93
95{
96 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
97
98 std::shared_ptr<NET_CONTEXT_MENU> netSubMenu = std::make_shared<NET_CONTEXT_MENU>();
99 netSubMenu->SetTool( this );
100
101 // Only show the net menu if all items in the selection are connectable
102 auto showNetMenuFunc =
103 []( const SELECTION& aSelection )
104 {
105 if( aSelection.Empty() )
106 return false;
107
108 for( const EDA_ITEM* item : aSelection )
109 {
110 switch( item->Type() )
111 {
112 case PCB_TRACE_T:
113 case PCB_ARC_T:
114 case PCB_VIA_T:
115 case PCB_PAD_T:
116 case PCB_ZONE_T:
117 continue;
118
119 case PCB_SHAPE_T:
120 {
121 if( !static_cast<const PCB_SHAPE*>( item )->IsOnCopperLayer() )
122 return false;
123 else
124 continue;
125 }
126
127 default:
128 return false;
129 }
130 }
131
132 return true;
133 };
134
135 CONDITIONAL_MENU& menu = selectionTool->GetToolMenu().GetMenu();
136
137 selectionTool->GetToolMenu().RegisterSubMenu( netSubMenu );
138
139 menu.AddMenu( netSubMenu.get(), showNetMenuFunc, 100 );
140
141 return true;
142}
143
144
149
150
152{
154 dialog.ShowModal();
155 return 0;
156}
157
158
159std::unique_ptr<DRC_ENGINE> BOARD_INSPECTION_TOOL::makeDRCEngine( bool* aCompileError,
160 bool* aCourtyardError )
161{
162 auto engine = std::make_unique<DRC_ENGINE>( m_frame->GetBoard(),
163 &m_frame->GetBoard()->GetDesignSettings() );
164
165 try
166 {
167 engine->InitEngine( m_frame->GetDesignRulesPath() );
168 }
169 catch( PARSE_ERROR& )
170 {
171 if( aCompileError )
172 *aCompileError = true;
173 }
174
175 for( ZONE* zone : m_frame->GetBoard()->Zones() )
176 zone->CacheBoundingBox();
177
178 for( FOOTPRINT* footprint : m_frame->GetBoard()->Footprints() )
179 {
180 for( ZONE* zone : footprint->Zones() )
181 zone->CacheBoundingBox();
182
183 footprint->BuildCourtyardCaches();
184
185 if( aCourtyardError && ( footprint->GetFlags() & MALFORMED_COURTYARDS ) != 0 )
186 *aCourtyardError = true;
187 }
188
189 return engine;
190}
191
192
193bool isNPTHPad( BOARD_ITEM* aItem )
194{
195 return aItem->Type() == PCB_PAD_T
196 && static_cast<PAD*>( aItem )->GetAttribute() == PAD_ATTRIB::NPTH;
197}
198
199
201{
202 // Null items have no description
203 if( !aItem )
204 return wxString();
205
206 wxString msg = aItem->GetItemDescription( m_frame, true );
207
208 if( aItem->IsConnected() && !isNPTHPad( aItem ) )
209 {
210 BOARD_CONNECTED_ITEM* cItem = static_cast<BOARD_CONNECTED_ITEM*>( aItem );
211
212 msg += wxS( " " )
213 + wxString::Format( _( "[netclass %s]" ),
215 }
216
217 return msg;
218};
219
220
222 const VECTOR2I& aPos )
223{
224 std::vector<BOARD_ITEM*> toAdd;
225
226 for( int i = 0; i < aCollector.GetCount(); ++i )
227 {
228 if( aCollector[i]->Type() == PCB_GROUP_T )
229 {
230 PCB_GROUP* group = static_cast<PCB_GROUP*>( aCollector[i] );
231
232 group->RunOnChildren(
233 [&]( BOARD_ITEM* child )
234 {
235 if( child->Type() == PCB_GROUP_T )
236 return;
237
238 if( !child->HitTest( aPos ) )
239 return;
240
241 toAdd.push_back( child );
242
243 if( child->Type() == PCB_FOOTPRINT_T )
244 {
245 for( PAD* pad : static_cast<FOOTPRINT*>( child )->Pads() )
246 {
247 if( pad->HitTest( aPos ) )
248 toAdd.push_back( pad );
249 }
250 }
251 },
253 }
254 }
255
256 for( BOARD_ITEM* item : toAdd )
257 aCollector.Append( item );
258
259 bool hasPadOrTrack = false;
260
261 for( int i = 0; i < aCollector.GetCount(); ++i )
262 {
263 KICAD_T type = aCollector[i]->Type();
264
265 if( type == PCB_PAD_T || type == PCB_VIA_T || type == PCB_TRACE_T
266 || type == PCB_ARC_T || type == PCB_ZONE_T )
267 {
268 hasPadOrTrack = true;
269 break;
270 }
271 }
272
273 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
274 {
275 BOARD_ITEM* item = aCollector[i];
276
277 if( hasPadOrTrack && item->Type() == PCB_FOOTPRINT_T )
278 {
279 aCollector.Remove( i );
280 continue;
281 }
282
283 if( item->Type() == PCB_GROUP_T )
284 aCollector.Remove( i );
285 }
286}
287
288
290 const wxString& aPrompt,
291 const std::vector<KICAD_T>& aTypes,
292 BOARD_ITEM* aLockedHighlight )
293{
294 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
295 PCB_PICKER_TOOL* picker = m_toolMgr->GetTool<PCB_PICKER_TOOL>();
296 STATUS_TEXT_POPUP statusPopup( m_frame );
297 BOARD_ITEM* pickedItem = nullptr;
298 BOARD_ITEM* highlightedItem = nullptr;
299 bool done = false;
300
301 statusPopup.SetText( aPrompt );
302
303 picker->SetCursor( KICURSOR::BULLSEYE );
304 picker->SetSnapping( false );
305 picker->ClearHandlers();
306
307 picker->SetClickHandler(
308 [&]( const VECTOR2D& aPoint ) -> bool
309 {
311
312 GENERAL_COLLECTORS_GUIDE guide = m_frame->GetCollectorsGuide();
313 GENERAL_COLLECTOR collector;
314
315 collector.Collect( m_frame->GetBoard(), aTypes, aPoint, guide );
316
317 for( int i = collector.GetCount() - 1; i >= 0; --i )
318 {
319 if( !selTool->Selectable( collector[i] ) )
320 collector.Remove( i );
321 }
322
323 filterCollectorForInspection( collector, aPoint );
324
325 if( collector.GetCount() > 1 )
326 selTool->GuessSelectionCandidates( collector, aPoint );
327
328 if( collector.GetCount() == 0 )
329 return true;
330
331 pickedItem = collector[0];
332 statusPopup.Hide();
333
334 return false;
335 } );
336
337 picker->SetMotionHandler(
338 [&]( const VECTOR2D& aPos )
339 {
340 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
341
342 GENERAL_COLLECTORS_GUIDE guide = m_frame->GetCollectorsGuide();
343 GENERAL_COLLECTOR collector;
344
345 collector.Collect( m_frame->GetBoard(), aTypes, aPos, guide );
346
347 for( int i = collector.GetCount() - 1; i >= 0; --i )
348 {
349 if( !selTool->Selectable( collector[i] ) )
350 collector.Remove( i );
351 }
352
353 filterCollectorForInspection( collector, aPos );
354
355 if( collector.GetCount() > 1 )
356 selTool->GuessSelectionCandidates( collector, aPos );
357
358 BOARD_ITEM* item = collector.GetCount() >= 1 ? collector[0] : nullptr;
359
360 if( highlightedItem != item )
361 {
362 if( highlightedItem && highlightedItem != aLockedHighlight )
363 selTool->UnbrightenItem( highlightedItem );
364
365 highlightedItem = item;
366
367 if( highlightedItem && highlightedItem != aLockedHighlight )
368 selTool->BrightenItem( highlightedItem );
369 }
370 } );
371
372 picker->SetCancelHandler(
373 [&]()
374 {
375 if( highlightedItem && highlightedItem != aLockedHighlight )
376 selTool->UnbrightenItem( highlightedItem );
377
378 highlightedItem = nullptr;
379 statusPopup.Hide();
380 done = true;
381 } );
382
383 picker->SetFinalizeHandler(
384 [&]( const int& aFinalState )
385 {
386 if( highlightedItem && highlightedItem != aLockedHighlight )
387 selTool->UnbrightenItem( highlightedItem );
388
389 highlightedItem = nullptr;
390
391 if( !pickedItem )
392 done = true;
393 } );
394
395 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
396 statusPopup.Popup();
397 m_frame->GetCanvas()->SetStatusPopup( statusPopup.GetPanel() );
398
399 m_toolMgr->RunAction( ACTIONS::pickerTool, &aEvent );
400
401 while( !done && !pickedItem )
402 {
403 if( TOOL_EVENT* evt = Wait() )
404 evt->SetPassEvent();
405 else
406 break;
407 }
408
409 picker->ClearHandlers();
410 m_frame->GetCanvas()->SetStatusPopup( nullptr );
411
412 return pickedItem;
413}
414
415
417{
418 r->Report( "" );
419 r->Report( _( "Report incomplete: could not compile custom design rules." )
420 + wxS( "&nbsp;&nbsp;" )
421 + wxS( "<a href='$CUSTOM_RULES'>" ) + _( "Show design rules." ) + wxS( "</a>" ) );
422}
423
424
425void BOARD_INSPECTION_TOOL::reportHeader( const wxString& aTitle, BOARD_ITEM* a, REPORTER* r )
426{
427 r->Report( wxT( "<h7>" ) + EscapeHTML( aTitle ) + wxT( "</h7>" ) );
428 r->Report( wxT( "<ul><li>" ) + EscapeHTML( getItemDescription( a ) ) + wxT( "</li></ul>" ) );
429}
430
431
432void BOARD_INSPECTION_TOOL::reportHeader( const wxString& aTitle, BOARD_ITEM* a, BOARD_ITEM* b,
433 REPORTER* r )
434{
435 r->Report( wxT( "<h7>" ) + EscapeHTML( aTitle ) + wxT( "</h7>" ) );
436 r->Report( wxT( "<ul><li>" ) + EscapeHTML( getItemDescription( a ) ) + wxT( "</li>" )
437 + wxT( "<li>" ) + EscapeHTML( getItemDescription( b ) ) + wxT( "</li></ul>" ) );
438}
439
440
441void BOARD_INSPECTION_TOOL::reportHeader( const wxString& aTitle, BOARD_ITEM* a, BOARD_ITEM* b,
442 PCB_LAYER_ID aLayer, REPORTER* r )
443{
444 wxString layerStr = _( "Layer" ) + wxS( " " ) + m_frame->GetBoard()->GetLayerName( aLayer );
445
446 r->Report( wxT( "<h7>" ) + EscapeHTML( aTitle ) + wxT( "</h7>" ) );
447 r->Report( wxT( "<ul><li>" ) + EscapeHTML( layerStr ) + wxT( "</li>" )
448 + wxT( "<li>" ) + EscapeHTML( getItemDescription( a ) ) + wxT( "</li>" )
449 + wxT( "<li>" ) + EscapeHTML( getItemDescription( b ) ) + wxT( "</li></ul>" ) );
450}
451
452
453namespace
454{
455class VECTOR_REPORTER : public REPORTER
456{
457public:
458 REPORTER& Report( const wxString& aText, SEVERITY aSeverity = RPT_SEVERITY_UNDEFINED ) override
459 {
460 m_messages.push_back( aText );
461 return *this;
462 }
463
464 bool HasMessage() const override { return !m_messages.empty(); }
465 EDA_UNITS GetUnits() const override { return EDA_UNITS::UNSCALED; }
466
467 std::vector<wxString> m_messages;
468};
469} // namespace
470
471
472wxString reportMin( PCB_BASE_FRAME* aFrame, DRC_CONSTRAINT& aConstraint )
473{
474 if( aConstraint.m_Value.HasMin() )
475 return aFrame->StringFromValue( aConstraint.m_Value.Min(), true );
476 else
477 return wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
478}
479
480
481wxString reportOpt( PCB_BASE_FRAME* aFrame, DRC_CONSTRAINT& aConstraint )
482{
483 if( aConstraint.m_Value.HasOpt() )
484 return aFrame->StringFromValue( aConstraint.m_Value.Opt(), true );
485 else
486 return wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
487}
488
489
490wxString reportMax( PCB_BASE_FRAME* aFrame, DRC_CONSTRAINT& aConstraint )
491{
492 if( aConstraint.m_Value.HasMax() )
493 return aFrame->StringFromValue( aConstraint.m_Value.Max(), true );
494 else
495 return wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
496}
497
498
499wxString BOARD_INSPECTION_TOOL::InspectDRCErrorMenuText( const std::shared_ptr<RC_ITEM>& aDRCItem )
500{
501 if( aDRCItem->GetErrorCode() == DRCE_CLEARANCE
502 || aDRCItem->GetErrorCode() == DRCE_EDGE_CLEARANCE
503 || aDRCItem->GetErrorCode() == DRCE_HOLE_CLEARANCE
504 || aDRCItem->GetErrorCode() == DRCE_DRILLED_HOLES_TOO_CLOSE
505 || aDRCItem->GetErrorCode() == DRCE_STARVED_THERMAL )
506 {
507 return m_frame->GetRunMenuCommandDescription( PCB_ACTIONS::inspectClearance );
508 }
509 else if( aDRCItem->GetErrorCode() == DRCE_TEXT_HEIGHT
510 || aDRCItem->GetErrorCode() == DRCE_TEXT_THICKNESS
511 || aDRCItem->GetErrorCode() == DRCE_DIFF_PAIR_UNCOUPLED_LENGTH_TOO_LONG
512 || aDRCItem->GetErrorCode() == DRCE_TRACK_WIDTH
513 || aDRCItem->GetErrorCode() == DRCE_TRACK_ANGLE
514 || aDRCItem->GetErrorCode() == DRCE_TRACK_SEGMENT_LENGTH
515 || aDRCItem->GetErrorCode() == DRCE_VIA_DIAMETER
516 || aDRCItem->GetErrorCode() == DRCE_ANNULAR_WIDTH
517 || aDRCItem->GetErrorCode() == DRCE_DRILL_OUT_OF_RANGE
518 || aDRCItem->GetErrorCode() == DRCE_MICROVIA_DRILL_OUT_OF_RANGE
519 || aDRCItem->GetErrorCode() == DRCE_CONNECTION_WIDTH
520 || aDRCItem->GetErrorCode() == DRCE_ASSERTION_FAILURE )
521 {
522 return m_frame->GetRunMenuCommandDescription( PCB_ACTIONS::inspectConstraints );
523 }
524 else if( aDRCItem->GetErrorCode() == DRCE_LIB_FOOTPRINT_MISMATCH )
525 {
526 return m_frame->GetRunMenuCommandDescription( PCB_ACTIONS::diffFootprint );
527 }
528
529 return wxEmptyString;
530}
531
532
533void BOARD_INSPECTION_TOOL::InspectDRCError( const std::shared_ptr<RC_ITEM>& aDRCItem )
534{
535 DRC_TOOL* drcTool = m_toolMgr->GetTool<DRC_TOOL>();
536
537 wxCHECK( drcTool && m_frame, /* void */ );
538
539 BOARD_ITEM* a = m_frame->GetBoard()->ResolveItem( aDRCItem->GetMainItemID() );
540 BOARD_ITEM* b = m_frame->GetBoard()->ResolveItem( aDRCItem->GetAuxItemID() );
541 BOARD_CONNECTED_ITEM* ac = dynamic_cast<BOARD_CONNECTED_ITEM*>( a );
542 BOARD_CONNECTED_ITEM* bc = dynamic_cast<BOARD_CONNECTED_ITEM*>( b );
543 PCB_LAYER_ID layer = m_frame->GetActiveLayer();
544
545 if( aDRCItem->GetErrorCode() == DRCE_LIB_FOOTPRINT_MISMATCH )
546 {
547 if( FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( a ) )
548 DiffFootprint( footprint, drcTool->GetDRCDialog() );
549
550 return;
551 }
552
553 DIALOG_BOOK_REPORTER* dialog = m_frame->GetInspectDrcErrorDialog();
554 wxCHECK( dialog, /* void */ );
555
556 dialog->DeleteAllPages();
557
558 bool compileError = false;
559 bool courtyardError = false;
560 std::unique_ptr<DRC_ENGINE> drcEngine = makeDRCEngine( &compileError, &courtyardError );
561
562 WX_HTML_REPORT_BOX* r = nullptr;
563 DRC_CONSTRAINT constraint;
564 int clearance = 0;
565 wxString clearanceStr;
566
567 switch( aDRCItem->GetErrorCode() )
568 {
570 {
571 for( KIID id : aDRCItem->GetIDs() )
572 {
573 bc = dynamic_cast<BOARD_CONNECTED_ITEM*>( m_frame->GetBoard()->ResolveItem( id, true ) );
574
575 if( ac && bc && ac->GetNetCode() != bc->GetNetCode() )
576 break;
577 }
578
579 r = dialog->AddHTMLPage( _( "Uncoupled Length" ) );
580 reportHeader( _( "Diff pair uncoupled length resolution for:" ), ac, bc, r );
581
582 if( compileError )
584
585 constraint = drcEngine->EvalRules( MAX_UNCOUPLED_CONSTRAINT, a, b, layer, r );
586
587 r->Report( "" );
588 r->Report( wxString::Format( _( "Resolved max uncoupled length: %s." ),
589 reportMax( m_frame, constraint ) ) );
590 break;
591 }
592
593 case DRCE_TEXT_HEIGHT:
594 r = dialog->AddHTMLPage( _( "Text Height" ) );
595 reportHeader( _( "Text height resolution for:" ), a, r );
596
597 if( compileError )
599
600 constraint = drcEngine->EvalRules( TEXT_HEIGHT_CONSTRAINT, a, b, layer, r );
601
602 r->Report( "" );
603 r->Report( wxString::Format( _( "Resolved height constraints: min %s; max %s." ),
604 reportMin( m_frame, constraint ),
605 reportMax( m_frame, constraint ) ) );
606 break;
607
609 r = dialog->AddHTMLPage( _( "Text Thickness" ) );
610 reportHeader( _( "Text thickness resolution for:" ), a, r );
611
612 if( compileError )
614
615 constraint = drcEngine->EvalRules( TEXT_THICKNESS_CONSTRAINT, a, b, layer, r );
616
617 r->Report( "" );
618 r->Report( wxString::Format( _( "Resolved thickness constraints: min %s; max %s." ),
619 reportMin( m_frame, constraint ),
620 reportMax( m_frame, constraint ) ) );
621 break;
622
623 case DRCE_TRACK_WIDTH:
624 r = dialog->AddHTMLPage( _( "Track Width" ) );
625 reportHeader( _( "Track width resolution for:" ), a, r );
626
627 if( compileError )
629
630 constraint = drcEngine->EvalRules( TRACK_WIDTH_CONSTRAINT, a, b, layer, r );
631
632 r->Report( "" );
633 r->Report( wxString::Format( _( "Resolved width constraints: min %s; max %s." ),
634 reportMin( m_frame, constraint ),
635 reportMax( m_frame, constraint ) ) );
636 break;
637
638 case DRCE_TRACK_ANGLE:
639 r = dialog->AddHTMLPage( _( "Track Angle" ) );
640 reportHeader( _( "Track Angle resolution for:" ), a, r );
641
642 if( compileError )
644
645 constraint = drcEngine->EvalRules( TRACK_ANGLE_CONSTRAINT, a, b, layer, r );
646
647 r->Report( "" );
648 r->Report( wxString::Format( _( "Resolved angle constraints: min %s; max %s." ),
649 reportMin( m_frame, constraint ),
650 reportMax( m_frame, constraint ) ) );
651 break;
652
654 r = dialog->AddHTMLPage( _( "Track Segment Length" ) );
655 reportHeader( _( "Track segment length resolution for:" ), a, r );
656
657 if( compileError )
659
660 constraint = drcEngine->EvalRules( TRACK_SEGMENT_LENGTH_CONSTRAINT, a, b, layer, r );
661
662 r->Report( "" );
663 r->Report( wxString::Format( _( "Resolved segment length constraints: min %s; max %s." ),
664 reportMin( m_frame, constraint ),
665 reportMax( m_frame, constraint ) ) );
666 break;
667
669 r = dialog->AddHTMLPage( _( "Connection Width" ) );
670 reportHeader( _( "Connection width resolution for:" ), a, b, r );
671
672 if( compileError )
674
675 constraint = drcEngine->EvalRules( CONNECTION_WIDTH_CONSTRAINT, a, b, layer, r );
676
677 r->Report( "" );
678 r->Report( wxString::Format( _( "Resolved min connection width: %s." ),
679 reportMin( m_frame, constraint ) ) );
680 break;
681
683 r = dialog->AddHTMLPage( _( "Via Diameter" ) );
684 reportHeader( _( "Via diameter resolution for:" ), a, r );
685
686 if( compileError )
688
689 constraint = drcEngine->EvalRules( VIA_DIAMETER_CONSTRAINT, a, b, layer, r );
690
691 r->Report( "" );
692 r->Report( wxString::Format( _( "Resolved diameter constraints: min %s; max %s." ),
693 reportMin( m_frame, constraint ),
694 reportMax( m_frame, constraint ) ) );
695 break;
696
698 r = dialog->AddHTMLPage( _( "Via Annulus" ) );
699 reportHeader( _( "Via annular width resolution for:" ), a, r );
700
701 if( compileError )
703
704 constraint = drcEngine->EvalRules( ANNULAR_WIDTH_CONSTRAINT, a, b, layer, r );
705
706 r->Report( "" );
707 r->Report( wxString::Format( _( "Resolved annular width constraints: min %s; max %s." ),
708 reportMin( m_frame, constraint ),
709 reportMax( m_frame, constraint ) ) );
710 break;
711
714 r = dialog->AddHTMLPage( _( "Hole Size" ) );
715 reportHeader( _( "Hole size resolution for:" ), a, r );
716
717 if( compileError )
719
720 constraint = drcEngine->EvalRules( HOLE_SIZE_CONSTRAINT, a, b, layer, r );
721
722 r->Report( "" );
723 r->Report( wxString::Format( _( "Resolved hole size constraints: min %s; max %s." ),
724 reportMin( m_frame, constraint ),
725 reportMax( m_frame, constraint ) ) );
726 break;
727
729 r = dialog->AddHTMLPage( _( "Hole Clearance" ) );
730 reportHeader( _( "Hole clearance resolution for:" ), a, b, r );
731
732 if( compileError )
734
735 if( ac && bc && ac->GetNetCode() == bc->GetNetCode() )
736 {
737 r->Report( "" );
738 r->Report( _( "Items belong to the same net. Clearance is 0." ) );
739 }
740 else
741 {
742 constraint = drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, a, b, layer, r );
743 clearance = constraint.m_Value.Min();
744 clearanceStr = m_frame->StringFromValue( clearance, true );
745
746 r->Report( "" );
747 r->Report( wxString::Format( _( "Resolved min clearance: %s." ), clearanceStr ) );
748 }
749
750 r->Report( "" );
751 r->Report( "" );
752 r->Report( "" );
753 reportHeader( _( "Physical hole clearance resolution for:" ), a, b, layer, r );
754
755 constraint = drcEngine->EvalRules( PHYSICAL_HOLE_CLEARANCE_CONSTRAINT, a, b, layer, r );
756 clearance = constraint.m_Value.Min();
757 clearanceStr = m_frame->StringFromValue( clearance, true );
758
759 if( !drcEngine->HasRulesForConstraintType( PHYSICAL_HOLE_CLEARANCE_CONSTRAINT ) )
760 {
761 r->Report( "" );
762 r->Report( _( "No 'physical_hole_clearance' constraints defined." ) );
763 }
764 else
765 {
766 r->Report( "" );
767 r->Report( wxString::Format( _( "Resolved min clearance: %s." ), clearanceStr ) );
768 }
769
770 break;
771
773 r = dialog->AddHTMLPage( _( "Hole to Hole" ) );
774 reportHeader( _( "Hole-to-hole clearance resolution for:" ), a, b, r );
775
776 if( compileError )
778
779 constraint = drcEngine->EvalRules( HOLE_TO_HOLE_CONSTRAINT, a, b, UNDEFINED_LAYER, r );
780 clearance = constraint.m_Value.Min();
781 clearanceStr = m_frame->StringFromValue( clearance, true );
782
783 r->Report( "" );
784 r->Report( wxString::Format( _( "Resolved min clearance: %s." ), clearanceStr ) );
785 break;
786
788 r = dialog->AddHTMLPage( _( "Edge Clearance" ) );
789 reportHeader( _( "Edge clearance resolution for:" ), a, b, r );
790
791 if( compileError )
793
794 constraint = drcEngine->EvalRules( EDGE_CLEARANCE_CONSTRAINT, a, b, layer, r );
795 clearance = constraint.m_Value.Min();
796 clearanceStr = m_frame->StringFromValue( clearance, true );
797
798 r->Report( "" );
799 r->Report( wxString::Format( _( "Resolved min clearance: %s." ), clearanceStr ) );
800 break;
801
802 case DRCE_CLEARANCE:
803 if( a->Type() == PCB_TRACE_T || a->Type() == PCB_ARC_T )
804 {
805 layer = a->GetLayer();
806 }
807 else if( b->Type() == PCB_TRACE_T || b->Type() == PCB_ARC_T )
808 {
809 layer = b->GetLayer();
810 }
811 else if( a->Type() == PCB_PAD_T
812 && static_cast<PAD*>( a )->GetAttribute() == PAD_ATTRIB::SMD )
813 {
814 PAD* pad = static_cast<PAD*>( a );
815
816 if( pad->IsOnLayer( F_Cu ) )
817 layer = F_Cu;
818 else
819 layer = B_Cu;
820 }
821 else if( b->Type() == PCB_PAD_T
822 && static_cast<PAD*>( a )->GetAttribute() == PAD_ATTRIB::SMD )
823 {
824 PAD* pad = static_cast<PAD*>( b );
825
826 if( pad->IsOnLayer( F_Cu ) )
827 layer = F_Cu;
828 else
829 layer = B_Cu;
830 }
831
832 r = dialog->AddHTMLPage( _( "Clearance" ) );
833 reportHeader( _( "Clearance resolution for:" ), a, b, layer, r );
834
835 if( compileError )
837
838 if( ac && bc && ac->GetNetCode() == bc->GetNetCode() )
839 {
840 r->Report( "" );
841 r->Report( _( "Items belong to the same net. Clearance is 0." ) );
842 }
843 else
844 {
845 constraint = drcEngine->EvalRules( CLEARANCE_CONSTRAINT, a, b, layer, r );
846 clearance = constraint.m_Value.Min();
847 clearanceStr = m_frame->StringFromValue( clearance, true );
848
849 r->Report( "" );
850 r->Report( wxString::Format( _( "Resolved min clearance: %s." ), clearanceStr ) );
851 }
852
853 r->Report( "" );
854 r->Report( "" );
855 r->Report( "" );
856 reportHeader( _( "Physical clearance resolution for:" ), a, b, layer, r );
857
858 constraint = drcEngine->EvalRules( PHYSICAL_CLEARANCE_CONSTRAINT, a, b, layer, r );
859 clearance = constraint.m_Value.Min();
860 clearanceStr = m_frame->StringFromValue( clearance, true );
861
862 if( !drcEngine->HasRulesForConstraintType( PHYSICAL_CLEARANCE_CONSTRAINT ) )
863 {
864 r->Report( "" );
865 r->Report( _( "No 'physical_clearance' constraints defined." ) );
866 }
867 else
868 {
869 r->Report( "" );
870 r->Report( wxString::Format( _( "Resolved min clearance: %s." ), clearanceStr ) );
871 }
872
873 break;
874
876 r = dialog->AddHTMLPage( _( "Assertions" ) );
877 reportHeader( _( "Assertions for:" ), a, r );
878
879 if( compileError )
881
882 drcEngine->ProcessAssertions( a, []( const DRC_CONSTRAINT* c ){}, r );
883 break;
884
885 default:
886 return;
887 }
888
889 r->Flush();
890
891 KIPLATFORM::UI::ReparentWindow( dialog, drcTool->GetDRCDialog() );
892 dialog->Show( true );
893}
894
895
897{
898 wxCHECK( m_frame, 0 );
899
900 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
901
902 wxCHECK( selTool, 0 );
903
904 const PCB_SELECTION& selection = selTool->GetSelection();
905 BOARD_ITEM* firstItem = nullptr;
906 BOARD_ITEM* secondItem = nullptr;
907
908 if( selection.Size() == 2 )
909 {
910 if( !selection.GetItem( 0 )->IsBOARD_ITEM() || !selection.GetItem( 1 )->IsBOARD_ITEM() )
911 return 0;
912
913 firstItem = static_cast<BOARD_ITEM*>( selection.GetItem( 0 ) );
914 secondItem = static_cast<BOARD_ITEM*>( selection.GetItem( 1 ) );
915
916 reportClearance( firstItem, secondItem );
917 return 0;
918 }
919
920 // Selection size is not 2, so we need to use picker mode.
921 // If there is one item selected, use it as the first item.
922 if( selection.Size() == 1 && selection.GetItem( 0 )->IsBOARD_ITEM() )
923 firstItem = static_cast<BOARD_ITEM*>( selection.GetItem( 0 ) );
924
925 static const std::vector<KICAD_T> clearanceTypes = {
926 PCB_PAD_T,
927 PCB_VIA_T,
929 PCB_ARC_T,
934 };
935
936 Activate();
937
938 if( !firstItem )
939 {
940 firstItem = pickItemForInspection( aEvent,
941 _( "Select first item for clearance resolution..." ),
942 clearanceTypes, nullptr );
943
944 if( !firstItem )
945 return 0;
946 }
947
948 // Keep the first item highlighted while selecting the second
949 selTool->BrightenItem( firstItem );
950
951 secondItem = pickItemForInspection( aEvent,
952 _( "Select second item for clearance resolution..." ),
953 clearanceTypes, firstItem );
954
955 selTool->UnbrightenItem( firstItem );
956
957 if( !secondItem )
958 return 0;
959
960 if( firstItem == secondItem )
961 {
962 m_frame->ShowInfoBarError( _( "Select two different items for clearance resolution." ) );
963 return 0;
964 }
965
966 reportClearance( firstItem, secondItem );
967
968 return 0;
969}
970
971
973{
974 wxCHECK( m_frame && aItemA && aItemB, /* void */ );
975
976 BOARD_ITEM* a = aItemA;
977 BOARD_ITEM* b = aItemB;
978
979 if( a->Type() == PCB_GROUP_T )
980 {
981 PCB_GROUP* ag = static_cast<PCB_GROUP*>( a );
982
983 if( ag->GetItems().empty() )
984 {
985 m_frame->ShowInfoBarError( _( "Cannot generate clearance report on empty group." ) );
986 return;
987 }
988
989 a = static_cast<BOARD_ITEM*>( *ag->GetItems().begin() );
990 }
991
992 if( b->Type() == PCB_GROUP_T )
993 {
994 PCB_GROUP* bg = static_cast<PCB_GROUP*>( b );
995
996 if( bg->GetItems().empty() )
997 {
998 m_frame->ShowInfoBarError( _( "Cannot generate clearance report on empty group." ) );
999 return;
1000 }
1001
1002 b = static_cast<BOARD_ITEM*>( *bg->GetItems().begin() );
1003 }
1004
1005 if( !a || !b )
1006 return;
1007
1008 auto checkFootprint =
1009 [&]( FOOTPRINT* footprint ) -> BOARD_ITEM*
1010 {
1011 PAD* foundPad = nullptr;
1012
1013 for( PAD* pad : footprint->Pads() )
1014 {
1015 if( !foundPad || pad->SameLogicalPadAs( foundPad ) )
1016 foundPad = pad;
1017 else
1018 return footprint;
1019 }
1020
1021 if( !foundPad )
1022 return footprint;
1023
1024 return foundPad;
1025 };
1026
1027 if( a->Type() == PCB_FOOTPRINT_T )
1028 a = checkFootprint( static_cast<FOOTPRINT*>( a ) );
1029
1030 if( b->Type() == PCB_FOOTPRINT_T )
1031 b = checkFootprint( static_cast<FOOTPRINT*>( b ) );
1032
1033 if( !a || !b )
1034 return;
1035
1036 DIALOG_BOOK_REPORTER* dialog = m_frame->GetInspectClearanceDialog();
1037
1038 wxCHECK( dialog, /* void */ );
1039
1040 dialog->DeleteAllPages();
1041
1042 if( a->Type() != PCB_ZONE_T && b->Type() == PCB_ZONE_T )
1043 std::swap( a, b );
1044 else if( !a->IsConnected() && b->IsConnected() )
1045 std::swap( a, b );
1046
1047 WX_HTML_REPORT_BOX* r = nullptr;
1048 PCB_LAYER_ID active = m_frame->GetActiveLayer();
1049 LSET layerIntersection = a->GetLayerSet() & b->GetLayerSet();
1050 LSET copperIntersection = layerIntersection & LSET::AllCuMask();
1051 BOARD_CONNECTED_ITEM* ac = dynamic_cast<BOARD_CONNECTED_ITEM*>( a );
1052 BOARD_CONNECTED_ITEM* bc = dynamic_cast<BOARD_CONNECTED_ITEM*>( b );
1053 ZONE* zone = dynamic_cast<ZONE*>( a );
1054 PAD* pad = dynamic_cast<PAD*>( b );
1055 FOOTPRINT* aFP = dynamic_cast<FOOTPRINT*>( a );
1056 FOOTPRINT* bFP = dynamic_cast<FOOTPRINT*>( b );
1057 DRC_CONSTRAINT constraint;
1058 int clearance = 0;
1059
1060 bool compileError = false;
1061 bool courtyardError = false;
1062 std::unique_ptr<DRC_ENGINE> drcEngine = makeDRCEngine( &compileError, &courtyardError );
1063
1064 if( copperIntersection.any() && zone && pad && zone->GetNetCode() == pad->GetNetCode() )
1065 {
1067
1068 if( zone->IsOnLayer( active ) )
1069 layer = active;
1070 else if( zone->GetLayerSet().count() > 0 )
1071 layer = zone->GetLayerSet().Seq().front();
1072
1073 r = dialog->AddHTMLPage( _( "Zone" ) );
1074 reportHeader( _( "Zone connection resolution for:" ), a, b, layer, r );
1075
1076 constraint = drcEngine->EvalZoneConnection( pad, zone, layer, r );
1077
1078 if( constraint.m_ZoneConnection == ZONE_CONNECTION::THERMAL )
1079 {
1080 r->Report( "" );
1081 r->Report( "" );
1082 reportHeader( _( "Thermal-relief gap resolution for:" ), a, b, layer, r );
1083
1084 constraint = drcEngine->EvalRules( THERMAL_RELIEF_GAP_CONSTRAINT, pad, zone, layer, r );
1085 int gap = constraint.m_Value.Min();
1086
1087 if( compileError )
1088 reportCompileError( r );
1089
1090 r->Report( "" );
1091 r->Report( wxString::Format( _( "Resolved thermal relief gap: %s." ),
1092 m_frame->StringFromValue( gap, true ) ) );
1093
1094 r->Report( "" );
1095 r->Report( "" );
1096 reportHeader( _( "Thermal-relief spoke width resolution for:" ), a, b, layer, r );
1097
1098 constraint = drcEngine->EvalRules( THERMAL_SPOKE_WIDTH_CONSTRAINT, pad, zone, layer, r );
1099 int width = constraint.m_Value.Opt();
1100
1101 if( compileError )
1102 reportCompileError( r );
1103
1104 r->Report( "" );
1105 r->Report( wxString::Format( _( "Resolved spoke width: %s." ),
1106 m_frame->StringFromValue( width, true ) ) );
1107
1108 r->Report( "" );
1109 r->Report( "" );
1110 reportHeader( _( "Thermal-relief min spoke count resolution for:" ), a, b, layer, r );
1111
1112 constraint = drcEngine->EvalRules( MIN_RESOLVED_SPOKES_CONSTRAINT, pad, zone, layer, r );
1113 int minSpokes = constraint.m_Value.Min();
1114
1115 if( compileError )
1116 reportCompileError( r );
1117
1118 r->Report( "" );
1119 r->Report( wxString::Format( _( "Resolved min spoke count: %d." ),
1120 minSpokes ) );
1121
1122 std::shared_ptr<CONNECTIVITY_DATA> connectivity = pad->GetBoard()->GetConnectivity();
1123 }
1124 else if( constraint.m_ZoneConnection == ZONE_CONNECTION::NONE )
1125 {
1126 r->Report( "" );
1127 r->Report( "" );
1128 reportHeader( _( "Zone clearance resolution for:" ), a, b, layer, r );
1129
1130 clearance = zone->GetLocalClearance().value();
1131 r->Report( "" );
1132 r->Report( wxString::Format( _( "Zone clearance: %s." ),
1133 m_frame->StringFromValue( clearance, true ) ) );
1134
1135 constraint = drcEngine->EvalRules( PHYSICAL_CLEARANCE_CONSTRAINT, pad, zone, layer, r );
1136
1137 if( constraint.m_Value.Min() > clearance )
1138 {
1139 clearance = constraint.m_Value.Min();
1140
1141 r->Report( "" );
1142 r->Report( wxString::Format( _( "Overridden by larger physical clearance from %s;"
1143 "clearance: %s." ),
1144 EscapeHTML( constraint.GetName() ),
1145 m_frame->StringFromValue( clearance, true ) ) );
1146 }
1147
1148 if( !pad->FlashLayer( layer ) )
1149 {
1150 constraint = drcEngine->EvalRules( PHYSICAL_HOLE_CLEARANCE_CONSTRAINT, pad, zone,
1151 layer, r );
1152
1153 if( constraint.m_Value.Min() > clearance )
1154 {
1155 clearance = constraint.m_Value.Min();
1156
1157 r->Report( "" );
1158 r->Report( wxString::Format( _( "Overridden by larger physical hole clearance "
1159 "from %s; clearance: %s." ),
1160 EscapeHTML( constraint.GetName() ),
1161 m_frame->StringFromValue( clearance, true ) ) );
1162 }
1163 }
1164
1165 if( compileError )
1166 reportCompileError( r );
1167
1168 r->Report( "" );
1169 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1170 m_frame->StringFromValue( clearance, true ) ) );
1171 }
1172 else
1173 {
1174 r->Report( "" );
1175 r->Report( "" );
1176 reportHeader( _( "Zone clearance resolution for:" ), a, b, layer, r );
1177
1178 if( compileError )
1179 reportCompileError( r );
1180
1181 r->Report( "" );
1182 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1183 m_frame->StringFromValue( 0, true ) ) );
1184 }
1185
1186 r->Flush();
1187 }
1188 else if( copperIntersection.any() && !aFP && !bFP )
1189 {
1190 bool sameNet = ac && bc && ac->GetNetCode() > 0 && ac->GetNetCode() == bc->GetNetCode();
1191
1192 std::vector<PCB_LAYER_ID> layers;
1193
1194 if( copperIntersection.test( active ) )
1195 layers.push_back( active );
1196
1197 for( PCB_LAYER_ID layer : copperIntersection.Seq() )
1198 {
1199 if( layer != active )
1200 layers.push_back( layer );
1201 }
1202
1203 auto fillReport = [&]( PCB_LAYER_ID layer, REPORTER* rep )
1204 {
1205 reportHeader( _( "Clearance resolution for:" ), a, b, layer, rep );
1206
1207 if( sameNet )
1208 {
1209 rep->Report( _( "Items belong to the same net. Min clearance is 0." ) );
1210 return;
1211 }
1212
1213 constraint = drcEngine->EvalRules( CLEARANCE_CONSTRAINT, a, b, layer, rep );
1214 clearance = constraint.m_Value.Min();
1215
1216 if( compileError )
1217 reportCompileError( rep );
1218
1219 rep->Report( "" );
1220
1221 if( constraint.IsNull() )
1222 {
1223 rep->Report( _( "Min clearance is 0." ) );
1224 }
1225 else if( clearance < 0 )
1226 {
1227 rep->Report( wxString::Format( _( "Resolved clearance: %s; clearance will "
1228 "not be tested." ),
1229 m_frame->StringFromValue( clearance, true ) ) );
1230 }
1231 else
1232 {
1233 rep->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1234 m_frame->StringFromValue( clearance, true ) ) );
1235 }
1236 };
1237
1238 if( layers.size() == 1 )
1239 {
1240 PCB_LAYER_ID layer = layers.front();
1241
1242 r = dialog->AddHTMLPage( m_frame->GetBoard()->GetLayerName( layer ) );
1243 fillReport( layer, r );
1244 r->Flush();
1245 }
1246 else
1247 {
1248 auto perLayerMessages = std::make_shared<std::vector<std::vector<wxString>>>();
1249 perLayerMessages->reserve( layers.size() );
1250
1251 for( PCB_LAYER_ID layer : layers )
1252 {
1253 VECTOR_REPORTER tmp;
1254 fillReport( layer, &tmp );
1255 perLayerMessages->push_back( std::move( tmp.m_messages ) );
1256 }
1257
1258 wxPanel* panel = dialog->AddBlankPage( _( "Clearance" ) );
1259 wxBoxSizer* vbox = new wxBoxSizer( wxVERTICAL );
1260
1261 wxChoice* choice = new wxChoice( panel, wxID_ANY );
1262
1263 for( PCB_LAYER_ID layer : layers )
1264 choice->Append( m_frame->GetBoard()->GetLayerName( layer ) );
1265
1266 choice->SetSelection( 0 );
1267
1268 WX_HTML_REPORT_BOX* reportBox = new WX_HTML_REPORT_BOX( panel, wxID_ANY, wxDefaultPosition, wxDefaultSize,
1269 wxHW_SCROLLBAR_AUTO | wxBORDER_SIMPLE );
1270 reportBox->SetUnits( m_frame->GetUserUnits() );
1271
1272 wxStaticText* layerLabel = new wxStaticText( panel, wxID_ANY, _( "Layer:" ) );
1273
1274 vbox->Add( layerLabel, 0, wxLEFT | wxRIGHT | wxTOP, 5 );
1275 vbox->Add( choice, 0, wxEXPAND | wxALL, 5 );
1276 vbox->Add( reportBox, 1, wxEXPAND | wxALL, 5 );
1277 panel->SetSizer( vbox );
1278 panel->Layout();
1279
1280 auto refresh = [reportBox, perLayerMessages]( int sel )
1281 {
1282 reportBox->Clear();
1283
1284 if( sel >= 0 && sel < (int) perLayerMessages->size() )
1285 {
1286 for( const wxString& line : ( *perLayerMessages )[sel] )
1287 reportBox->Report( line );
1288 }
1289
1290 reportBox->Flush();
1291 };
1292
1293 choice->Bind( wxEVT_CHOICE,
1294 [refresh]( wxCommandEvent& evt )
1295 {
1296 refresh( evt.GetSelection() );
1297 } );
1298
1299 refresh( 0 );
1300 }
1301 }
1302
1303 if( ac && bc )
1304 {
1305 NETINFO_ITEM* refNet = ac->GetNet();
1306 wxString coupledNet;
1307 wxString dummy;
1308
1309 if( DRC_ENGINE::MatchDpSuffix( refNet->GetNetname(), coupledNet, dummy )
1310 && bc->GetNetname() == coupledNet )
1311 {
1312 LSET dpIntersection = ac->GetLayerSet() & bc->GetLayerSet() & LSET::AllCuMask();
1313 PCB_LAYER_ID dpLayer = active;
1314
1315 if( !dpIntersection.test( dpLayer ) && dpIntersection.any() )
1316 dpLayer = dpIntersection.Seq().front();
1317
1318 r = dialog->AddHTMLPage( _( "Diff Pair" ) );
1319 reportHeader( _( "Diff-pair gap resolution for:" ), ac, bc, dpLayer, r );
1320
1321 constraint = drcEngine->EvalRules( DIFF_PAIR_GAP_CONSTRAINT, ac, bc, dpLayer, r );
1322
1323 r->Report( "" );
1324 r->Report( wxString::Format( _( "Resolved gap constraints: min %s; opt %s; max %s." ),
1325 reportMin( m_frame, constraint ),
1326 reportOpt( m_frame, constraint ),
1327 reportMax( m_frame, constraint ) ) );
1328
1329 r->Report( "" );
1330 r->Report( "" );
1331 r->Report( "" );
1332 reportHeader( _( "Diff-pair max uncoupled length resolution for:" ), ac, bc, dpLayer, r );
1333
1334 if( !drcEngine->HasRulesForConstraintType( MAX_UNCOUPLED_CONSTRAINT ) )
1335 {
1336 r->Report( "" );
1337 r->Report( _( "No 'diff_pair_uncoupled' constraints defined." ) );
1338 }
1339 else
1340 {
1341 constraint = drcEngine->EvalRules( MAX_UNCOUPLED_CONSTRAINT, ac, bc, dpLayer, r );
1342
1343 r->Report( "" );
1344 r->Report( wxString::Format( _( "Resolved max uncoupled length: %s." ),
1345 reportMax( m_frame, constraint ) ) );
1346 }
1347
1348 r->Flush();
1349 }
1350 }
1351
1352 auto isOnCorrespondingLayer=
1353 [&]( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer, wxString* aWarning )
1354 {
1355 if( aItem->IsOnLayer( aLayer ) )
1356 return true;
1357
1358 PCB_LAYER_ID correspondingMask = IsFrontLayer( aLayer ) ? F_Mask : B_Mask;
1359 PCB_LAYER_ID correspondingCopper = IsFrontLayer( aLayer ) ? F_Cu : B_Cu;
1360
1361 if( aItem->IsOnLayer( aLayer ) )
1362 return true;
1363
1364 if( aItem->IsOnLayer( correspondingMask ) )
1365 return true;
1366
1367 if( aItem->IsTented( correspondingMask ) && aItem->IsOnLayer( correspondingCopper ) )
1368 {
1369 *aWarning = wxString::Format( _( "Note: %s is tented; clearance will only be "
1370 "applied to holes." ),
1371 getItemDescription( aItem ) );
1372 return true;
1373 }
1374
1375 return false;
1376 };
1377
1378 for( PCB_LAYER_ID layer : { F_SilkS, B_SilkS } )
1379 {
1380 wxString warning;
1381
1382 if( ( a->IsOnLayer( layer ) && isOnCorrespondingLayer( b, layer, &warning ) )
1383 || ( b->IsOnLayer( layer ) && isOnCorrespondingLayer( a, layer, &warning ) ) )
1384 {
1385 r = dialog->AddHTMLPage( m_frame->GetBoard()->GetLayerName( layer ) );
1386 reportHeader( _( "Silkscreen clearance resolution for:" ), a, b, layer, r );
1387
1388 constraint = drcEngine->EvalRules( SILK_CLEARANCE_CONSTRAINT, a, b, layer, r );
1389 clearance = constraint.m_Value.Min();
1390
1391 if( compileError )
1392 reportCompileError( r );
1393
1394 r->Report( "" );
1395
1396 if( !warning.IsEmpty() )
1397 r->Report( warning );
1398
1399 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1400 m_frame->StringFromValue( clearance, true ) ) );
1401
1402 r->Flush();
1403 }
1404 }
1405
1406 for( PCB_LAYER_ID layer : { F_CrtYd, B_CrtYd } )
1407 {
1408 bool aCourtyard = aFP && !aFP->GetCourtyard( layer ).IsEmpty();
1409 bool bCourtyard = bFP && !bFP->GetCourtyard( layer ).IsEmpty();
1410
1411 if( aCourtyard && bCourtyard )
1412 {
1413 r = dialog->AddHTMLPage( m_frame->GetBoard()->GetLayerName( layer ) );
1414 reportHeader( _( "Courtyard clearance resolution for:" ), a, b, layer, r );
1415
1416 constraint = drcEngine->EvalRules( COURTYARD_CLEARANCE_CONSTRAINT, a, b, layer, r );
1417 clearance = constraint.m_Value.Min();
1418
1419 if( compileError )
1420 reportCompileError( r );
1421
1422 r->Report( "" );
1423 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1424 m_frame->StringFromValue( clearance, true ) ) );
1425
1426 r->Flush();
1427 }
1428 }
1429
1430 if( a->HasHole() || b->HasHole() )
1431 {
1433 bool pageAdded = false;
1434
1435 if( a->HasHole() && b->IsOnLayer( active ) && IsCopperLayer( active ) )
1436 layer = active;
1437 else if( b->HasHole() && a->IsOnLayer( active ) && IsCopperLayer( active ) )
1438 layer = active;
1439 else if( a->HasHole() && b->IsOnCopperLayer() )
1440 layer = b->GetLayer();
1441 else if( b->HasHole() && a->IsOnCopperLayer() )
1442 layer = a->GetLayer();
1443
1444 if( layer >= 0 )
1445 {
1446 r = dialog->AddHTMLPage( _( "Hole" ) );
1447 pageAdded = true;
1448
1449 reportHeader( _( "Hole clearance resolution for:" ), a, b, layer, r );
1450
1451 constraint = drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, a, b, layer, r );
1452 clearance = constraint.m_Value.Min();
1453
1454 if( compileError )
1455 reportCompileError( r );
1456
1457 r->Report( "" );
1458 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1459 m_frame->StringFromValue( clearance, true ) ) );
1460
1461 r->Flush();
1462 }
1463
1464 if( a->HasDrilledHole() || b->HasDrilledHole() )
1465 {
1466 if( !pageAdded )
1467 {
1468 r = dialog->AddHTMLPage( _( "Hole" ) );
1469 pageAdded = true;
1470 }
1471 else
1472 {
1473 r->Report( "" );
1474 r->Report( "" );
1475 r->Report( "" );
1476 }
1477
1478 reportHeader( _( "Hole-to-hole clearance resolution for:" ), a, b, r );
1479
1480 constraint = drcEngine->EvalRules( HOLE_TO_HOLE_CONSTRAINT, a, b, UNDEFINED_LAYER, r );
1481 clearance = constraint.m_Value.Min();
1482
1483 if( compileError )
1484 reportCompileError( r );
1485
1486 r->Report( "" );
1487 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1488 m_frame->StringFromValue( clearance, true ) ) );
1489
1490 r->Flush();
1491 }
1492 }
1493
1494 for( PCB_LAYER_ID edgeLayer : { Edge_Cuts, Margin } )
1495 {
1497
1498 if( a->IsOnLayer( edgeLayer ) && b->Type() != PCB_FOOTPRINT_T )
1499 {
1500 if( b->IsOnLayer( active ) && IsCopperLayer( active ) )
1501 layer = active;
1502 else if( IsCopperLayer( b->GetLayer() ) )
1503 layer = b->GetLayer();
1504 }
1505 else if( b->IsOnLayer( edgeLayer ) && a->Type() != PCB_FOOTPRINT_T )
1506 {
1507 if( a->IsOnLayer( active ) && IsCopperLayer( active ) )
1508 layer = active;
1509 else if( IsCopperLayer( a->GetLayer() ) )
1510 layer = a->GetLayer();
1511 }
1512
1513 if( layer >= 0 )
1514 {
1515 wxString layerName = m_frame->GetBoard()->GetLayerName( edgeLayer );
1516 r = dialog->AddHTMLPage( layerName + wxS( " " ) + _( "Clearance" ) );
1517 reportHeader( _( "Edge clearance resolution for:" ), a, b, layer, r );
1518
1519 constraint = drcEngine->EvalRules( EDGE_CLEARANCE_CONSTRAINT, a, b, layer, r );
1520 clearance = constraint.m_Value.Min();
1521
1522 if( compileError )
1523 reportCompileError( r );
1524
1525 r->Report( "" );
1526 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1527 m_frame->StringFromValue( clearance, true ) ) );
1528
1529 r->Flush();
1530 }
1531 }
1532
1533 r = dialog->AddHTMLPage( _( "Physical Clearances" ) );
1534
1535 if( compileError )
1536 {
1537 reportCompileError( r );
1538 }
1539 else if( !drcEngine->HasRulesForConstraintType( PHYSICAL_CLEARANCE_CONSTRAINT ) )
1540 {
1541 r->Report( "" );
1542 r->Report( _( "No 'physical_clearance' constraints defined." ) );
1543 }
1544 else
1545 {
1546 LSET reportLayers = layerIntersection;
1547 bool reported = false;
1548
1549 if( a->IsOnLayer( Edge_Cuts ) )
1550 {
1551 LSET edgeInteractingLayers = bFP ? LSET( { F_CrtYd, B_CrtYd } )
1553 reportLayers |= edgeInteractingLayers;
1554 }
1555
1556 if( b->IsOnLayer( Edge_Cuts ) )
1557 {
1558 LSET edgeInteractingLayers = aFP ? LSET( { F_CrtYd, B_CrtYd } )
1560 reportLayers |= edgeInteractingLayers;
1561 }
1562
1563 for( PCB_LAYER_ID layer : reportLayers )
1564 {
1565 reported = true;
1566 reportHeader( _( "Physical clearance resolution for:" ), a, b, layer, r );
1567
1568 constraint = drcEngine->EvalRules( PHYSICAL_CLEARANCE_CONSTRAINT, a, b, layer, r );
1569 clearance = constraint.m_Value.Min();
1570
1571 if( constraint.IsNull() )
1572 {
1573 r->Report( "" );
1574 r->Report( wxString::Format( _( "No 'physical_clearance' constraints in effect on %s." ),
1575 m_frame->GetBoard()->GetLayerName( layer ) ) );
1576 }
1577 else
1578 {
1579 r->Report( "" );
1580 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1581 m_frame->StringFromValue( clearance, true ) ) );
1582 }
1583
1584 r->Report( "" );
1585 r->Report( "" );
1586 r->Report( "" );
1587 }
1588
1589 if( !reported )
1590 {
1591 reportHeader( _( "Physical clearance resolution for:" ), a, b, r );
1592 r->Report( "" );
1593 r->Report( _( "Items share no relevant layers. No 'physical_clearance' constraints will "
1594 "be applied." ) );
1595 }
1596 }
1597
1598 if( a->HasHole() || b->HasHole() )
1599 {
1600 PCB_LAYER_ID layer;
1601
1602 if( a->HasHole() && b->IsOnLayer( active ) )
1603 layer = active;
1604 else if( b->HasHole() && a->IsOnLayer( active ) )
1605 layer = active;
1606 else if( a->HasHole() )
1607 layer = b->GetLayer();
1608 else
1609 layer = a->GetLayer();
1610
1611 reportHeader( _( "Physical hole clearance resolution for:" ), a, b, layer, r );
1612
1613 constraint = drcEngine->EvalRules( PHYSICAL_HOLE_CLEARANCE_CONSTRAINT, a, b, layer, r );
1614 clearance = constraint.m_Value.Min();
1615
1616 if( compileError )
1617 {
1618 reportCompileError( r );
1619 }
1620 else if( !drcEngine->HasRulesForConstraintType( PHYSICAL_HOLE_CLEARANCE_CONSTRAINT ) )
1621 {
1622 r->Report( "" );
1623 r->Report( _( "No 'physical_hole_clearance' constraints defined." ) );
1624 }
1625 else
1626 {
1627 r->Report( "" );
1628 r->Report( wxString::Format( _( "Resolved min clearance: %s." ),
1629 m_frame->StringFromValue( clearance, true ) ) );
1630 }
1631 }
1632
1633 r->Flush();
1634
1635 dialog->Raise();
1636 dialog->Show( true );
1637}
1638
1639
1641{
1642#define EVAL_RULES( constraint, a, b, layer, r ) drcEngine->EvalRules( constraint, a, b, layer, r )
1643
1644 wxCHECK( m_frame, 0 );
1645
1646 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1647
1648 wxCHECK( selTool, 0 );
1649
1650 const PCB_SELECTION& selection = selTool->GetSelection();
1651 BOARD_ITEM* item = nullptr;
1652
1653 if( selection.Size() == 1 && selection.GetItem( 0 )->IsBOARD_ITEM() )
1654 {
1655 item = static_cast<BOARD_ITEM*>( selection.GetItem( 0 ) );
1656 }
1657 else if( selection.Size() == 0 )
1658 {
1659 static const std::vector<KICAD_T> constraintTypes = {
1660 PCB_PAD_T,
1661 PCB_VIA_T,
1663 PCB_ARC_T,
1664 PCB_ZONE_T,
1668 PCB_TEXT_T,
1671 };
1672
1673 Activate();
1674
1675 item = pickItemForInspection( aEvent, _( "Select item for constraints resolution..." ),
1676 constraintTypes, nullptr );
1677
1678 if( !item )
1679 return 0;
1680 }
1681 else
1682 {
1683 m_frame->ShowInfoBarError( _( "Select a single item for a constraints resolution report." ) );
1684 return 0;
1685 }
1686
1687 DIALOG_BOOK_REPORTER* dialog = m_frame->GetInspectConstraintsDialog();
1688
1689 wxCHECK( dialog, 0 );
1690
1691 dialog->DeleteAllPages();
1692 DRC_CONSTRAINT constraint;
1693
1694 bool compileError = false;
1695 bool courtyardError = false;
1696 std::unique_ptr<DRC_ENGINE> drcEngine = makeDRCEngine( &compileError, &courtyardError );
1697
1698 WX_HTML_REPORT_BOX* r = nullptr;
1699
1700 if( item->Type() == PCB_TRACE_T )
1701 {
1702 r = dialog->AddHTMLPage( _( "Track Width" ) );
1703 reportHeader( _( "Track width resolution for:" ), item, r );
1704
1705 constraint = EVAL_RULES( TRACK_WIDTH_CONSTRAINT, item, nullptr, item->GetLayer(), r );
1706
1707 if( compileError )
1708 reportCompileError( r );
1709
1710 r->Report( "" );
1711 r->Report( wxString::Format( _( "Resolved width constraints: min %s; opt %s; max %s." ),
1712 reportMin( m_frame, constraint ),
1713 reportOpt( m_frame, constraint ),
1714 reportMax( m_frame, constraint ) ) );
1715
1716 r->Flush();
1717 }
1718
1719 if( item->Type() == PCB_VIA_T )
1720 {
1721 r = dialog->AddHTMLPage( _( "Via Diameter" ) );
1722 reportHeader( _( "Via diameter resolution for:" ), item, r );
1723
1724 // PADSTACKS TODO: once we have padstacks we'll need to run this per-layer....
1725 constraint = EVAL_RULES( VIA_DIAMETER_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
1726
1727 if( compileError )
1728 reportCompileError( r );
1729
1730 r->Report( "" );
1731 r->Report( wxString::Format( _( "Resolved diameter constraints: min %s; opt %s; max %s." ),
1732 reportMin( m_frame, constraint ),
1733 reportOpt( m_frame, constraint ),
1734 reportMax( m_frame, constraint ) ) );
1735
1736 r->Flush();
1737
1738 r = dialog->AddHTMLPage( _( "Via Annular Width" ) );
1739 reportHeader( _( "Via annular width resolution for:" ), item, r );
1740
1741 // PADSTACKS TODO: once we have padstacks we'll need to run this per-layer....
1742 constraint = EVAL_RULES( ANNULAR_WIDTH_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
1743
1744 if( compileError )
1745 reportCompileError( r );
1746
1747 r->Report( "" );
1748 r->Report( wxString::Format( _( "Resolved annular width constraints: min %s; opt %s; max %s." ),
1749 reportMin( m_frame, constraint ),
1750 reportOpt( m_frame, constraint ),
1751 reportMax( m_frame, constraint ) ) );
1752
1753 r->Flush();
1754 }
1755
1756 if( ( item->Type() == PCB_PAD_T && static_cast<PAD*>( item )->GetDrillSize().x > 0 )
1757 || item->Type() == PCB_VIA_T )
1758 {
1759 r = dialog->AddHTMLPage( _( "Hole Size" ) );
1760 reportHeader( _( "Hole size resolution for:" ), item, r );
1761
1762 constraint = EVAL_RULES( HOLE_SIZE_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
1763
1764 if( compileError )
1765 reportCompileError( r );
1766
1767 r->Report( "" );
1768 r->Report( wxString::Format( _( "Resolved hole size constraints: min %s; opt %s; max %s." ),
1769 reportMin( m_frame, constraint ),
1770 reportOpt( m_frame, constraint ),
1771 reportMax( m_frame, constraint ) ) );
1772
1773 r->Flush();
1774 }
1775
1776 if( item->Type() == PCB_PAD_T || item->Type() == PCB_SHAPE_T || dynamic_cast<PCB_TRACK*>( item ) )
1777 {
1778 r = dialog->AddHTMLPage( _( "Solder Mask" ) );
1779 reportHeader( _( "Solder mask expansion resolution for:" ), item, r );
1780
1781 constraint = EVAL_RULES( SOLDER_MASK_EXPANSION_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
1782
1783 if( compileError )
1784 reportCompileError( r );
1785
1786 r->Report( "" );
1787 r->Report( wxString::Format( _( "Resolved solder mask expansion: %s." ),
1788 reportOpt( m_frame, constraint ) ) );
1789
1790 r->Flush();
1791 }
1792
1793 if( item->Type() == PCB_PAD_T )
1794 {
1795 r = dialog->AddHTMLPage( _( "Solder Paste" ) );
1796 reportHeader( _( "Solder paste absolute clearance resolution for:" ), item, r );
1797
1798 constraint = EVAL_RULES( SOLDER_PASTE_ABS_MARGIN_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
1799
1800 if( compileError )
1801 reportCompileError( r );
1802
1803 r->Report( "" );
1804 r->Report( wxString::Format( _( "Resolved solder paste absolute clearance: %s." ),
1805 reportOpt( m_frame, constraint ) ) );
1806
1807 reportHeader( _( "Solder paste relative clearance resolution for:" ), item, r );
1808
1809 constraint = EVAL_RULES( SOLDER_PASTE_REL_MARGIN_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
1810
1811 if( compileError )
1812 reportCompileError( r );
1813
1814 r->Report( "" );
1815 r->Report( "" );
1816 r->Report( "" );
1817 r->Report( wxString::Format( _( "Resolved solder paste relative clearance: %s." ),
1818 reportOpt( m_frame, constraint ) ) );
1819
1820 r->Flush();
1821 }
1822
1823 if( item->Type() == PCB_FIELD_T || item->Type() == PCB_TEXT_T || item->Type() == PCB_TEXTBOX_T )
1824 {
1825 r = dialog->AddHTMLPage( _( "Text Size" ) );
1826 reportHeader( _( "Text height resolution for:" ), item, r );
1827
1828 constraint = EVAL_RULES( TEXT_HEIGHT_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
1829
1830 if( compileError )
1831 reportCompileError( r );
1832
1833 r->Report( "" );
1834 r->Report( wxString::Format( _( "Resolved height constraints: min %s; opt %s; max %s." ),
1835 reportMin( m_frame, constraint ),
1836 reportOpt( m_frame, constraint ),
1837 reportMax( m_frame, constraint ) ) );
1838
1839 r->Report( "" );
1840 r->Report( "" );
1841 r->Report( "" );
1842 reportHeader( _( "Text thickness resolution for:" ), item, r );
1843
1844 constraint = EVAL_RULES( TEXT_THICKNESS_CONSTRAINT, item, nullptr, UNDEFINED_LAYER, r );
1845
1846 if( compileError )
1847 reportCompileError( r );
1848
1849 r->Report( "" );
1850 r->Report( wxString::Format( _( "Resolved thickness constraints: min %s; opt %s; max %s." ),
1851 reportMin( m_frame, constraint ),
1852 reportOpt( m_frame, constraint ),
1853 reportMax( m_frame, constraint ) ) );
1854
1855 r->Flush();
1856 }
1857
1858 r = dialog->AddHTMLPage( _( "Keepouts" ) );
1859 reportHeader( _( "Keepout resolution for:" ), item, r );
1860
1861 constraint = EVAL_RULES( DISALLOW_CONSTRAINT, item, nullptr, item->GetLayer(), r );
1862
1863 if( compileError )
1864 reportCompileError( r );
1865
1866 if( courtyardError )
1867 {
1868 r->Report( "" );
1869 r->Report( _( "Report may be incomplete: some footprint courtyards are malformed." )
1870 + wxS( "&nbsp;&nbsp;" )
1871 + wxS( "<a href='$DRC'>" ) + _( "Run DRC for a full analysis." )
1872 + wxS( "</a>" ) );
1873 }
1874
1875 r->Report( "" );
1876
1877 if( constraint.m_DisallowFlags )
1878 r->Report( _( "Item <b>disallowed</b> at current location." ) );
1879 else
1880 r->Report( _( "Item allowed at current location." ) );
1881
1882 r->Flush();
1883
1884 r = dialog->AddHTMLPage( _( "Assertions" ) );
1885 reportHeader( _( "Assertions for:" ), item, r );
1886
1887 if( compileError )
1888 reportCompileError( r );
1889
1890 if( courtyardError )
1891 {
1892 r->Report( "" );
1893 r->Report( _( "Report may be incomplete: some footprint courtyards are malformed." )
1894 + wxS( "&nbsp;&nbsp;" )
1895 + wxS( "<a href='$DRC'>" ) + _( "Run DRC for a full analysis." )
1896 + wxS( "</a>" ) );
1897 }
1898
1899 drcEngine->ProcessAssertions( item, []( const DRC_CONSTRAINT* c ){}, r );
1900 r->Flush();
1901
1902 dialog->Raise();
1903 dialog->Show( true );
1904 return 0;
1905}
1906
1907
1909{
1910 wxCHECK( m_frame, 0 );
1911
1912 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1913
1914 wxCHECK( selTool, 0 );
1915
1916 const PCB_SELECTION& selection = selTool->RequestSelection(
1917 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
1918 {
1919 // Iterate from the back so we don't have to worry about removals.
1920 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
1921 {
1922 BOARD_ITEM* item = aCollector[ i ];
1923
1924 if( !dynamic_cast<FOOTPRINT*>( item ) )
1925 aCollector.Remove( item );
1926 }
1927 } );
1928
1929 if( selection.Size() == 1 )
1930 DiffFootprint( static_cast<FOOTPRINT*>( selection.GetItem( 0 ) ) );
1931 else
1932 m_frame->ShowInfoBarError( _( "Select a footprint to diff with its library equivalent." ) );
1933
1934 return 0;
1935}
1936
1937
1939{
1940 wxCHECK( m_frame, 0 );
1941
1942 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1943
1944 wxCHECK( selTool, 0 );
1945
1946 const PCB_SELECTION& selection = selTool->GetSelection();
1947
1948 if( selection.Size() != 1 || selection.Front()->Type() != PCB_FOOTPRINT_T )
1949 {
1950 m_frame->ShowInfoBarError( _( "Select a footprint for a footprint associations report." ) );
1951 return 0;
1952 }
1953
1954 DIALOG_FOOTPRINT_ASSOCIATIONS dlg( m_frame, static_cast<FOOTPRINT*>( selection.Front() ) );
1955
1956 dlg.ShowModal();
1957
1958 return 0;
1959}
1960
1961
1962void BOARD_INSPECTION_TOOL::DiffFootprint( FOOTPRINT* aFootprint, wxTopLevelWindow* aReparentTo )
1963{
1964 DIALOG_BOOK_REPORTER* dialog = m_frame->GetFootprintDiffDialog();
1965
1966 wxCHECK( dialog, /* void */ );
1967
1968 dialog->DeleteAllPages();
1969 dialog->SetUserItemID( aFootprint->m_Uuid );
1970
1971 LIB_ID fpID = aFootprint->GetFPID();
1972 wxString libName = fpID.GetLibNickname();
1973 wxString fpName = fpID.GetLibItemName();
1974 WX_HTML_REPORT_BOX* r = nullptr;
1975
1976 r = dialog->AddHTMLPage( _( "Summary" ) );
1977
1978 r->Report( wxS( "<h7>" ) + _( "Board vs library diff for:" ) + wxS( "</h7>" ) );
1979 r->Report( wxS( "<ul><li>" ) + EscapeHTML( getItemDescription( aFootprint ) ) + wxS( "</li>" )
1980 + wxS( "<li>" ) + _( "Library: " ) + EscapeHTML( libName ) + wxS( "</li>" )
1981 + wxS( "<li>" ) + _( "Library item: " ) + EscapeHTML( fpName ) + wxS( "</li></ul>" ) );
1982
1983 r->Report( "" );
1984
1985 PROJECT* project = aFootprint->GetBoard()->GetProject();
1987
1988 if( !adapter->HasLibrary( libName, false ) )
1989 {
1990 r->Report( _( "The library is not included in the current configuration." )
1991 + wxS( "&nbsp;&nbsp;&nbsp" )
1992 + wxS( "<a href='$CONFIG'>" ) + _( "Manage Footprint Libraries" )
1993 + wxS( "</a>" ) );
1994
1995 }
1996 else if( !adapter->HasLibrary( libName, true ) )
1997 {
1998 r->Report( _( "The library is not enabled in the current configuration." )
1999 + wxS( "&nbsp;&nbsp;&nbsp" )
2000 + wxS( "<a href='$CONFIG'>" ) + _( "Manage Footprint Libraries" )
2001 + wxS( "</a>" ) );
2002
2003 }
2004 else
2005 {
2006 std::shared_ptr<FOOTPRINT> libFootprint;
2007
2008 try
2009 {
2010 libFootprint.reset( adapter->LoadFootprint( libName, fpName, true ) );
2011 }
2012 catch( const IO_ERROR& )
2013 {
2014 }
2015
2016 if( !libFootprint )
2017 {
2018 r->Report( wxString::Format( _( "The library no longer contains the item %s." ),
2019 fpName) );
2020 }
2021 else
2022 {
2023 if( !aFootprint->FootprintNeedsUpdate( libFootprint.get(), 0, r ) )
2024 r->Report( _( "No relevant differences detected." ) );
2025
2026 wxPanel* panel = dialog->AddBlankPage( _( "Visual" ) );
2028
2029 diff->DisplayDiff( aFootprint, libFootprint );
2030 }
2031 }
2032
2033 r->Flush();
2034
2035 if( aReparentTo )
2036 KIPLATFORM::UI::ReparentWindow( dialog, aReparentTo );
2037 else
2038 dialog->Raise();
2039
2040 dialog->Show( true );
2041}
2042
2043
2045{
2046 wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
2047
2048 FOOTPRINT_DIFF_WIDGET* diffWidget = new FOOTPRINT_DIFF_WIDGET( aParentPanel, m_frame->Kiway() );
2049
2050 sizer->Add( diffWidget, 1, wxEXPAND | wxALL, 5 );
2051 aParentPanel->SetSizer( sizer );
2052 aParentPanel->Layout();
2053
2054 return diffWidget;
2055}
2056
2057
2059{
2060 BOARD_ITEM* item = aEvent.Parameter<BOARD_ITEM*>();
2061
2062 m_frame->m_ProbingSchToPcb = true; // recursion guard
2063 {
2064 m_toolMgr->RunAction( ACTIONS::selectionClear );
2065
2066 if( item )
2067 m_toolMgr->RunAction<EDA_ITEM*>( ACTIONS::selectItem, item );
2068 }
2069 m_frame->m_ProbingSchToPcb = false;
2070
2071 bool request3DviewRedraw = frame()->GetPcbNewSettings()->m_Display.m_Live3DRefresh;
2072
2073 if( item && item->Type() != PCB_FOOTPRINT_T )
2074 request3DviewRedraw = false;
2075
2076 // Update 3D viewer highlighting
2077 if( request3DviewRedraw )
2078 m_frame->Update3DView( false, true );
2079
2080 return 0;
2081}
2082
2083
2084 bool BOARD_INSPECTION_TOOL::highlightNet( const VECTOR2D& aPosition, bool aUseSelection )
2085{
2086 BOARD* board = static_cast<BOARD*>( m_toolMgr->GetModel() );
2088 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
2089
2090 int net = -1;
2091 bool enableHighlight = false;
2092
2093 if( aUseSelection )
2094 {
2095 const PCB_SELECTION& selection = selectionTool->GetSelection();
2096 std::set<int> netcodes;
2097
2098 for( EDA_ITEM* item : selection )
2099 {
2100 if( BOARD_CONNECTED_ITEM* ci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
2101 netcodes.insert( ci->GetNetCode() );
2102 }
2103
2104 enableHighlight = !netcodes.empty();
2105
2106 if( enableHighlight && netcodes.size() > 1 )
2107 {
2108 // If we are doing a multi-highlight, cross-probing back and other stuff is not
2109 // yet supported
2110 settings->SetHighlight( netcodes );
2111 board->ResetNetHighLight();
2112
2113 for( int multiNet : netcodes )
2114 board->SetHighLightNet( multiNet, true );
2115
2116 board->HighLightON();
2117 m_toolMgr->GetView()->UpdateAllLayersColor();
2118 m_currentlyHighlighted = netcodes;
2119 return true;
2120 }
2121 else if( enableHighlight )
2122 {
2123 net = *netcodes.begin();
2124 }
2125 }
2126
2127 // If we didn't get a net to highlight from the selection, use the cursor
2128 if( net < 0 )
2129 {
2130 GENERAL_COLLECTORS_GUIDE guide = m_frame->GetCollectorsGuide();
2131 guide.SetIgnoreZoneFills( false );
2132 guide.SetIgnoreNoNets( true );
2133
2134 PCB_LAYER_ID activeLayer = static_cast<PCB_LAYER_ID>( view()->GetTopLayer() );
2135 guide.SetPreferredLayer( activeLayer );
2136
2137 GENERAL_COLLECTOR collector;
2138 collector.Collect( board, { PCB_PAD_T, PCB_VIA_T, PCB_TRACE_T, PCB_ARC_T, PCB_SHAPE_T }, aPosition,
2139 guide );
2140
2141 if( collector.GetCount() == 0 )
2142 collector.Collect( board, { PCB_ZONE_T }, aPosition, guide );
2143
2144 // Apply the active selection filter, except we want to allow picking locked items for
2145 // highlighting even if the user has disabled them for selection
2146 PCB_SELECTION_FILTER_OPTIONS& filter = selectionTool->GetFilter();
2147
2148 bool saved = filter.lockedItems;
2149 filter.lockedItems = true;
2150
2151 selectionTool->FilterCollectedItems( collector, true, nullptr );
2152
2153 filter.lockedItems = saved;
2154
2155 // Clear the previous highlight
2156 //m_frame->SendMessageToEESCHEMA( nullptr );
2157
2158 bool highContrast = settings->GetHighContrast();
2159 PCB_LAYER_ID contrastLayer = settings->GetPrimaryHighContrastLayer();
2160
2161 for( int i = collector.GetCount() - 1; i >= 0; i-- )
2162 {
2163 LSET itemLayers = collector[i]->GetLayerSet();
2164
2165 if( ( itemLayers & LSET::AllCuMask() ).none() ||
2166 ( highContrast && !itemLayers.Contains( contrastLayer ) ) )
2167 {
2168 collector.Remove( i );
2169 continue;
2170 }
2171 }
2172
2173 enableHighlight = ( collector.GetCount() > 0 );
2174
2175 // Obtain net code for the clicked item
2176 if( enableHighlight )
2177 {
2178 BOARD_CONNECTED_ITEM* targetItem = static_cast<BOARD_CONNECTED_ITEM*>( collector[0] );
2179
2180 if( targetItem->Type() == PCB_PAD_T )
2181 m_frame->SendCrossProbeItem( targetItem );
2182
2183 net = targetItem->GetNetCode();
2184 }
2185 }
2186
2187 const std::set<int>& netcodes = settings->GetHighlightNetCodes();
2188
2189 if( !aUseSelection && net >= 0 && netcodes.size() == 1 && netcodes.contains( net ) && settings->IsHighlightEnabled() )
2190 {
2191 if( BOARD* board2 = m_frame->GetBoard() )
2192 {
2193 if( NETINFO_ITEM* netinfo = board2->FindNet( net ) )
2194 {
2195 wxString sig = netinfo->GetNetChain();
2196 if( !sig.IsEmpty() )
2197 {
2198 int count = 0;
2199 for( NETINFO_ITEM* n : board2->GetNetInfo() )
2200 if( n->GetNetChain() == sig )
2201 count++;
2202
2203 if( count > 1 )
2204 {
2205 std::set<int> sigCodes;
2206
2207
2208 for( NETINFO_ITEM* n : board2->GetNetInfo() )
2209 if( n->GetNetChain() == sig )
2210 sigCodes.insert( n->GetNetCode() );
2211
2212 settings->SetHighlight( sigCodes, true );
2213 m_toolMgr->GetView()->UpdateAllLayersColor();
2214 m_currentlyHighlighted = sigCodes;
2216
2217 board2->ResetNetHighLight();
2218 for( int c : sigCodes )
2219 board2->SetHighLightNet( c, true );
2220 board2->HighLightON();
2221
2222 if( auto pcbSettings = dynamic_cast<KIGFX::PCB_RENDER_SETTINGS*>( settings ) )
2223 pcbSettings->SetHighlightedNetChain( sig );
2224
2225 return true;
2226 }
2227 }
2228 }
2229 }
2230
2231 enableHighlight = !settings->IsHighlightEnabled();
2232 }
2233 else if( !aUseSelection && netcodes.size() == 1 && netcodes.contains( net ) )
2234 {
2235 enableHighlight = !settings->IsHighlightEnabled();
2236 }
2237
2238 if( enableHighlight != settings->IsHighlightEnabled() || !netcodes.count( net ) )
2239 {
2240 if( !netcodes.empty() )
2241 m_lastHighlighted = netcodes;
2242
2243 settings->SetHighlight( enableHighlight, net );
2244 m_toolMgr->GetView()->UpdateAllLayersColor();
2245 }
2246
2247 // Store the highlighted netcode in the current board (for dialogs for instance)
2248 if( enableHighlight && net >= 0 )
2249 {
2250 m_currentlyHighlighted = netcodes;
2251 board->SetHighLightNet( net );
2252 board->HighLightON();
2253
2254 NETINFO_ITEM* netinfo = board->FindNet( net );
2255
2256 if( netinfo )
2257 {
2258 std::vector<MSG_PANEL_ITEM> items;
2259 netinfo->GetMsgPanelInfo( m_frame, items );
2260 m_frame->SetMsgPanel( items );
2261 m_frame->SendCrossProbeNetName( netinfo->GetNetname() );
2262 }
2263 }
2264 else
2265 {
2266 m_currentlyHighlighted.clear();
2267 board->ResetNetHighLight();
2268 m_frame->SetMsgPanel( board );
2269 m_frame->SendCrossProbeNetName( "" );
2270 }
2271
2272 return true;
2273}
2274
2275
2277{
2278 int netcode = aEvent.Parameter<int>();
2279 KIGFX::RENDER_SETTINGS* settings = m_toolMgr->GetView()->GetPainter()->GetSettings();
2280 const std::set<int>& highlighted = settings->GetHighlightNetCodes();
2281
2282 if( netcode > 0 )
2283 {
2284 m_lastHighlighted = highlighted;
2285 settings->SetHighlight( true, netcode );
2286 m_toolMgr->GetView()->UpdateAllLayersColor();
2287 m_currentlyHighlighted.clear();
2288 m_currentlyHighlighted.insert( netcode );
2289
2290 // If this net belongs to a multi-net chain and was already highlighted, escalate to chain highlight
2291 if( BOARD* board = m_frame->GetBoard() )
2292 {
2293 if( NETINFO_ITEM* net = board->FindNet( netcode ) )
2294 {
2295 wxString sig = net->GetNetChain();
2296 if( !sig.IsEmpty() )
2297 {
2298 int count = 0;
2299 for( NETINFO_ITEM* n : board->GetNetInfo() )
2300 if( n->GetNetChain() == sig )
2301 count++;
2302 bool alreadyHighlighted = highlighted.count( netcode );
2303 if( count > 1 && alreadyHighlighted )
2304 {
2305 if( m_highlightedNetChain != sig )
2306 {
2307 TOOL_EVENT sigEvt = PCB_ACTIONS::highlightNetChain.MakeEvent();
2308 HighlightNetChain( sigEvt );
2309 }
2310 }
2311 }
2312 }
2313 }
2314 }
2315 else if( aEvent.IsAction( &PCB_ACTIONS::highlightNetSelection ) )
2316 {
2317 // Highlight selection (cursor position will be ignored)
2318 highlightNet( getViewControls()->GetMousePosition(), true );
2319 }
2320 else if( aEvent.IsAction( &PCB_ACTIONS::toggleLastNetHighlight ) )
2321 {
2322 std::set<int> temp = highlighted;
2323 settings->SetHighlight( m_lastHighlighted );
2324 m_toolMgr->GetView()->UpdateAllLayersColor();
2326 m_lastHighlighted = std::move( temp );
2327 }
2328 else if( aEvent.IsAction( &PCB_ACTIONS::toggleNetHighlight ) )
2329 {
2330 bool turnOn = highlighted.empty() && !m_currentlyHighlighted.empty();
2331 settings->SetHighlight( m_currentlyHighlighted, turnOn );
2332 m_toolMgr->GetView()->UpdateAllLayersColor();
2333 }
2334 else // Highlight the net belonging to the item under the cursor
2335 {
2336 highlightNet( getViewControls()->GetMousePosition(), false );
2337 }
2338
2339 return 0;
2340}
2341
2342
2344{
2346 VECTOR2D cursorPos = controls->GetCursorPosition( !aEvent.DisableGridSnapping() );
2347 BOARD_ITEM* item = nullptr;
2348 {
2349 // Collect nearest connectable item at cursor position
2350 BOARD* board = m_frame->GetBoard();
2351 GENERAL_COLLECTORS_GUIDE guide = m_frame->GetCollectorsGuide();
2352 GENERAL_COLLECTOR collector;
2353 collector.Collect( board, { PCB_PAD_T, PCB_VIA_T, PCB_TRACE_T, PCB_ARC_T, PCB_SHAPE_T }, cursorPos,
2354 guide );
2355
2356 if( collector.GetCount() > 0 )
2357 item = static_cast<BOARD_ITEM*>( collector[0] );
2358 }
2359 wxString sig;
2360
2361 if( item )
2362 {
2363 NETINFO_ITEM* net = nullptr;
2364
2365 if( auto pad = dynamic_cast<PAD*>( item ) )
2366 net = pad->GetNet();
2367 else if( auto ci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
2368 net = ci->GetNet();
2369
2370 if( net )
2371 sig = net->GetNetChain();
2372 }
2373
2374 KIGFX::RENDER_SETTINGS* settings = m_toolMgr->GetView()->GetPainter()->GetSettings();
2375
2376 // If no chain under cursor and a chain is currently highlighted, toggle off
2377 if( sig.IsEmpty() && !m_highlightedNetChain.IsEmpty() )
2378 {
2379 m_highlightedNetChain.clear();
2380 settings->SetHighlight( false );
2381 m_currentlyHighlighted.clear();
2382 m_toolMgr->GetView()->UpdateAllLayersColor();
2383 if( auto pcbSettings = dynamic_cast<KIGFX::PCB_RENDER_SETTINGS*>( settings ) )
2384 pcbSettings->SetHighlightedNetChain( wxString() );
2385 return 0;
2386 }
2387
2388 // If same chain already highlighted, clear highlight
2389 if( !sig.IsEmpty() && sig == m_highlightedNetChain )
2390 {
2391 m_highlightedNetChain.clear();
2392 settings->SetHighlight( false );
2393 m_currentlyHighlighted.clear();
2394 m_toolMgr->GetView()->UpdateAllLayersColor();
2395 if( auto pcbSettings = dynamic_cast<KIGFX::PCB_RENDER_SETTINGS*>( settings ) )
2396 pcbSettings->SetHighlightedNetChain( wxString() );
2397 return 0;
2398 }
2399
2400 // If we have a net highlight active but no chain highlight, convert to chain highlight
2401 if( !sig.IsEmpty() && m_highlightedNetChain.IsEmpty() && !m_currentlyHighlighted.empty() )
2402 {
2403 // Determine chain from first highlighted net if cursor item had no chain
2404 if( sig.IsEmpty() )
2405 {
2406 int firstCode = *m_currentlyHighlighted.begin();
2407 if( NETINFO_ITEM* net = m_frame->GetBoard()->FindNet( firstCode ) )
2408 sig = net->GetNetChain();
2409 }
2410 }
2411
2413 if( auto pcbSettings = dynamic_cast<KIGFX::PCB_RENDER_SETTINGS*>( settings ) )
2414 pcbSettings->SetHighlightedNetChain( sig );
2415
2416 std::set<int> codes;
2417 if( !sig.IsEmpty() )
2418 {
2419 for( NETINFO_ITEM* net : m_frame->GetBoard()->GetNetInfo() )
2420 {
2421 if( net->GetNetChain() == sig )
2422 codes.insert( net->GetNetCode() );
2423 }
2424 }
2425
2426 settings->SetHighlight( codes, true );
2427 m_toolMgr->GetView()->UpdateAllLayersColor();
2428 m_currentlyHighlighted = codes;
2429
2430 return 0;
2431}
2432
2433
2435{
2436 if( m_highlightedNetChain.IsEmpty() )
2437 return 0;
2438
2439 // Parameters are passed as a single pair<old,new>
2440 auto ids = aEvent.Parameter<std::pair<wxString, wxString>>();
2441 KIID oldId( ids.first );
2442 KIID newId( ids.second );
2443 m_frame->GetBoard()->ReplaceNetChainTerminalPad( m_highlightedNetChain, oldId, newId );
2444 return 0;
2445}
2446
2447
2449{
2450 BOARD* board = static_cast<BOARD*>( m_toolMgr->GetModel() );
2451 KIGFX::RENDER_SETTINGS* settings = m_toolMgr->GetView()->GetPainter()->GetSettings();
2452
2453 m_currentlyHighlighted.clear();
2454 m_lastHighlighted.clear();
2455
2456 board->ResetNetHighLight();
2457 settings->SetHighlight( false );
2458 // Also clear any chain-specific state
2459 if( auto pcbSettings = dynamic_cast<KIGFX::PCB_RENDER_SETTINGS*>( settings ) )
2460 pcbSettings->SetHighlightedNetChain( wxString() );
2461 m_toolMgr->GetView()->UpdateAllLayersColor();
2462 m_frame->SetMsgPanel( board );
2463 m_frame->SendCrossProbeNetName( "" );
2464 return 0;
2465}
2466
2467
2469{
2470 PCB_PICKER_TOOL* picker = m_toolMgr->GetTool<PCB_PICKER_TOOL>();
2471
2472 // Deactivate other tools; particularly important if another PICKER is currently running
2473 Activate();
2474
2475 picker->SetCursor( KICURSOR::BULLSEYE );
2476 picker->SetSnapping( false );
2477 picker->ClearHandlers();
2478
2479 picker->SetClickHandler(
2480 [this]( const VECTOR2D& pt ) -> bool
2481 {
2482 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
2483
2484 m_toolMgr->RunAction( ACTIONS::selectionClear );
2486 EDIT_TOOL::PadFilter );
2487
2488 PCB_SELECTION& selection = selectionTool->GetSelection();
2489
2490 if( selection.Empty() )
2491 {
2493 EDIT_TOOL::FootprintFilter );
2494 selection = selectionTool->GetSelection();
2495 }
2496
2497 if( selection.Empty() )
2498 {
2499 // Clear the previous local ratsnest if we click off all items
2500 for( FOOTPRINT* fp : getModel<BOARD>()->Footprints() )
2501 {
2502 for( PAD* pad : fp->Pads() )
2503 pad->SetLocalRatsnestVisible( displayOptions().m_ShowGlobalRatsnest );
2504 }
2505 }
2506 else
2507 {
2508 for( EDA_ITEM* item : selection )
2509 {
2510 if( PAD* pad = dyn_cast<PAD*>( item) )
2511 {
2512 pad->SetLocalRatsnestVisible( !pad->GetLocalRatsnestVisible() );
2513 }
2514 else if( FOOTPRINT* fp = dyn_cast<FOOTPRINT*>( item) )
2515 {
2516 if( !fp->Pads().empty() )
2517 {
2518 bool enable = !fp->Pads()[0]->GetLocalRatsnestVisible();
2519
2520 for( PAD* childPad : fp->Pads() )
2521 childPad->SetLocalRatsnestVisible( enable );
2522 }
2523 }
2524 }
2525 }
2526
2527 m_toolMgr->GetView()->MarkTargetDirty( KIGFX::TARGET_OVERLAY );
2528
2529 return true;
2530 } );
2531
2532 picker->SetFinalizeHandler(
2533 [this]( int aCondition )
2534 {
2535 if( aCondition != PCB_PICKER_TOOL::END_ACTIVATE )
2536 {
2537 for( FOOTPRINT* fp : getModel<BOARD>()->Footprints() )
2538 {
2539 for( PAD* pad : fp->Pads() )
2540 pad->SetLocalRatsnestVisible( displayOptions().m_ShowGlobalRatsnest );
2541 }
2542 }
2543 } );
2544
2545 m_toolMgr->RunAction( ACTIONS::pickerTool, &aEvent );
2546
2547 return 0;
2548}
2549
2550
2552{
2553 VECTOR2I delta = aEvent.Parameter<VECTOR2I>();
2554
2555 if( delta == VECTOR2I() )
2556 {
2557 // We can delete the existing map to force a recalculation
2558 delete m_dynamicData;
2559 m_dynamicData = nullptr;
2560 }
2561
2562 auto selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
2563 auto& selection = selectionTool->GetSelection();
2564 auto connectivity = getModel<BOARD>()->GetConnectivity();
2565
2566 if( selection.Empty() )
2567 {
2568 connectivity->ClearLocalRatsnest();
2569 delete m_dynamicData;
2570 m_dynamicData = nullptr;
2571 }
2572 else
2573 {
2575 }
2576
2577 return 0;
2578}
2579
2580
2582{
2583 getModel<BOARD>()->GetConnectivity()->ClearLocalRatsnest();
2584 delete m_dynamicData;
2585 m_dynamicData = nullptr;
2586
2587 return 0;
2588}
2589
2590
2592{
2593 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
2594 SELECTION& selection = selectionTool->GetSelection();
2595 std::shared_ptr<CONNECTIVITY_DATA> connectivity = board()->GetConnectivity();
2596 std::vector<BOARD_ITEM*> items;
2597 std::deque<EDA_ITEM*> queued_items( selection.begin(), selection.end() );
2598
2599 for( std::size_t i = 0; i < queued_items.size(); ++i )
2600 {
2601 if( !queued_items[i]->IsBOARD_ITEM() )
2602 continue;
2603
2604 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( queued_items[i] );
2605
2606 wxCHECK2( item, continue );
2607
2608 if( item->Type() == PCB_FOOTPRINT_T )
2609 {
2610 for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
2611 {
2612 if( pad->GetLocalRatsnestVisible() || displayOptions().m_ShowModuleRatsnest )
2613 items.push_back( pad );
2614 }
2615 }
2616 else if( item->Type() == PCB_GROUP_T || item->Type() == PCB_GENERATOR_T )
2617 {
2618 item->RunOnChildren( [ &queued_items ]( BOARD_ITEM *aItem )
2619 {
2620 queued_items.push_back( aItem );
2621 },
2623 }
2624 else if( BOARD_CONNECTED_ITEM* boardItem = dyn_cast<BOARD_CONNECTED_ITEM*>( item ) )
2625 {
2626 if( boardItem->GetLocalRatsnestVisible() || displayOptions().m_ShowModuleRatsnest )
2627 items.push_back( boardItem );
2628 }
2629 }
2630
2631 if( items.empty() || std::none_of( items.begin(), items.end(),
2632 []( const BOARD_ITEM* aItem )
2633 {
2634 return( aItem->Type() == PCB_TRACE_T
2635 || aItem->Type() == PCB_PAD_T
2636 || aItem->Type() == PCB_ARC_T
2637 || aItem->Type() == PCB_ZONE_T
2638 || aItem->Type() == PCB_FOOTPRINT_T
2639 || aItem->Type() == PCB_VIA_T
2640 || aItem->Type() == PCB_SHAPE_T );
2641 } ) )
2642 {
2643 return;
2644 }
2645
2646 if( !m_dynamicData )
2647 {
2648 m_dynamicData = new CONNECTIVITY_DATA( board()->GetConnectivity(), items, true );
2649 connectivity->BlockRatsnestItems( items );
2650 }
2651 else
2652 {
2653 m_dynamicData->Move( aDelta );
2654 }
2655
2656 connectivity->ComputeLocalRatsnest( items, m_dynamicData );
2657}
2658
2659
2661{
2662 doHideRatsnestNet( aEvent.Parameter<int>(), true );
2663 return 0;
2664}
2665
2666
2668{
2669 doHideRatsnestNet( aEvent.Parameter<int>(), false );
2670 return 0;
2671}
2672
2673
2674void BOARD_INSPECTION_TOOL::doHideRatsnestNet( int aNetCode, bool aHide )
2675{
2677 m_toolMgr->GetView()->GetPainter()->GetSettings() );
2678
2679 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
2680 SELECTION& selection = selectionTool->GetSelection();
2681
2682 if( aNetCode <= 0 && !selection.Empty() )
2683 {
2684 for( EDA_ITEM* item : selection )
2685 {
2686 if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
2687 {
2688 if( bci->GetNetCode() > 0 )
2689 doHideRatsnestNet( bci->GetNetCode(), aHide );
2690 }
2691 }
2692
2693 return;
2694 }
2695
2696 if( aHide )
2697 rs->GetHiddenNets().insert( aNetCode );
2698 else
2699 rs->GetHiddenNets().erase( aNetCode );
2700
2701 if( !m_frame->GetAppearancePanel()->IsTogglingNetclassRatsnestVisibility() )
2702 {
2703 m_frame->GetCanvas()->RedrawRatsnest();
2704 m_frame->GetCanvas()->Refresh();
2705
2706 m_frame->GetAppearancePanel()->OnNetVisibilityChanged( aNetCode, !aHide );
2707 }
2708}
2709
2710
2712{
2716
2722
2731
2734}
std::function< void(const VECTOR2I &, GENERAL_COLLECTOR &, PCB_SELECTION_TOOL *)> CLIENT_SELECTION_FILTER
Definition actions.h:37
#define EVAL_RULES(constraint, a, b, layer, r)
wxString reportMax(PCB_BASE_FRAME *aFrame, DRC_CONSTRAINT &aConstraint)
bool isNPTHPad(BOARD_ITEM *aItem)
wxString reportMin(PCB_BASE_FRAME *aFrame, DRC_CONSTRAINT &aConstraint)
wxString reportOpt(PCB_BASE_FRAME *aFrame, DRC_CONSTRAINT &aConstraint)
static TOOL_ACTION selectItem
Select an item (specified as the event parameter).
Definition actions.h:227
static TOOL_ACTION selectionCursor
Select a single item under the cursor position.
Definition actions.h:217
static TOOL_ACTION pickerTool
Definition actions.h:253
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:224
ACTION_MENU(bool isContextMenu, TOOL_INTERACTIVE *aTool=nullptr)
Default constructor.
void SetTitle(const wxString &aTitle) override
Set title for the menu.
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
wxMenuItem * Add(const wxString &aLabel, int aId, BITMAPS aIcon)
Add a wxWidgets-style entry to the menu.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
virtual NETCLASS * GetEffectiveNetClass() const
Return the NETCLASS for this item.
NETINFO_ITEM * GetNet() const
Return #NET_INFO object for a given item.
void InspectDRCError(const std::shared_ptr< RC_ITEM > &aDRCItem)
Show the clearance resolution for two selected items.
int HighlightNet(const TOOL_EVENT &aEvent)
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 HighlightNetChain(const TOOL_EVENT &aEvent)
int DiffFootprint(const TOOL_EVENT &aEvent)
void reportClearance(BOARD_ITEM *aItemA, BOARD_ITEM *aItemB)
int LocalRatsnestTool(const TOOL_EVENT &aEvent)
Hide the ratsnest for a given net.
bool Init() override
Init() is called once upon a registration of the tool.
int ShowNetInRatsnest(const TOOL_EVENT &aEvent)
void reportCompileError(REPORTER *r)
int ClearHighlight(const TOOL_EVENT &aEvent)
Perform the appropriate action in response to an Eeschema cross-probe.
std::unique_ptr< DRC_ENGINE > makeDRCEngine(bool *aCompileError, bool *aCourtyardError)
int HideNetInRatsnest(const TOOL_EVENT &aEvent)
Show the ratsnest for a given net.
int InspectConstraints(const TOOL_EVENT &aEvent)
void doHideRatsnestNet(int aNetCode, bool aHide)
Bind handlers to corresponding TOOL_ACTIONs.
BOARD_ITEM * pickItemForInspection(const TOOL_EVENT &aEvent, const wxString &aPrompt, const std::vector< KICAD_T > &aTypes, BOARD_ITEM *aLockedHighlight)
wxString getItemDescription(BOARD_ITEM *aItem)
CONNECTIVITY_DATA * m_dynamicData
int ReplaceTerminalPad(const TOOL_EVENT &aEvent)
Clear all board highlights.
int ShowFootprintLinks(const TOOL_EVENT &aEvent)
void reportHeader(const wxString &aTitle, BOARD_ITEM *a, REPORTER *r)
void filterCollectorForInspection(GENERAL_COLLECTOR &aCollector, const VECTOR2I &aPos)
FOOTPRINT_DIFF_WIDGET * constructDiffPanel(wxPanel *aParentPanel)
int InspectClearance(const TOOL_EVENT &aEvent)
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
std::set< int > m_currentlyHighlighted
int UpdateLocalRatsnest(const TOOL_EVENT &aEvent)
Hide ratsnest for selected items. Called when there are no items selected.
int HideLocalRatsnest(const TOOL_EVENT &aEvent)
Show local ratsnest of a component.
int HighlightItem(const TOOL_EVENT &aEvent)
Update ratsnest for selected items.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition board_item.h:268
virtual bool IsConnected() const
Returns information if the object is derived from BOARD_CONNECTED_ITEM.
Definition board_item.h:158
virtual void Move(const VECTOR2I &aMoveVector)
Move this object.
Definition board_item.h:375
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Test to see if this object is on the given layer.
Definition board_item.h:350
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:288
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:197
virtual void RunOnChildren(const std::function< void(BOARD_ITEM *)> &aFunction, RECURSE_MODE aMode) const
Invoke a function on all children.
Definition board_item.h:232
virtual bool HasDrilledHole() const
Definition board_item.h:185
virtual bool IsOnCopperLayer() const
Definition board_item.h:175
virtual bool HasHole() const
Definition board_item.h:180
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:323
PROJECT * GetProject() const
Definition board.h:587
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition board.h:571
int GetCount() const
Return the number of objects in the list.
Definition collector.h:83
void Remove(int aIndex)
Remove the item at aIndex (first position is 0).
Definition collector.h:111
void Append(EDA_ITEM *item)
Add an item to the end of the list.
Definition collector.h:101
void AddMenu(ACTION_MENU *aMenu, const SELECTION_CONDITION &aCondition=SELECTION_CONDITIONS::ShowAlways, int aOrder=ANY_ORDER)
Add a submenu to the menu.
Dialog to show common board info.
wxPanel * AddBlankPage(const wxString &aTitle)
WX_HTML_REPORT_BOX * AddHTMLPage(const wxString &aTitle)
void SetUserItemID(const KIID &aID)
Dialog to show footprint library and symbol links.
bool Show(bool show) override
int ShowModal() override
wxString GetName() const
Definition drc_rule.h:208
int m_DisallowFlags
Definition drc_rule.h:245
ZONE_CONNECTION m_ZoneConnection
Definition drc_rule.h:246
MINOPTMAX< int > m_Value
Definition drc_rule.h:244
bool IsNull() const
Definition drc_rule.h:195
static int MatchDpSuffix(const wxString &aNetName, wxString &aComplementNet, wxString &aBaseDpName)
Check if the given net is a diff pair, returning its polarity and complement if so.
DIALOG_DRC * GetDRCDialog()
Definition drc_tool.h:64
std::unordered_set< EDA_ITEM * > & GetItems()
Definition eda_group.h:54
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:100
virtual wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const
Return a user-visible description string of this item.
Definition eda_item.cpp:154
const KIID m_Uuid
Definition eda_item.h:528
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:112
virtual bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const
Test if aPosition is inside or on the boundary of this item.
Definition eda_item.h:240
void DisplayDiff(FOOTPRINT *aBoardFootprint, std::shared_ptr< FOOTPRINT > &aLibFootprint)
Set the currently displayed symbol.
An interface to the global shared library manager that is schematic-specific and linked to one projec...
FOOTPRINT * LoadFootprint(const wxString &aNickname, const wxString &aName, bool aKeepUUID)
Load a FOOTPRINT having aName from the library given by aNickname.
bool FootprintNeedsUpdate(const FOOTPRINT *aLibFP, int aCompareFlags=0, REPORTER *aReporter=nullptr)
Return true if a board footprint differs from the library version.
const LIB_ID & GetFPID() const
Definition footprint.h:429
const SHAPE_POLY_SET & GetCourtyard(PCB_LAYER_ID aLayer) const
Used in DRC to test the courtyard area (a complex polygon).
A general implementation of a COLLECTORS_GUIDE.
Definition collectors.h:324
void SetIgnoreZoneFills(bool ignore)
Definition collectors.h:473
void SetPreferredLayer(PCB_LAYER_ID aLayer)
Definition collectors.h:390
void SetIgnoreNoNets(bool ignore)
Definition collectors.h:476
Used when the right click button is pressed, or when the select tool is in effect.
Definition collectors.h:207
void Collect(BOARD_ITEM *aItem, const std::vector< KICAD_T > &aScanList, const VECTOR2I &aRefPos, const COLLECTORS_GUIDE &aGuide)
Scan a BOARD_ITEM using this class's Inspector method, which does the collection.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
PCB specific render settings.
Definition pcb_painter.h:82
std::set< int > & GetHiddenNets()
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
const std::set< int > & GetHighlightNetCodes() const
Return the netcode of currently highlighted net.
PCB_LAYER_ID GetPrimaryHighContrastLayer() const
Return the board layer which is in high-contrast mode.
bool IsHighlightEnabled() const
Return current highlight setting.
void SetHighlight(bool aEnabled, int aNetcode=-1, bool aMulti=false)
Turns on/off highlighting.
An interface for classes handling user events controlling the view behavior such as zooming,...
virtual int GetTopLayer() const
Definition view.cpp:903
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition view.h:229
Definition kiid.h:48
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library tables.
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:49
const UTF8 & GetLibItemName() const
Definition lib_id.h:102
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:87
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:608
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition lset.cpp:313
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:599
static const LSET & PhysicalLayersMask()
Return a mask holding all layers which are physically realized.
Definition lset.cpp:697
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
Definition lset.h:63
T Min() const
Definition minoptmax.h:33
bool HasMax() const
Definition minoptmax.h:38
bool HasMin() const
Definition minoptmax.h:37
T Max() const
Definition minoptmax.h:34
T Opt() const
Definition minoptmax.h:35
bool HasOpt() const
Definition minoptmax.h:39
const wxString GetHumanReadableName() const
Gets the consolidated name of this netclass (which may be an aggregate).
Definition netclass.cpp:294
Handle the data for a net.
Definition netinfo.h:50
const wxString & GetNetChain() const
Definition netinfo.h:115
const wxString & GetNetname() const
Definition netinfo.h:103
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Return the information about the NETINFO_ITEM in aList to display in the message panel.
ACTION_MENU * create() const override
Return an instance of this class. It has to be overridden in inheriting classes.
Definition pad.h:55
const VECTOR2I & GetDrillSize() const
Definition pad.h:317
PAD_ATTRIB GetAttribute() const
Definition pad.h:563
static TOOL_ACTION highlightItem
static TOOL_ACTION toggleNetHighlight
static TOOL_ACTION setTerminalPad
static TOOL_ACTION highlightNet
static TOOL_ACTION hideNetInRatsnest
static TOOL_ACTION hideLocalRatsnest
static TOOL_ACTION showNetInRatsnest
static TOOL_ACTION highlightNetChain
static TOOL_ACTION toggleLastNetHighlight
static TOOL_ACTION inspectConstraints
static TOOL_ACTION clearHighlight
static TOOL_ACTION inspectClearance
static TOOL_ACTION updateLocalRatsnest
static TOOL_ACTION diffFootprint
static TOOL_ACTION showFootprintAssociations
static TOOL_ACTION highlightNetSelection
static TOOL_ACTION boardStatistics
static TOOL_ACTION localRatsnestTool
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
A set of BOARD_ITEMs (i.e., without duplicates).
Definition pcb_group.h:53
Generic tool for picking an item.
The selection tool: currently supports:
void GuessSelectionCandidates(GENERAL_COLLECTOR &aCollector, const VECTOR2I &aWhere) const
Try to guess best selection candidates in case multiple items are clicked, by doing some brain-dead h...
PCB_SELECTION & RequestSelection(CLIENT_SELECTION_FILTER aClientFilter)
Return the current selection, filtered according to aClientFilter.
bool Selectable(const BOARD_ITEM *aItem, bool checkVisibilityOnly=false) const
PCB_SELECTION_FILTER_OPTIONS & GetFilter()
Set up handlers for various events.
PCB_SELECTION & GetSelection()
void FilterCollectedItems(GENERAL_COLLECTOR &aCollector, bool aMultiSelect, PCB_SELECTION_FILTER_OPTIONS *aRejected=nullptr)
Apply the SELECTION_FITLER_OPTIONS to the collector.
T * frame() const
KIGFX::PCB_VIEW * view() const
KIGFX::VIEW_CONTROLS * controls() const
PCB_TOOL_BASE(TOOL_ID aId, const std::string &aName)
Constructor.
BOARD * board() const
PCBNEW_SETTINGS::DISPLAY_OPTIONS & displayOptions() const
const PCB_SELECTION & selection() const
FOOTPRINT * footprint() const
void SetClickHandler(CLICK_HANDLER aHandler)
Set a handler for mouse click event.
Definition picker_tool.h:81
void SetSnapping(bool aSnap)
Definition picker_tool.h:66
void SetCursor(KICURSOR aCursor)
Definition picker_tool.h:64
void SetFinalizeHandler(FINALIZE_HANDLER aHandler)
Set a handler for the finalize event.
static FOOTPRINT_LIBRARY_ADAPTER * FootprintLibAdapter(PROJECT *aProject)
Container for project specific data.
Definition project.h:66
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:75
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition reporter.h:104
void BrightenItem(EDA_ITEM *aItem)
void UnbrightenItem(EDA_ITEM *aItem)
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
Extension of STATUS_POPUP for displaying a single line text.
T * getEditFrame() const
Return the application window object, casted to requested user type.
Definition tool_base.h:186
T * getModel() const
Return the model object if it matches the requested type.
Definition tool_base.h:198
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition tool_base.cpp:44
TOOL_MANAGER * m_toolMgr
Definition tool_base.h:220
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition tool_base.cpp:38
RESET_REASON
Determine the reason of reset for a tool.
Definition tool_base.h:78
Generic, UI-independent tool event.
Definition tool_event.h:171
bool DisableGridSnapping() const
Definition tool_event.h:371
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
T Parameter() const
Return a parameter assigned to the event.
Definition tool_event.h:473
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
TOOL_MENU & GetToolMenu()
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Suspend execution of the tool until an event specified in aEventList arrives.
void Activate()
Run the tool.
CONDITIONAL_MENU & GetMenu()
Definition tool_menu.cpp:44
void RegisterSubMenu(std::shared_ptr< ACTION_MENU > aSubMenu)
Store a submenu of this menu model.
Definition tool_menu.cpp:50
wxString StringFromValue(double aValue, bool aAddUnitLabel=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
Converts aValue in internal units into a united string.
A slimmed down version of WX_HTML_REPORT_PANEL.
void Clear() override
Delete the stored messages.
REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED) override
Report a string with a given severity.
void SetUnits(EDA_UNITS aUnits)
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:936
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Test to see if this object is on the given layer.
Definition zone.cpp:734
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition zone.h:137
@ BULLSEYE
Definition cursors.h:58
@ DRCE_HOLE_CLEARANCE
Definition drc_item.h:55
@ DRCE_VIA_DIAMETER
Definition drc_item.h:62
@ DRCE_TRACK_WIDTH
Definition drc_item.h:56
@ DRCE_DRILL_OUT_OF_RANGE
Definition drc_item.h:61
@ DRCE_EDGE_CLEARANCE
Definition drc_item.h:47
@ DRCE_STARVED_THERMAL
Definition drc_item.h:50
@ DRCE_TRACK_SEGMENT_LENGTH
Definition drc_item.h:58
@ DRCE_TRACK_ANGLE
Definition drc_item.h:57
@ DRCE_CLEARANCE
Definition drc_item.h:44
@ DRCE_DRILLED_HOLES_TOO_CLOSE
Definition drc_item.h:53
@ DRCE_DIFF_PAIR_UNCOUPLED_LENGTH_TOO_LONG
Definition drc_item.h:110
@ DRCE_MICROVIA_DRILL_OUT_OF_RANGE
Definition drc_item.h:65
@ DRCE_TEXT_HEIGHT
Definition drc_item.h:101
@ DRCE_ASSERTION_FAILURE
Definition drc_item.h:89
@ DRCE_LIB_FOOTPRINT_MISMATCH
Definition drc_item.h:84
@ DRCE_TEXT_THICKNESS
Definition drc_item.h:102
@ DRCE_CONNECTION_WIDTH
Definition drc_item.h:60
@ DRCE_ANNULAR_WIDTH
Definition drc_item.h:59
@ ANNULAR_WIDTH_CONSTRAINT
Definition drc_rule.h:67
@ COURTYARD_CLEARANCE_CONSTRAINT
Definition drc_rule.h:61
@ VIA_DIAMETER_CONSTRAINT
Definition drc_rule.h:76
@ DIFF_PAIR_GAP_CONSTRAINT
Definition drc_rule.h:82
@ DISALLOW_CONSTRAINT
Definition drc_rule.h:75
@ TRACK_WIDTH_CONSTRAINT
Definition drc_rule.h:65
@ SILK_CLEARANCE_CONSTRAINT
Definition drc_rule.h:62
@ EDGE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:59
@ MIN_RESOLVED_SPOKES_CONSTRAINT
Definition drc_rule.h:71
@ TRACK_SEGMENT_LENGTH_CONSTRAINT
Definition drc_rule.h:66
@ TEXT_THICKNESS_CONSTRAINT
Definition drc_rule.h:64
@ PHYSICAL_HOLE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:87
@ CLEARANCE_CONSTRAINT
Definition drc_rule.h:55
@ THERMAL_SPOKE_WIDTH_CONSTRAINT
Definition drc_rule.h:70
@ CONNECTION_WIDTH_CONSTRAINT
Definition drc_rule.h:89
@ THERMAL_RELIEF_GAP_CONSTRAINT
Definition drc_rule.h:69
@ MAX_UNCOUPLED_CONSTRAINT
Definition drc_rule.h:83
@ HOLE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:57
@ SOLDER_PASTE_ABS_MARGIN_CONSTRAINT
Definition drc_rule.h:73
@ SOLDER_MASK_EXPANSION_CONSTRAINT
Definition drc_rule.h:72
@ TRACK_ANGLE_CONSTRAINT
Definition drc_rule.h:90
@ HOLE_SIZE_CONSTRAINT
Definition drc_rule.h:60
@ TEXT_HEIGHT_CONSTRAINT
Definition drc_rule.h:63
@ PHYSICAL_CLEARANCE_CONSTRAINT
Definition drc_rule.h:86
@ SOLDER_PASTE_REL_MARGIN_CONSTRAINT
Definition drc_rule.h:74
@ HOLE_TO_HOLE_CONSTRAINT
Definition drc_rule.h:58
#define _(s)
@ RECURSE
Definition eda_item.h:53
#define MALFORMED_COURTYARDS
EDA_UNITS
Definition eda_units.h:48
bool IsFrontLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a front layer.
Definition layer_ids.h:782
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:679
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ F_CrtYd
Definition layer_ids.h:116
@ Edge_Cuts
Definition layer_ids.h:112
@ B_Mask
Definition layer_ids.h:98
@ B_Cu
Definition layer_ids.h:65
@ F_Mask
Definition layer_ids.h:97
@ Margin
Definition layer_ids.h:113
@ F_SilkS
Definition layer_ids.h:100
@ B_CrtYd
Definition layer_ids.h:115
@ UNDEFINED_LAYER
Definition layer_ids.h:61
@ B_SilkS
Definition layer_ids.h:101
@ F_Cu
Definition layer_ids.h:64
@ TARGET_OVERLAY
Items that may change while the view stays the same (noncached)
Definition definitions.h:39
void ReparentWindow(wxNonOwnedWindow *aWindow, wxTopLevelWindow *aParent)
Definition wxgtk/ui.cpp:174
wxPoint GetMousePosition()
Returns the mouse position in screen coordinates.
Definition wxgtk/ui.cpp:721
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:103
@ SMD
Smd pad, appears on the solder paste layer (default)
Definition padstack.h:99
Class to handle a set of BOARD_ITEMs.
SEVERITY
@ RPT_SEVERITY_UNDEFINED
std::vector< FAB_LAYER_COLOR > dummy
wxString EscapeHTML(const wxString &aString)
Return a new wxString escaped for embedding in HTML.
A filename or source description, a problem input line, a line number, a byte offset,...
This file contains data structures that are saved in the project file or project local settings file ...
int clearance
int delta
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:75
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:85
@ PCB_GENERATOR_T
class PCB_GENERATOR, generator on a layer
Definition typeinfo.h:88
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:94
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition typeinfo.h:108
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:90
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition typeinfo.h:105
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:89
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition typeinfo.h:87
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition typeinfo.h:83
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:84
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:95
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:93
Casted dyn_cast(From aObject)
A lightweight dynamic downcast.
Definition typeinfo.h:60
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687
VECTOR2< double > VECTOR2D
Definition vector2d.h:686
@ THERMAL
Use thermal relief for pads.
Definition zones.h:50
@ NONE
Pads are not covered.
Definition zones.h:49