KiCad PCB EDA Suite
router_tool.cpp
Go to the documentation of this file.
1/*
2 * KiRouter - a push-and-(sometimes-)shove PCB router
3 *
4 * Copyright (C) 2013-2017 CERN
5 * Copyright (C) 2017-2022 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * @author Tomasz Wlostowski <[email protected]>
8 *
9 * This program is free software: you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation, either version 3 of the License, or (at your
12 * option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#include <wx/hyperlink.h>
24#include <advanced_config.h>
25
26#include <functional>
27#include <iomanip>
28#include <utility>
29#include <sstream>
30
31using namespace std::placeholders;
32#include <board.h>
34#include <board_item.h>
35#include <footprint.h>
36#include <fp_shape.h>
37#include <pad.h>
38#include <zone.h>
39#include <pcb_edit_frame.h>
40#include <pcbnew_id.h>
44#include <widgets/infobar.h>
48#include <confirm.h>
49#include <bitmaps.h>
50#include <string_utils.h>
51#include <painter.h>
52#include <tool/action_menu.h>
53#include <tool/tool_manager.h>
54#include <tool/tool_menu.h>
55#include <tools/pcb_actions.h>
58#include <tools/drc_tool.h>
61
62#include <project.h>
64
65#include "router_tool.h"
66#include "pns_segment.h"
67#include "pns_router.h"
68#include "pns_itemset.h"
69#include "pns_logger.h"
70#include "pns_placement_algo.h"
71#include "pns_line_placer.h"
72#include "pns_topology.h"
73
74#include "pns_kicad_iface.h"
75
77
79
80using namespace KIGFX;
81
86{
87 // Via type
88 VIA_MASK = 0x03,
89 VIA = 0x00,
90 BLIND_VIA = 0x01,
91 MICROVIA = 0x02,
92
93 // Select layer
95};
96
97
98// Actions, being statically-defined, require specialized I18N handling. We continue to
99// use the _() macro so that string harvesting by the I18N framework doesn't have to be
100// specialized, but we don't translate on initialization and instead do it in the getters.
101
102#undef _
103#define _(s) s
104
105static const TOOL_ACTION ACT_EndTrack( "pcbnew.InteractiveRouter.EndTrack",
107 WXK_END, "",
108 _( "Finish Track" ), _( "Stops laying the current track." ),
110
111static const TOOL_ACTION ACT_PlaceThroughVia( "pcbnew.InteractiveRouter.PlaceVia",
113 'V', LEGACY_HK_NAME( "Add Through Via" ),
114 _( "Place Through Via" ),
115 _( "Adds a through-hole via at the end of currently routed track." ),
117
118static const TOOL_ACTION ACT_PlaceBlindVia( "pcbnew.InteractiveRouter.PlaceBlindVia",
120 MD_ALT + MD_SHIFT + 'V', LEGACY_HK_NAME( "Add Blind/Buried Via" ),
121 _( "Place Blind/Buried Via" ),
122 _( "Adds a blind or buried via at the end of currently routed track."),
124
125static const TOOL_ACTION ACT_PlaceMicroVia( "pcbnew.InteractiveRouter.PlaceMicroVia",
127 MD_CTRL + 'V', LEGACY_HK_NAME( "Add MicroVia" ),
128 _( "Place Microvia" ), _( "Adds a microvia at the end of currently routed track." ),
130
132 "pcbnew.InteractiveRouter.SelLayerAndPlaceVia",
134 '<', LEGACY_HK_NAME( "Select Layer and Add Through Via" ),
135 _( "Select Layer and Place Through Via..." ),
136 _( "Select a layer, then add a through-hole via at the end of currently routed track." ),
139
141 "pcbnew.InteractiveRouter.SelLayerAndPlaceBlindVia",
143 MD_ALT + '<', LEGACY_HK_NAME( "Select Layer and Add Blind/Buried Via" ),
144 _( "Select Layer and Place Blind/Buried Via..." ),
145 _( "Select a layer, then add a blind or buried via at the end of currently routed track." ),
148
150 "pcbnew.InteractiveRouter.SelLayerAndPlaceMicroVia",
152 0, "",
153 _( "Select Layer and Place Micro Via..." ),
154 _( "Select a layer, then add a micro via at the end of currently routed track." ),
157
158static const TOOL_ACTION ACT_CustomTrackWidth( "pcbnew.InteractiveRouter.CustomTrackViaSize",
160 'Q', LEGACY_HK_NAME( "Custom Track/Via Size" ),
161 _( "Custom Track/Via Size..." ),
162 _( "Shows a dialog for changing the track width and via size." ),
164
165static const TOOL_ACTION ACT_SwitchPosture( "pcbnew.InteractiveRouter.SwitchPosture",
167 '/', LEGACY_HK_NAME( "Switch Track Posture" ),
168 _( "Switch Track Posture" ),
169 _( "Switches posture of the currently routed track." ),
171
172static const TOOL_ACTION ACT_SwitchCornerMode( "pcbnew.InteractiveRouter.SwitchRounding",
174 MD_CTRL + '/', "",
175 _( "Track Corner Mode" ),
176 _( "Switches between sharp/rounded and 45°/90° corners when routing tracks." ),
178
179#undef _
180#define _(s) wxGetTranslation((s))
181
182
184 TOOL_BASE( "pcbnew.InteractiveRouter" ),
185 m_lastTargetLayer( UNDEFINED_LAYER ),
186 m_originalActiveLayer( UNDEFINED_LAYER ),
187 m_inRouterTool( false )
188{
189}
190
191
193{
194public:
196 ACTION_MENU( true ),
197 m_frame( aFrame )
198 {
200 SetTitle( _( "Select Track/Via Width" ) );
201 }
202
203protected:
204 ACTION_MENU* create() const override
205 {
206 return new TRACK_WIDTH_MENU( m_frame );
207 }
208
209 void update() override
210 {
212 bool useIndex = !bds.m_UseConnectedTrackWidth &&
214 wxString msg;
215
216 Clear();
217
218 Append( ID_POPUP_PCB_SELECT_AUTO_WIDTH, _( "Use Starting Track Width" ),
219 _( "Route using the width of the starting track." ), wxITEM_CHECK );
222
223 Append( ID_POPUP_PCB_SELECT_USE_NETCLASS_VALUES, _( "Use Net Class Values" ),
224 _( "Use track and via sizes from the net class" ), wxITEM_CHECK );
226 useIndex && bds.GetTrackWidthIndex() == 0 && bds.GetViaSizeIndex() == 0 );
227
228 Append( ID_POPUP_PCB_SELECT_CUSTOM_WIDTH, _( "Use Custom Values..." ),
229 _( "Specify custom track and via sizes" ), wxITEM_CHECK );
231
232 AppendSeparator();
233
234 // Append the list of tracks & via sizes
235 for( unsigned i = 0; i < bds.m_TrackWidthList.size(); i++ )
236 {
237 int width = bds.m_TrackWidthList[i];
238
239 if( i == 0 )
240 msg = _( "Track netclass width" );
241 else
242 msg.Printf( _( "Track %s" ), m_frame.MessageTextFromValue( width ) );
243
244 int menuIdx = ID_POPUP_PCB_SELECT_WIDTH1 + i;
245 Append( menuIdx, msg, wxEmptyString, wxITEM_CHECK );
246 Check( menuIdx, useIndex && bds.GetTrackWidthIndex() == i );
247 }
248
249 AppendSeparator();
250
251 for( unsigned i = 0; i < bds.m_ViasDimensionsList.size(); i++ )
252 {
254
255 if( i == 0 )
256 msg = _( "Via netclass values" );
257 else
258 {
259 if( via.m_Drill > 0 )
260 {
261 msg.Printf( _("Via %s, hole %s" ),
262 m_frame.MessageTextFromValue( via.m_Diameter ),
263 m_frame.MessageTextFromValue( via.m_Drill ) );
264 }
265 else
266 {
267 msg.Printf( _( "Via %s" ),
268 m_frame.MessageTextFromValue( via.m_Diameter ) );
269 }
270 }
271
272 int menuIdx = ID_POPUP_PCB_SELECT_VIASIZE1 + i;
273 Append( menuIdx, msg, wxEmptyString, wxITEM_CHECK );
274 Check( menuIdx, useIndex && bds.GetViaSizeIndex() == i );
275 }
276 }
277
278 OPT_TOOL_EVENT eventHandler( const wxMenuEvent& aEvent ) override
279 {
281 int id = aEvent.GetId();
282
283 // On Windows, this handler can be called with an event ID not existing in any
284 // menuitem, so only set flags when we have an ID match.
285
287 {
288 bds.UseCustomTrackViaSize( true );
289 bds.m_TempOverrideTrackWidth = true;
291 }
292 else if( id == ID_POPUP_PCB_SELECT_AUTO_WIDTH )
293 {
294 bds.UseCustomTrackViaSize( false );
295 bds.m_UseConnectedTrackWidth = true;
296 bds.m_TempOverrideTrackWidth = false;
297 }
299 {
300 bds.UseCustomTrackViaSize( false );
301 bds.m_UseConnectedTrackWidth = false;
302 bds.SetViaSizeIndex( 0 );
303 bds.SetTrackWidthIndex( 0 );
304 }
306 {
307 bds.UseCustomTrackViaSize( false );
309 }
311 {
312 bds.UseCustomTrackViaSize( false );
313 bds.m_TempOverrideTrackWidth = true;
315 }
316
318 }
319
320private:
322};
323
324
326{
327public:
329 ACTION_MENU( true ),
330 m_frame( aFrame )
331 {
333 SetTitle( _( "Select Differential Pair Dimensions" ) );
334 }
335
336protected:
337 ACTION_MENU* create() const override
338 {
339 return new DIFF_PAIR_MENU( m_frame );
340 }
341
342 void update() override
343 {
345
346 Clear();
347
348 Append( ID_POPUP_PCB_SELECT_USE_NETCLASS_DIFFPAIR, _( "Use Net Class Values" ),
349 _( "Use differential pair dimensions from the net class" ), wxITEM_CHECK );
351 !bds.UseCustomDiffPairDimensions() && bds.GetDiffPairIndex() == 0 );
352
353 Append( ID_POPUP_PCB_SELECT_CUSTOM_DIFFPAIR, _( "Use Custom Values..." ),
354 _( "Specify custom differential pair dimensions" ), wxITEM_CHECK );
356
357 AppendSeparator();
358
359 // Append the list of differential pair dimensions
360
361 // Drop index 0 which is the current netclass dimensions (which are handled above)
362 for( unsigned i = 1; i < bds.m_DiffPairDimensionsList.size(); ++i )
363 {
365 wxString msg;
366
367 if( diffPair.m_Gap <= 0 )
368 {
369 if( diffPair.m_ViaGap <= 0 )
370 {
371 msg.Printf( _( "Width %s" ),
373 }
374 else
375 {
376 msg.Printf( _( "Width %s, via gap %s" ),
379 }
380 }
381 else
382 {
383 if( diffPair.m_ViaGap <= 0 )
384 {
385 msg.Printf( _( "Width %s, gap %s" ),
387 m_frame.MessageTextFromValue( diffPair.m_Gap ) );
388 }
389 else
390 {
391 msg.Printf( _( "Width %s, gap %s, via gap %s" ),
395 }
396 }
397
398 int menuIdx = ID_POPUP_PCB_SELECT_DIFFPAIR1 + i - 1;
399 Append( menuIdx, msg, wxEmptyString, wxITEM_CHECK );
400 Check( menuIdx, !bds.UseCustomDiffPairDimensions() && bds.GetDiffPairIndex() == i );
401 }
402 }
403
404 OPT_TOOL_EVENT eventHandler( const wxMenuEvent& aEvent ) override
405 {
407 int id = aEvent.GetId();
408
409 // On Windows, this handler can be called with an event ID not existing in any
410 // menuitem, so only set flags when we have an ID match.
411
413 {
414 bds.UseCustomDiffPairDimensions( true );
415 TOOL_MANAGER* toolManager = m_frame.GetToolManager();
416 toolManager->RunAction( PCB_ACTIONS::routerDiffPairDialog, true );
417 }
419 {
420 bds.UseCustomDiffPairDimensions( false );
421 bds.SetDiffPairIndex( 0 );
422 }
424 {
425 bds.UseCustomDiffPairDimensions( false );
426 // remember that the menu doesn't contain index 0 (which is the netclass values)
428 }
429
431 }
432
433private:
435};
436
437
439{
440}
441
442
444{
447
448 PCB_EDIT_FRAME* frame = getEditFrame<PCB_EDIT_FRAME>();
449
450 wxASSERT( frame );
451
452 auto& menu = m_menu.GetMenu();
453 menu.SetTitle( _( "Interactive Router" ) );
454
455 m_trackViaMenu = std::make_shared<TRACK_WIDTH_MENU>( *frame );
456 m_trackViaMenu->SetTool( this );
458
459 m_diffPairMenu = std::make_shared<DIFF_PAIR_MENU>( *frame );
460 m_diffPairMenu->SetTool( this );
462
463 auto haveHighlight =
464 [&]( const SELECTION& sel )
465 {
467
468 return !cfg->GetHighlightNetCodes().empty();
469 };
470
471 auto notRoutingCond =
472 [this]( const SELECTION& )
473 {
474 return !m_router->RoutingInProgress();
475 };
476
477 auto hasOtherEnd =
478 [&]( const SELECTION& )
479 {
480 std::vector<int> currentNets = m_router->GetCurrentNets();
481
482 // Need to have something unconnected to finish to
483 int currentNet = currentNets.empty() ? -1 : currentNets[0];
484 BOARD* board = getEditFrame<PCB_EDIT_FRAME>()->GetBoard();
485 RN_NET* ratsnest = board->GetConnectivity()->GetRatsnestForNet( currentNet );
486
487 return ratsnest && !ratsnest->GetEdges().empty();
488 };
489
491 menu.AddSeparator( 1 );
492
493 menu.AddItem( PCB_ACTIONS::clearHighlight, haveHighlight, 2 );
494 menu.AddSeparator( haveHighlight, 2 );
495
496 menu.AddItem( PCB_ACTIONS::routeSingleTrack, notRoutingCond );
497 menu.AddItem( PCB_ACTIONS::routeDiffPair, notRoutingCond );
500 menu.AddItem( PCB_ACTIONS::routerContinueFromEnd, hasOtherEnd );
501 menu.AddItem( PCB_ACTIONS::routerAttemptFinish, hasOtherEnd );
502 menu.AddItem( PCB_ACTIONS::breakTrack, notRoutingCond );
503
504 menu.AddItem( PCB_ACTIONS::drag45Degree, notRoutingCond );
505 menu.AddItem( PCB_ACTIONS::dragFreeAngle, notRoutingCond );
506
515
516 menu.AddSeparator();
517
518 auto diffPairCond =
519 [this]( const SELECTION& )
520 {
522 };
523
525 menu.AddMenu( m_diffPairMenu.get(), diffPairCond );
526
528
529 menu.AddSeparator();
530
532
533 return true;
534}
535
536
538{
540
541 if( aReason == RUN )
542 TOOL_BASE::Reset( aReason );
543}
544
545// Saves the complete event log and the dump of the PCB, allowing us to
546// recreate hard-to-find P&S quirks and bugs.
547
549{
550 auto logger = m_router->Logger();
551
552 if( ! logger )
553 return;
554
555 wxString cwd = wxGetCwd();
556
557 wxFileName fname_log;
558 fname_log.SetPath( cwd );
559 fname_log.SetName( "pns.log" );
560
561 wxFileName fname_dump( cwd );
562 fname_dump.SetPath( cwd );
563 fname_dump.SetName( "pns.dump" );
564
565 wxFileName fname_settings( cwd );
566 fname_settings.SetPath( cwd );
567 fname_settings.SetName( "pns.settings" );
568
569 wxString msg = wxString::Format( _( "Event file: %s\nBoard dump: %s" ), fname_log.GetFullPath(), fname_log.GetFullPath() );
570
571 int rv = OKOrCancelDialog( nullptr, _("Save router log"), _("Would you like to save the router\nevent log for debugging purposes?"), msg, _("OK"), _("Cancel") );
572
573 if( !rv )
574 return;
575
576 FILE *f = fopen( fname_settings.GetFullPath().c_str(), "wb" );
577 std::string settingsStr = m_router->Settings().FormatAsString();
578 fprintf(f,"%s\n", settingsStr.c_str( ) );
579 fclose(f);
580
581 f = fopen( fname_log.GetFullPath().c_str(), "wb" );
582
583 fprintf(f, "mode %d\n", m_router->Mode() );
584
585 const auto& events = logger->GetEvents();
586
587 for( const auto& evt : events)
588 {
589 fprintf( f, "event %d %d %d %s %d %d %d %d %d %d %d\n", evt.p.x, evt.p.y, evt.type,
590 static_cast<const char*>( evt.uuid.AsString().c_str() ),
591 evt.sizes.TrackWidth(),
592 evt.sizes.ViaDiameter(),
593 evt.sizes.ViaDrill(),
594 evt.sizes.TrackWidthIsExplicit() ? 1: 0,
595 evt.sizes.GetLayerBottom(),
596 evt.sizes.GetLayerTop(),
597 evt.sizes.ViaType() );
598 }
599
600 // Export as *.kicad_pcb format, using a strategy which is specifically chosen
601 // as an example on how it could also be used to send it to the system clipboard.
602
603 PCB_PLUGIN pcb_io;
604
605 pcb_io.Save( fname_dump.GetFullPath(), m_iface->GetBoard(), nullptr );
606
607 PROJECT* prj = m_iface->GetBoard()->GetProject();
608 prj->GetProjectFile().SaveAs( cwd, "pns" );
609
610 std::vector<PNS::ITEM*> added, removed;
611
612 if( !m_router->GetUpdatedItems( removed, added ) )
613 {
614 fclose( f );
615 return;
616 }
617
618 for( auto item : removed )
619 {
620 fprintf(f, "removed %s\n", item->Parent()->m_Uuid.AsString().c_str().AsChar() );
621 }
622
623 for( auto item : added )
624 {
625 fprintf(f, "added %s\n", item->Format().c_str() );
626 }
627
628 fclose( f );
629}
630
631
633{
634 if( aEvent.Category() == TC_VIEW || aEvent.Category() == TC_MOUSE )
635 {
636 BOX2D viewAreaD = getView()->GetGAL()->GetVisibleWorldExtents();
637 m_router->SetVisibleViewArea( BOX2I( viewAreaD.GetOrigin(), viewAreaD.GetSize() ) );
638 }
639
640 if( !aEvent.IsKeyPressed() )
641 return;
642
643 switch( aEvent.KeyCode() )
644 {
645 case '0':
646 if( !ADVANCED_CFG::GetCfg().m_ShowRouterDebugGraphics )
647 return;
648
650 aEvent.SetPassEvent( false );
651 break;
652
653 default:
654 break;
655 }
656}
657
658
660{
661 int tl = getView()->GetTopLayer();
662
663 if( m_startItem )
664 {
665 const LAYER_RANGE& ls = m_startItem->Layers();
666
667 if( ls.Overlaps( tl ) )
668 return tl;
669 else
670 return ls.Start();
671 }
672
673 return tl;
674}
675
676
678{
679 int activeLayer = frame()->GetActiveLayer();
680 int currentLayer = m_router->GetCurrentLayer();
681
682 if( currentLayer != activeLayer )
683 m_router->SwitchLayer( activeLayer );
684
685 std::optional<int> newLayer = m_router->Sizes().PairedLayer( currentLayer );
686
687 if( !newLayer )
688 newLayer = m_router->Sizes().GetLayerTop();
689
690 m_router->SwitchLayer( *newLayer );
691 m_lastTargetLayer = *newLayer;
692
694}
695
696
698{
699 std::vector<int> nets = m_router->GetCurrentNets();
700
703 std::shared_ptr<DRC_ENGINE>& drcEngine = bds.m_DRCEngine;
704 DRC_CONSTRAINT constraint;
705
706 PCB_TRACK dummyTrack( board() );
707 dummyTrack.SetLayer( targetLayer );
708 dummyTrack.SetNetCode( nets.empty() ? 0 : nets[0] );
709
710 if( bds.UseNetClassTrack() || !sizes.TrackWidthIsExplicit() )
711 {
712 constraint = drcEngine->EvalRules( TRACK_WIDTH_CONSTRAINT, &dummyTrack, nullptr,
713 targetLayer );
714
715 if( !constraint.IsNull() )
716 {
717 sizes.SetTrackWidth( std::max( bds.m_TrackMinWidth, constraint.m_Value.Opt() ) );
718
719 if( sizes.TrackWidth() == constraint.m_Value.Opt() )
720 sizes.SetWidthSource( constraint.GetName() );
721 else
722 sizes.SetWidthSource( _( "board minimum track width" ) );
723 }
724 }
725
726 if( nets.size() >= 2 && ( bds.UseNetClassDiffPair() || !sizes.TrackWidthIsExplicit() ) )
727 {
728 PCB_TRACK dummyTrackB( board() );
729 dummyTrackB.SetLayer( targetLayer );
730 dummyTrackB.SetNetCode( nets[1] );
731
732 constraint = drcEngine->EvalRules( TRACK_WIDTH_CONSTRAINT, &dummyTrack, &dummyTrackB,
733 targetLayer );
734
735 if( !constraint.IsNull() )
736 {
737 sizes.SetDiffPairWidth( std::max( bds.m_TrackMinWidth, constraint.m_Value.Opt() ) );
738
739 if( sizes.DiffPairWidth() == constraint.m_Value.Opt() )
740 sizes.SetDiffPairWidthSource( constraint.GetName() );
741 else
742 sizes.SetDiffPairWidthSource( _( "board minimum track width" ) );
743 }
744
745 constraint = drcEngine->EvalRules( DIFF_PAIR_GAP_CONSTRAINT, &dummyTrack, &dummyTrackB,
746 targetLayer );
747
748 if( !constraint.IsNull() )
749 {
750 sizes.SetDiffPairGap( std::max( bds.m_MinClearance, constraint.m_Value.Opt() ) );
751
752 if( sizes.DiffPairGap() == constraint.m_Value.Opt() )
753 sizes.SetDiffPairGapSource( constraint.GetName() );
754 else
755 sizes.SetDiffPairGapSource( _( "board minimum clearance" ) );
756 }
757 }
758
759 m_router->UpdateSizes( sizes );
761}
762
763
764static VIATYPE getViaTypeFromFlags( int aFlags )
765{
766 switch( aFlags & VIA_ACTION_FLAGS::VIA_MASK )
767 {
769 return VIATYPE::THROUGH;
773 return VIATYPE::MICROVIA;
774 default:
775 wxASSERT_MSG( false, wxT( "Unhandled via type" ) );
776 return VIATYPE::THROUGH;
777 }
778}
779
780
782{
783 if( aEvent.IsAction( &PCB_ACTIONS::layerTop ) )
784 return F_Cu;
785 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner1 ) )
786 return In1_Cu;
787 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner2 ) )
788 return In2_Cu;
789 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner3 ) )
790 return In3_Cu;
791 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner4 ) )
792 return In4_Cu;
793 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner5 ) )
794 return In5_Cu;
795 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner6 ) )
796 return In6_Cu;
797 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner7 ) )
798 return In7_Cu;
799 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner8 ) )
800 return In8_Cu;
801 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner9 ) )
802 return In9_Cu;
803 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner10 ) )
804 return In10_Cu;
805 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner11 ) )
806 return In11_Cu;
807 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner12 ) )
808 return In12_Cu;
809 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner13 ) )
810 return In13_Cu;
811 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner14 ) )
812 return In14_Cu;
813 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner15 ) )
814 return In15_Cu;
815 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner16 ) )
816 return In16_Cu;
817 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner17 ) )
818 return In17_Cu;
819 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner18 ) )
820 return In18_Cu;
821 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner19 ) )
822 return In19_Cu;
823 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner20 ) )
824 return In20_Cu;
825 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner21 ) )
826 return In21_Cu;
827 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner22 ) )
828 return In22_Cu;
829 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner23 ) )
830 return In23_Cu;
831 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner24 ) )
832 return In24_Cu;
833 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner25 ) )
834 return In25_Cu;
835 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner26 ) )
836 return In26_Cu;
837 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner27 ) )
838 return In27_Cu;
839 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner28 ) )
840 return In28_Cu;
841 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner29 ) )
842 return In29_Cu;
843 else if( aEvent.IsAction( &PCB_ACTIONS::layerInner30 ) )
844 return In30_Cu;
845 else if( aEvent.IsAction( &PCB_ACTIONS::layerBottom ) )
846 return B_Cu;
847 else
848 return UNDEFINED_LAYER;
849}
850
851
853{
854 return handleLayerSwitch( aEvent, false );
855}
856
857
859{
860 if( !m_router->IsPlacingVia() )
861 {
862 return handleLayerSwitch( aEvent, true );
863 }
864 else
865 {
868 updateEndItem( aEvent );
870 }
871
872 return 0;
873}
874
875
876int ROUTER_TOOL::handleLayerSwitch( const TOOL_EVENT& aEvent, bool aForceVia )
877{
878 wxCHECK( m_router, 0 );
879
880 if( !IsToolActive() )
881 return 0;
882
883 // First see if this is one of the switch layer commands
884 LSEQ layers = LSET( board()->GetEnabledLayers() & LSET::AllCuMask() ).Seq();
886 PCB_LAYER_ID targetLayer = UNDEFINED_LAYER;
887
888 if( aEvent.IsAction( &PCB_ACTIONS::layerNext ) )
889 {
891 m_lastTargetLayer = currentLayer;
892
893 size_t idx = 0;
894
895 for( size_t i = 0; i < layers.size(); i++ )
896 {
897 if( layers[i] == m_lastTargetLayer )
898 {
899 idx = i;
900 break;
901 }
902 }
903
904 idx = ( idx + 1 ) % layers.size();
905 targetLayer = layers[idx];
906 }
907 else if( aEvent.IsAction( &PCB_ACTIONS::layerPrev ) )
908 {
910 m_lastTargetLayer = currentLayer;
911
912 size_t idx = 0;
913
914 for( size_t i = 0; i < layers.size(); i++ )
915 {
916 if( layers[i] == m_lastTargetLayer )
917 {
918 idx = i;
919 break;
920 }
921 }
922
923 idx = ( idx > 0 ) ? ( idx - 1 ) : ( layers.size() - 1 );
924 targetLayer = layers[idx];
925 }
926 else
927 {
928 targetLayer = getTargetLayerFromEvent( aEvent );
929 }
930
931 if( targetLayer != UNDEFINED_LAYER )
932 {
933 m_lastTargetLayer = targetLayer;
934
935 if( targetLayer == currentLayer )
936 return 0;
937
938 if( !aForceVia && m_router && m_router->SwitchLayer( targetLayer ) )
939 {
940 updateSizesAfterLayerSwitch( targetLayer );
941 updateEndItem( aEvent );
942 m_router->Move( m_endSnapPoint, m_endItem ); // refresh
943 return 0;
944 }
945 }
946
948 const int layerCount = bds.GetCopperLayerCount();
949
952
954
955 VIATYPE viaType = VIATYPE::THROUGH;
956 bool selectLayer = false;
957
958 // Otherwise it is one of the router-specific via commands
959 if( targetLayer == UNDEFINED_LAYER )
960 {
961 const int actViaFlags = aEvent.Parameter<intptr_t>();
962 selectLayer = actViaFlags & VIA_ACTION_FLAGS::SELECT_LAYER;
963
964 viaType = getViaTypeFromFlags( actViaFlags );
965
966 // ask the user for a target layer
967 if( selectLayer )
968 {
969 wxPoint endPoint = (wxPoint) view()->ToScreen( m_endSnapPoint );
970 endPoint = frame()->GetCanvas()->ClientToScreen( endPoint );
971
972 // Build the list of not allowed layer for the target layer
973 LSET not_allowed_ly = LSET::AllNonCuMask();
974
975 if( viaType != VIATYPE::THROUGH )
976 not_allowed_ly.set( currentLayer );
977
978 if( viaType == VIATYPE::MICROVIA )
979 {
980 // Allows only the previous or the next layer from the current layer
981 int previous_layer = currentLayer == B_Cu ? layerCount - 2
982 : currentLayer - 1;
983
984 int next_layer = currentLayer >= layerCount-2 ? B_Cu
985 : currentLayer + 1;
986
987 not_allowed_ly = LSET::AllLayersMask();
988
989 if( previous_layer >= F_Cu && previous_layer != currentLayer )
990 not_allowed_ly.reset( previous_layer );
991
992 if( next_layer != currentLayer )
993 not_allowed_ly.reset( next_layer );
994 }
995
996 targetLayer = frame()->SelectOneLayer( static_cast<PCB_LAYER_ID>( currentLayer ),
997 not_allowed_ly, endPoint );
998
999 // Reset the cursor to the end of the track
1001
1002 if( targetLayer == UNDEFINED_LAYER ) // cancelled by user
1003 return 0;
1004
1005 // One cannot place a blind/buried via on only one layer:
1006 if( viaType != VIATYPE::THROUGH )
1007 {
1008 if( currentLayer == targetLayer )
1009 return 0;
1010 }
1011 }
1012 }
1013
1014 // fixme: P&S supports more than one fixed layer pair. Update the dialog?
1015 sizes.ClearLayerPairs();
1016
1017 // Convert blind/buried via to a through hole one, if it goes through all layers
1018 if( viaType == VIATYPE::BLIND_BURIED
1019 && ( ( targetLayer == B_Cu && currentLayer == F_Cu )
1020 || ( targetLayer == F_Cu && currentLayer == B_Cu ) ) )
1021 {
1022 viaType = VIATYPE::THROUGH;
1023 }
1024
1025 if( targetLayer == UNDEFINED_LAYER )
1026 {
1027 // Implicic layer selection
1028
1029 switch( viaType )
1030 {
1031 case VIATYPE::THROUGH:
1032 // use the default layer pair
1033 currentLayer = pairTop;
1034 targetLayer = pairBottom;
1035 break;
1036
1037 case VIATYPE::MICROVIA:
1038 // Try to use the layer pair preset, if the layers are adjacent,
1039 // because a microvia is usually restricted to 2 adjacent copper layers
1040 if( pairTop > pairBottom ) std::swap( pairTop, pairBottom );
1041
1042 if( currentLayer == pairTop && pairBottom == pairTop+1 )
1043 {
1044 targetLayer = pairBottom;
1045 }
1046 else if( currentLayer == pairBottom && pairBottom == pairTop+1 )
1047 {
1048 targetLayer = pairTop;
1049 }
1050 else if( currentLayer == F_Cu || currentLayer == In1_Cu )
1051 {
1052 // front-side microvia
1053 currentLayer = F_Cu;
1054
1055 if( layerCount > 2 ) // Ensure the inner layer In1_Cu exists
1056 targetLayer = In1_Cu;
1057 else
1058 targetLayer = B_Cu;
1059 }
1060 else if( currentLayer == B_Cu || currentLayer == layerCount - 2 )
1061 {
1062 // back-side microvia
1063 currentLayer = B_Cu,
1064 targetLayer = (PCB_LAYER_ID) ( layerCount - 2 );
1065 }
1066 else
1067 {
1068 // This is not optimal: from an internal layer one can want to switch
1069 // to the previous or the next internal layer
1070 // but at this point we do not know what the user want.
1071 targetLayer = PCB_LAYER_ID( currentLayer + 1 );
1072 }
1073
1074 break;
1075
1077 if( currentLayer == pairTop || currentLayer == pairBottom )
1078 {
1079 // the current layer is on the defined layer pair,
1080 // swap to the other side
1081 currentLayer = pairTop;
1082 targetLayer = pairBottom;
1083 }
1084 else
1085 {
1086 // the current layer is not part of the current layer pair,
1087 // so fallback and swap to the top layer of the pair by default
1088 targetLayer = pairTop;
1089 }
1090
1091 // Do not create a broken via (i.e. a via on only one copper layer)
1092 if( currentLayer == targetLayer )
1093 {
1094 WX_INFOBAR* infobar = frame()->GetInfoBar();
1095 infobar->ShowMessageFor( _( "Blind/buried via need 2 different layers." ),
1096 2000, wxICON_ERROR,
1098 return 0;
1099 }
1100
1101 break;
1102
1103 default:
1104 wxFAIL_MSG( wxT( "unexpected via type" ) );
1105 return 0;
1106 break;
1107 }
1108 }
1109
1110 sizes.SetViaDiameter( bds.m_ViasMinSize );
1111 sizes.SetViaDrill( bds.m_MinThroughDrill );
1112
1113 if( bds.UseNetClassVia() || viaType == VIATYPE::MICROVIA )
1114 {
1115 PCB_VIA dummyVia( board() );
1116 dummyVia.SetViaType( viaType );
1117 dummyVia.SetLayerPair( currentLayer, targetLayer );
1118
1119 if( !m_router->GetCurrentNets().empty() )
1120 dummyVia.SetNetCode( m_router->GetCurrentNets()[0] );
1121
1122 DRC_CONSTRAINT constraint;
1123
1124 constraint = bds.m_DRCEngine->EvalRules( VIA_DIAMETER_CONSTRAINT, &dummyVia, nullptr,
1125 currentLayer );
1126
1127 if( !constraint.IsNull() )
1128 sizes.SetViaDiameter( constraint.m_Value.Opt() );
1129
1130 constraint = bds.m_DRCEngine->EvalRules( HOLE_SIZE_CONSTRAINT, &dummyVia, nullptr,
1131 currentLayer );
1132
1133 if( !constraint.IsNull() )
1134 sizes.SetViaDrill( constraint.m_Value.Opt() );
1135 }
1136 else
1137 {
1138 sizes.SetViaDiameter( bds.GetCurrentViaSize() );
1139 sizes.SetViaDrill( bds.GetCurrentViaDrill() );
1140 }
1141
1142 sizes.SetViaType( viaType );
1143 sizes.AddLayerPair( currentLayer, targetLayer );
1144
1145 m_router->UpdateSizes( sizes );
1146
1147 if( !m_router->IsPlacingVia() )
1149
1150 m_lastTargetLayer = targetLayer;
1151
1153 {
1154 updateEndItem( aEvent );
1156 }
1157 else
1158 {
1159 updateStartItem( aEvent );
1160 }
1161
1162 return 0;
1163}
1164
1165
1167{
1168 PCB_EDIT_FRAME* editFrame = getEditFrame<PCB_EDIT_FRAME>();
1169 int routingLayer = getStartLayer( m_startItem );
1170
1171 if( !IsCopperLayer( routingLayer ) )
1172 {
1173 editFrame->ShowInfoBarError( _( "Tracks on Copper layers only." ) );
1174 return false;
1175 }
1176
1178 editFrame->SetActiveLayer( ToLAYER_ID( routingLayer ) );
1179
1180 if( !getView()->IsLayerVisible( routingLayer ) )
1181 {
1182 editFrame->GetAppearancePanel()->SetLayerVisible( routingLayer, true );
1183 editFrame->GetCanvas()->Refresh();
1184 }
1185
1186 if( m_startItem && m_startItem->Net() > 0 )
1187 highlightNet( true, m_startItem->Net() );
1188
1189 controls()->SetAutoPan( true );
1190
1192
1193 m_iface->SetStartLayer( routingLayer );
1194
1196 m_iface->ImportSizes( sizes, m_startItem, -1 );
1197 sizes.AddLayerPair( frame()->GetScreen()->m_Route_Layer_TOP,
1198 frame()->GetScreen()->m_Route_Layer_BOTTOM );
1199
1200 m_router->UpdateSizes( sizes );
1201
1202 if( !m_router->StartRouting( m_startSnapPoint, m_startItem, routingLayer ) )
1203 {
1204 // It would make more sense to leave the net highlighted as the higher-contrast mode
1205 // makes the router clearances more visible. However, since we just started routing
1206 // the conversion of the screen from low contrast to high contrast is a bit jarring and
1207 // makes the infobar coming up less noticeable.
1208 highlightNet( false );
1209
1211 [&]()
1212 {
1213 m_router->ClearViewDecorations();
1214 } );
1215
1216 controls()->SetAutoPan( false );
1217 return false;
1218 }
1219
1220 m_endItem = nullptr;
1222
1224 frame()->UndoRedoBlock( true );
1225
1226 return true;
1227}
1228
1229
1231{
1233
1234 m_startItem = nullptr;
1235 m_endItem = nullptr;
1236
1240 controls()->SetAutoPan( false );
1241 controls()->ForceCursorPosition( false );
1242 frame()->UndoRedoBlock( false );
1243 highlightNet( false );
1244
1245 return true;
1246}
1247
1248
1250{
1252
1253 if( !prepareInteractive() )
1254 return;
1255
1256 auto setCursor =
1257 [&]()
1258 {
1260 };
1261
1262 auto syncRouterAndFrameLayer =
1263 [&]()
1264 {
1265 PCB_LAYER_ID routingLayer = ToLAYER_ID( m_router->GetCurrentLayer() );
1266 PCB_EDIT_FRAME* editFrame = getEditFrame<PCB_EDIT_FRAME>();
1267
1268 editFrame->SetActiveLayer( routingLayer );
1269
1270 if( !getView()->IsLayerVisible( routingLayer ) )
1271 {
1272 editFrame->GetAppearancePanel()->SetLayerVisible( routingLayer, true );
1273 editFrame->GetCanvas()->Refresh();
1274 }
1275 };
1276
1277 // Set initial cursor
1278 setCursor();
1279
1280 while( TOOL_EVENT* evt = Wait() )
1281 {
1282 setCursor();
1283
1284 // Don't crash if we missed an operation that canceled routing.
1285 if( !m_router->RoutingInProgress() )
1286 {
1287 if( evt->IsCancelInteractive() )
1288 m_cancelled = true;
1289
1290 break;
1291 }
1292
1293 handleCommonEvents( *evt );
1294
1295 if( evt->IsMotion() )
1296 {
1297 updateEndItem( *evt );
1299 }
1300 else if( evt->IsAction( &PCB_ACTIONS::routerUndoLastSegment ) )
1301 {
1303 updateEndItem( *evt );
1305 }
1306 else if( evt->IsAction( &PCB_ACTIONS::routerAttemptFinish ) )
1307 {
1308 bool* autoRouted = evt->Parameter<bool*>();
1309
1310 if( m_router->Finish() )
1311 {
1312 // When we're routing a group of signals automatically we want
1313 // to break up the undo stack every time we have to manually route
1314 // so the user gets nice checkpoints. Remove the APPEND_UNDO flag.
1315 if( autoRouted != nullptr )
1316 *autoRouted = true;
1317
1318 break;
1319 }
1320 else
1321 {
1322 // This acts as check if we were called by the autorouter; we don't want
1323 // to reset APPEND_UNDO if we're auto finishing after route-other-end
1324 if( autoRouted != nullptr )
1325 {
1326 *autoRouted = false;
1327 m_iface->SetCommitFlags( 0 );
1328 }
1329
1330 // Warp the mouse so the user is at the point we managed to route to
1331 controls()->WarpMouseCursor( m_router->Placer()->CurrentEnd(), true, true );
1332 }
1333 }
1334 else if( evt->IsAction( &PCB_ACTIONS::routerContinueFromEnd ) )
1335 {
1336 bool needsAppend = m_router->Placer()->HasPlacedAnything();
1337
1338 if( m_router->ContinueFromEnd() )
1339 {
1340 syncRouterAndFrameLayer();
1342
1343 // Warp the mouse to wherever we actually ended up routing to
1344 controls()->WarpMouseCursor( m_router->Placer()->CurrentEnd(), true, true );
1345
1346 // We want the next router commit to be one undo at the UI layer
1347 m_iface->SetCommitFlags( needsAppend ? APPEND_UNDO : 0 );
1348 }
1349 }
1350 else if( evt->IsClick( BUT_LEFT ) || evt->IsDrag( BUT_LEFT ) || evt->IsAction( &PCB_ACTIONS::routeSingleTrack ) )
1351 {
1352 updateEndItem( *evt );
1353 bool needLayerSwitch = m_router->IsPlacingVia();
1354 bool forceFinish = evt->Modifier( MD_SHIFT );
1355
1356 if( m_router->FixRoute( m_endSnapPoint, m_endItem, forceFinish ) )
1357 break;
1358
1359 if( needLayerSwitch )
1361
1362 // Synchronize the indicated layer
1363 syncRouterAndFrameLayer();
1364
1365 updateEndItem( *evt );
1367 m_startItem = nullptr;
1368 }
1369 else if( evt->IsAction( &ACT_SwitchCornerMode ) )
1370 {
1373 updateEndItem( *evt );
1374 m_router->Move( m_endSnapPoint, m_endItem ); // refresh
1375 }
1376 else if( evt->IsAction( &ACT_SwitchPosture ) )
1377 {
1379 updateEndItem( *evt );
1380 m_router->Move( m_endSnapPoint, m_endItem ); // refresh
1381 }
1382 else if( evt->IsAction( &PCB_ACTIONS::properties ) )
1383 {
1385 controls()->SetAutoPan( false );
1386 {
1388 }
1389 controls()->SetAutoPan( true );
1390 setCursor();
1392 }
1393 else if( evt->IsAction( &ACT_EndTrack ) || evt->IsDblClick( BUT_LEFT ) )
1394 {
1395 // Stop current routing:
1397 break;
1398 }
1399 else if( evt->IsCancelInteractive() || evt->IsActivate()
1400 || evt->IsAction( &PCB_ACTIONS::routerInlineDrag ) )
1401 {
1402 if( evt->IsCancelInteractive() && !m_router->RoutingInProgress() )
1403 m_cancelled = true;
1404
1405 if( evt->IsActivate() && !evt->IsMoveTool() )
1406 m_cancelled = true;
1407
1408 break;
1409 }
1410 else if( evt->IsUndoRedo() )
1411 {
1412 // We're in an UndoRedoBlock. If we get here, something's broken.
1413 wxFAIL;
1414 break;
1415 }
1416 else if( evt->IsClick( BUT_RIGHT ) )
1417 {
1419 }
1420 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
1421 // but we don't at present have that, so we just knock out some of the egregious ones.
1422 else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
1423 {
1424 wxBell();
1425 }
1426 else
1427 {
1428 evt->SetPassEvent();
1429 }
1430 }
1431
1433 // Reset to normal for next route
1434 m_iface->SetCommitFlags( 0 );
1435
1437}
1438
1439
1441{
1443 DIALOG_PNS_DIFF_PAIR_DIMENSIONS settingsDlg( frame(), sizes );
1444
1445 if( settingsDlg.ShowModal() == wxID_OK )
1446 {
1447 m_router->UpdateSizes( sizes );
1448 m_savedSizes = sizes;
1449
1452 bds.SetCustomDiffPairGap( sizes.DiffPairGap() );
1454 }
1455
1456 return 0;
1457}
1458
1459
1461{
1462 DIALOG_PNS_SETTINGS settingsDlg( frame(), m_router->Settings() );
1463
1464 settingsDlg.ShowModal();
1465
1467
1468 return 0;
1469}
1470
1471
1473{
1474 PNS::PNS_MODE mode = aEvent.Parameter<PNS::PNS_MODE>();
1476
1477 settings.SetMode( mode );
1478
1479 return 0;
1480}
1481
1482
1484{
1486 PNS::PNS_MODE mode = settings.Mode();
1487
1488 switch( mode )
1489 {
1490 case PNS::RM_MarkObstacles: mode = PNS::RM_Shove; break;
1491 case PNS::RM_Shove: mode = PNS::RM_Walkaround; break;
1492 case PNS::RM_Walkaround: mode = PNS::RM_MarkObstacles; break;
1493 }
1494
1495 settings.SetMode( mode );
1496
1497 return 0;
1498}
1499
1500
1502{
1503 return m_router->Settings().Mode();
1504}
1505
1506
1508{
1509 return m_router->RoutingInProgress();
1510}
1511
1512
1514{
1517}
1518
1519
1521{
1523 PCB_EDIT_FRAME* frame = getEditFrame<PCB_EDIT_FRAME>();
1525 PCB_LAYER_ID originalLayer = frame->GetActiveLayer();
1526 bool autoRoute = aEvent.Matches( PCB_ACTIONS::routerAutorouteSelected.MakeEvent() );
1527 bool otherEnd = aEvent.Matches( PCB_ACTIONS::routerRouteSelectedFromEnd.MakeEvent() );
1528
1530 return 0;
1531
1532 // Save selection then clear it for interactive routing
1534
1535 if( selection.Size() == 0 )
1536 return 0;
1537
1539
1540 frame->PushTool( aEvent );
1541
1542 auto setCursor =
1543 [&]()
1544 {
1546 };
1547
1548 Activate();
1549 // Must be done after Activate() so that it gets set into the correct context
1550 controls->ShowCursor( true );
1551 controls->ForceCursorPosition( false );
1552 // Set initial cursor
1553 setCursor();
1554
1555 // Get all connected board items, adding pads for any footprints selected
1556 std::vector<BOARD_CONNECTED_ITEM*> itemList;
1557
1559 {
1560 if( item->Type() == PCB_FOOTPRINT_T )
1561 {
1562 const PADS& fpPads = ( static_cast<FOOTPRINT*>( item ) )->Pads();
1563
1564 for( PAD* pad : fpPads )
1565 itemList.push_back( pad );
1566 }
1567 else if( dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) != nullptr )
1568 {
1569 itemList.push_back( static_cast<BOARD_CONNECTED_ITEM*>( item ) );
1570 }
1571 }
1572
1573 std::shared_ptr<CONNECTIVITY_DATA> connectivity = frame->GetBoard()->GetConnectivity();
1574
1575 // For putting sequential tracks that successfully autoroute into one undo commit
1576 bool groupStart = true;
1577
1578 for( BOARD_CONNECTED_ITEM* item : itemList )
1579 {
1580 // This code is similar to GetRatsnestForPad() but it only adds the anchor for
1581 // the side of the connectivity on this pad. It also checks for ratsnest points
1582 // inside the pad (like a trace end) and counts them.
1583 RN_NET* net = connectivity->GetRatsnestForNet( item->GetNetCode() );
1584 std::vector<std::shared_ptr<CN_ANCHOR>> anchors;
1585
1586 for( const CN_EDGE& edge : net->GetEdges() )
1587 {
1588 std::shared_ptr<CN_ANCHOR> target = edge.GetTargetNode();
1589 std::shared_ptr<CN_ANCHOR> source = edge.GetSourceNode();
1590
1591 if( source->Parent() == item )
1592 anchors.push_back( edge.GetSourceNode() );
1593 else if( target->Parent() == item )
1594 anchors.push_back( edge.GetTargetNode() );
1595 }
1596
1597 // Route them
1598 for( std::shared_ptr<CN_ANCHOR> anchor : anchors )
1599 {
1600 // Try to return to the original layer as indicating the user's preferred
1601 // layer for autorouting tracks. The layer can be changed by the user to
1602 // finish tracks that can't complete automatically, but should be changed
1603 // back after.
1604 if( frame->GetActiveLayer() != originalLayer )
1605 frame->SetActiveLayer( originalLayer );
1606
1607 VECTOR2I ignore;
1609 m_startSnapPoint = anchor->Pos();
1610 m_router->SetMode( mode );
1611
1612 // Prime the interactive routing to attempt finish if we are autorouting
1613 bool autoRouted = false;
1614
1615 if( autoRoute )
1617 else if( otherEnd )
1619
1620 // We want autorouted tracks to all be in one undo group except for
1621 // any tracks that need to be manually finished.
1622 // The undo appending for manually finished tracks is handled in peformRouting()
1623 if( groupStart )
1624 groupStart = false;
1625 else
1627
1628 // Start interactive routing. Will automatically finish if possible.
1630
1631 // Route didn't complete automatically, need to a new undo commit
1632 // for the next line so those can group as far as they autoroute
1633 if( !autoRouted )
1634 groupStart = true;
1635 }
1636 }
1637
1638 m_iface->SetCommitFlags( 0 );
1639 frame->PopTool( aEvent );
1640 return 0;
1641}
1642
1643
1645{
1646 if( m_inRouterTool )
1647 return 0;
1648
1650
1652 PCB_EDIT_FRAME* frame = getEditFrame<PCB_EDIT_FRAME>();
1654
1656 {
1657 if( m_router->Mode() == mode )
1658 return 0;
1659 else
1661 }
1662
1663 // Deselect all items
1665
1666 frame->PushTool( aEvent );
1667
1668 auto setCursor =
1669 [&]()
1670 {
1672 };
1673
1674 Activate();
1675 // Must be done after Activate() so that it gets set into the correct context
1676 controls->ShowCursor( true );
1677 controls->ForceCursorPosition( false );
1678 // Set initial cursor
1679 setCursor();
1680
1681 m_router->SetMode( mode );
1682 m_cancelled = false;
1683
1684 if( aEvent.HasPosition() )
1685 m_toolMgr->PrimeTool( aEvent.Position() );
1686
1687 // Main loop: keep receiving events
1688 while( TOOL_EVENT* evt = Wait() )
1689 {
1690 if( !evt->IsDrag() )
1691 setCursor();
1692
1693 if( evt->IsCancelInteractive() )
1694 {
1695 frame->PopTool( aEvent );
1696 break;
1697 }
1698 else if( evt->IsActivate() )
1699 {
1700 if( evt->IsMoveTool() || evt->IsEditorTool() )
1701 {
1702 // leave ourselves on the stack so we come back after the move
1703 break;
1704 }
1705 else
1706 {
1707 frame->PopTool( aEvent );
1708 break;
1709 }
1710 }
1711 else if( evt->Action() == TA_UNDO_REDO_PRE )
1712 {
1714 }
1715 else if( evt->Action() == TA_UNDO_REDO_POST || evt->Action() == TA_MODEL_CHANGE )
1716 {
1718 }
1719 else if( evt->IsMotion() )
1720 {
1721 updateStartItem( *evt );
1722 }
1723 else if( evt->IsAction( &PCB_ACTIONS::dragFreeAngle ) )
1724 {
1725 updateStartItem( *evt, true );
1727 }
1728 else if( evt->IsAction( &PCB_ACTIONS::drag45Degree ) )
1729 {
1730 updateStartItem( *evt, true );
1732 }
1733 else if( evt->IsAction( &PCB_ACTIONS::breakTrack ) )
1734 {
1735 updateStartItem( *evt, true );
1736 breakTrack( );
1737 evt->SetPassEvent( false );
1738 }
1739 else if( evt->IsClick( BUT_LEFT )
1740 || evt->IsAction( &PCB_ACTIONS::routeSingleTrack )
1741 || evt->IsAction( &PCB_ACTIONS::routeDiffPair ) )
1742 {
1743 updateStartItem( *evt );
1744
1745 if( evt->HasPosition() )
1746 {
1747 if( evt->Modifier( MD_SHIFT ) )
1749 else
1751 }
1752 }
1753 else if( evt->IsAction( &ACT_PlaceThroughVia ) )
1754 {
1756 }
1757 else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
1758 {
1761 updateStartItem( *evt );
1762 }
1763 else if( evt->IsKeyPressed() )
1764 {
1765 // wxWidgets fails to correctly translate shifted keycodes on the wxEVT_CHAR_HOOK
1766 // event so we need to process the wxEVT_CHAR event that will follow as long as we
1767 // pass the event.
1768 evt->SetPassEvent();
1769 }
1770 else if( evt->IsClick( BUT_RIGHT ) )
1771 {
1773 }
1774 else
1775 {
1776 evt->SetPassEvent();
1777 }
1778
1779 if( m_cancelled )
1780 {
1781 frame->PopTool( aEvent );
1782 break;
1783 }
1784 }
1785
1786 // Store routing settings till the next invocation
1789
1790 return 0;
1791}
1792
1793
1795{
1797
1799
1800 if( m_startItem && m_startItem->IsLocked() )
1801 {
1802 KIDIALOG dlg( frame(), _( "The selected item is locked." ), _( "Confirmation" ),
1803 wxOK | wxCANCEL | wxICON_WARNING );
1804 dlg.SetOKLabel( _( "Drag Anyway" ) );
1805 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
1806
1807 if( dlg.ShowModal() == wxID_CANCEL )
1808 return;
1809 }
1810
1811 // We don't support dragging arcs inside the PNS right now
1813 {
1816
1817 m_startItem = nullptr;
1818
1819 m_gridHelper->SetAuxAxes( false );
1820 ctls->ForceCursorPosition( false );
1821 highlightNet( false );
1822
1823 m_cancelled = true;
1824
1826
1827 return;
1828 }
1829
1830 bool dragStarted = m_router->StartDragging( m_startSnapPoint, m_startItem, aMode );
1831
1832 if( !dragStarted )
1833 return;
1834
1835 if( m_startItem && m_startItem->Net() > 0 )
1836 highlightNet( true, m_startItem->Net() );
1837
1838 ctls->SetAutoPan( true );
1840 frame()->UndoRedoBlock( true );
1841
1842 while( TOOL_EVENT* evt = Wait() )
1843 {
1844 ctls->ForceCursorPosition( false );
1845
1846 if( evt->IsMotion() )
1847 {
1848 updateEndItem( *evt );
1850 }
1851 else if( evt->IsClick( BUT_LEFT ) )
1852 {
1854 break;
1855 }
1856 else if( evt->IsClick( BUT_RIGHT ) )
1857 {
1859 }
1860 else if( evt->IsCancelInteractive() || evt->IsActivate() )
1861 {
1862 if( evt->IsCancelInteractive() && !m_startItem )
1863 m_cancelled = true;
1864
1865 if( evt->IsActivate() && !evt->IsMoveTool() )
1866 m_cancelled = true;
1867
1868 break;
1869 }
1870 else if( evt->IsUndoRedo() )
1871 {
1872 // We're in an UndoRedoBlock. If we get here, something's broken.
1873 wxFAIL;
1874 break;
1875 }
1876 else if( evt->Category() == TC_COMMAND )
1877 {
1878 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
1879 // but we don't at present have that, so we just knock out some of the egregious ones.
1880 if( evt->IsAction( &ACTIONS::cut )
1881 || evt->IsAction( &ACTIONS::copy )
1882 || evt->IsAction( &ACTIONS::paste )
1883 || evt->IsAction( &ACTIONS::pasteSpecial )
1885 {
1886 wxBell();
1887 }
1888 // treat an undo as an escape
1889 else if( evt->IsAction( &ACTIONS::undo ) )
1890 {
1891 if( m_startItem )
1892 break;
1893 else
1894 wxBell();
1895 }
1896 else
1897 {
1898 evt->SetPassEvent();
1899 }
1900 }
1901 else
1902 {
1903 evt->SetPassEvent();
1904 }
1905
1906 handleCommonEvents( *evt );
1907 }
1908
1911
1912 m_startItem = nullptr;
1913
1914 m_gridHelper->SetAuxAxes( false );
1915 frame()->UndoRedoBlock( false );
1916 ctls->SetAutoPan( false );
1917 ctls->ForceCursorPosition( false );
1918 highlightNet( false );
1919}
1920
1921
1923{
1924 /*
1925 * If the collection contains a trivial line corner (two connected segments)
1926 * or a non-fanout-via (a via with no more than two connected segments), then
1927 * trim the collection down to a single item (which one won't matter since
1928 * they're all connected).
1929 */
1930
1931 // First make sure we've got something that *might* match.
1932 int vias = aCollector.CountType( PCB_VIA_T );
1933 int traces = aCollector.CountType( PCB_TRACE_T );
1934 int arcs = aCollector.CountType( PCB_ARC_T );
1935
1936 if( arcs > 0 || vias > 1 || traces > 2 || vias + traces < 1 )
1937 return;
1938
1939 // Fetch first PCB_TRACK (via or trace) as our reference
1940 PCB_TRACK* reference = nullptr;
1941
1942 for( int i = 0; !reference && i < aCollector.GetCount(); i++ )
1943 reference = dynamic_cast<PCB_TRACK*>( aCollector[i] );
1944
1945 int refNet = reference->GetNetCode();
1946
1947 VECTOR2I refPoint( aPt.x, aPt.y );
1948 EDA_ITEM_FLAGS flags = reference->IsPointOnEnds( refPoint, -1 );
1949
1950 if( flags & STARTPOINT )
1951 refPoint = reference->GetStart();
1952 else if( flags & ENDPOINT )
1953 refPoint = reference->GetEnd();
1954
1955 // Check all items to ensure that any TRACKs are co-terminus with the reference and on
1956 // the same net.
1957 for( int i = 0; i < aCollector.GetCount(); i++ )
1958 {
1959 PCB_TRACK* neighbor = dynamic_cast<PCB_TRACK*>( aCollector[i] );
1960
1961 if( neighbor && neighbor != reference )
1962 {
1963 if( neighbor->GetNetCode() != refNet )
1964 return;
1965
1966 if( neighbor->GetStart() != refPoint && neighbor->GetEnd() != refPoint )
1967 return;
1968 }
1969 }
1970
1971 // Selection meets criteria; trim it to the reference item.
1972 aCollector.Empty();
1973 aCollector.Append( reference );
1974}
1975
1976
1977bool ROUTER_TOOL::CanInlineDrag( int aDragMode )
1978{
1980 const PCB_SELECTION& selection = m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
1981
1982 if( selection.Size() == 1 )
1983 {
1984 const BOARD_ITEM* item = static_cast<const BOARD_ITEM*>( selection.Front() );
1985
1986 // Note: EDIT_TOOL::Drag temporarily handles items of type PCB_ARC_T on its own using
1987 // DragArcTrack(), so PCB_ARC_T should never occur here.
1989 {
1990 // Footprints cannot be dragged freely.
1991 if( item->IsType( { PCB_FOOTPRINT_T } ) )
1992 return !( aDragMode & PNS::DM_FREE_ANGLE );
1993 else
1994 return true;
1995 }
1996 }
1997
1998 return false;
1999}
2000
2001
2003{
2004 const PCB_SELECTION& selection = m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
2005
2006 if( selection.Empty() )
2008
2009 if( selection.Size() != 1 )
2010 return 0;
2011
2012 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( selection.Front() );
2013
2014 if( item->Type() != PCB_TRACE_T
2015 && item->Type() != PCB_VIA_T
2016 && item->Type() != PCB_FOOTPRINT_T )
2017 {
2018 return 0;
2019 }
2020
2021 // If we overrode locks, we want to clear the flag from the source item before SyncWorld is
2022 // called so that virtual vias are not generated for the (now unlocked) track segment. Note in
2023 // this case the lock can't be reliably re-applied, because there is no guarantee that the end
2024 // state of the drag results in the same number of segments so it's not clear which segment to
2025 // apply the lock state to.
2026 bool wasLocked = false;
2027
2028 if( item->IsLocked() )
2029 {
2030 wasLocked = true;
2031 item->SetLocked( false );
2032 }
2033
2035
2036 Activate();
2037
2038 m_startItem = nullptr;
2039
2040 PNS::ITEM* startItem = nullptr;
2041 PNS::ITEM_SET itemsToDrag;
2042 FOOTPRINT* footprint = nullptr;
2043
2044 bool showCourtyardConflicts = frame()->GetPcbNewSettings()->m_ShowCourtyardCollisions;
2045
2046 std::shared_ptr<DRC_ENGINE> drcEngine = m_toolMgr->GetTool<DRC_TOOL>()->GetDRCEngine();
2047 DRC_INTERACTIVE_COURTYARD_CLEARANCE courtyardClearanceDRC( drcEngine );
2048
2049 std::shared_ptr<CONNECTIVITY_DATA> connectivityData = board()->GetConnectivity();
2050 std::vector<BOARD_ITEM*> dynamicItems;
2051 std::unique_ptr<CONNECTIVITY_DATA> dynamicData = nullptr;
2052 VECTOR2I lastOffset;
2053
2054 if( item->Type() == PCB_FOOTPRINT_T )
2055 {
2056 footprint = static_cast<FOOTPRINT*>( item );
2057
2058 for( PAD* pad : footprint->Pads() )
2059 {
2061
2062 if( solid )
2063 itemsToDrag.Add( solid );
2064
2065 if( pad->GetLocalRatsnestVisible() || displayOptions().m_ShowModuleRatsnest )
2066 {
2067 if( connectivityData->GetRatsnestForPad( pad ).size() > 0 )
2068 dynamicItems.push_back( pad );
2069 }
2070 }
2071
2072 if( showCourtyardConflicts )
2073 {
2074 courtyardClearanceDRC.Init( board() );
2075 courtyardClearanceDRC.m_FpInMove.push_back( footprint );
2076 }
2077
2078 dynamicData = std::make_unique<CONNECTIVITY_DATA>( dynamicItems, true );
2079 connectivityData->BlockRatsnestItems( dynamicItems );
2080 }
2081 else
2082 {
2083 startItem = m_router->GetWorld()->FindItemByParent( item );
2084
2085 if( startItem )
2086 itemsToDrag.Add( startItem );
2087 }
2088
2089 GAL* gal = m_toolMgr->GetView()->GetGAL();
2090 VECTOR2I p0 = controls()->GetCursorPosition( false );
2091 VECTOR2I p = p0;
2092
2094 m_gridHelper->SetSnap( !aEvent.Modifier( MD_SHIFT ) );
2095
2096 if( startItem )
2097 {
2098 p = snapToItem( startItem, p0 );
2099 m_startItem = startItem;
2100
2101 if( m_startItem && m_startItem->Net() > 0 )
2102 highlightNet( true, m_startItem->Net() );
2103 }
2104 else if( footprint )
2105 {
2106 // The mouse is going to be moved on grid before dragging begins.
2107 VECTOR2I tweakedMousePos;
2108 PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
2109
2110 // Check if user wants to warp the mouse to origin of moved object
2111
2112 if( editFrame->GetMoveWarpsCursor() )
2113 tweakedMousePos = footprint->GetPosition(); // Use footprint anchor to warp mouse
2114 else
2115 tweakedMousePos = controls()->GetCursorPosition(); // Just use current mouse pos
2116
2117 // We tweak the mouse position using the value from above, and then use that as the
2118 // start position to prevent the footprint from jumping when we start dragging.
2119 // First we move the visual cross hair cursor...
2120 controls()->ForceCursorPosition( true, tweakedMousePos );
2121 controls()->SetCursorPosition( tweakedMousePos ); // ...then the mouse pointer
2122
2123 // Now that the mouse is in the right position, get a copy of the position to use later
2124 p = controls()->GetCursorPosition();
2125 }
2126
2127 int dragMode = aEvent.Parameter<int64_t> ();
2128
2129 bool dragStarted = m_router->StartDragging( p, itemsToDrag, dragMode );
2130
2131 if( !dragStarted )
2132 {
2133 if( wasLocked )
2134 item->SetLocked( true );
2135
2136 return 0;
2137 }
2138
2139 m_gridHelper->SetAuxAxes( true, p );
2140 controls()->ShowCursor( true );
2141 controls()->SetAutoPan( true );
2142 frame()->UndoRedoBlock( true );
2143
2144 view()->ClearPreview();
2145 view()->InitPreview();
2146
2147 auto setCursor =
2148 [&]()
2149 {
2151 };
2152
2153 // Set initial cursor
2154 setCursor();
2155
2156 // Set the initial visible area
2157 BOX2D viewAreaD = getView()->GetGAL()->GetVisibleWorldExtents();
2158 m_router->SetVisibleViewArea( BOX2I( viewAreaD.GetOrigin(), viewAreaD.GetSize() ) );
2159
2160 // Send an initial movement to prime the collision detection
2161 m_router->Move( p, nullptr );
2162
2163 bool hasMouseMoved = false;
2164
2165 while( TOOL_EVENT* evt = Wait() )
2166 {
2167 setCursor();
2168
2169 if( evt->IsCancelInteractive() )
2170 {
2171 if( wasLocked )
2172 item->SetLocked( true );
2173
2174 break;
2175 }
2176 else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) )
2177 {
2178 hasMouseMoved = true;
2179 updateEndItem( *evt );
2181
2182 if( footprint )
2183 {
2184 VECTOR2I offset = m_endSnapPoint - p;
2185 BOARD_ITEM* previewItem;
2186
2187 VECTOR2I fp_offset( offset );
2188 RotatePoint( fp_offset, -footprint->GetOrientation() );
2189
2190 view()->ClearPreview();
2191
2192 for( BOARD_ITEM* drawing : footprint->GraphicalItems() )
2193 {
2194 previewItem = static_cast<BOARD_ITEM*>( drawing->Clone() );
2195
2196 if( drawing->Type() == PCB_FP_SHAPE_T )
2197 {
2198 FP_SHAPE* shape = static_cast<FP_SHAPE*>( previewItem );
2199 shape->FP_SHAPE::Move( fp_offset );
2200 }
2201 else
2202 {
2203 previewItem->Move( offset );
2204 }
2205
2206 view()->AddToPreview( previewItem );
2207 view()->Hide( drawing, true );
2208 }
2209
2210 for( PAD* pad : footprint->Pads() )
2211 {
2212 if( ( pad->GetLayerSet() & LSET::AllCuMask() ).none()
2213 && pad->GetDrillSize().x == 0 )
2214 {
2215 previewItem = static_cast<BOARD_ITEM*>( pad->Clone() );
2216 previewItem->Move( offset );
2217
2218 view()->AddToPreview( previewItem );
2219 }
2220 else
2221 {
2222 // Pads with copper or holes are handled by the router
2223 }
2224
2225 view()->Hide( pad, true );
2226 }
2227
2228 previewItem = static_cast<BOARD_ITEM*>( footprint->Reference().Clone() );
2229 previewItem->Move( offset );
2230 view()->AddToPreview( previewItem );
2231 view()->Hide( &footprint->Reference() );
2232
2233 previewItem = static_cast<BOARD_ITEM*>( footprint->Value().Clone() );
2234 previewItem->Move( offset );
2235 view()->AddToPreview( previewItem );
2236 view()->Hide( &footprint->Value() );
2237
2238 for( ZONE* zone : footprint->Zones() )
2239 {
2240 previewItem = static_cast<BOARD_ITEM*>( zone->Clone() );
2241 previewItem->Move( offset );
2242 view()->AddToPreview( previewItem );
2243 view()->Hide( zone, true );
2244 }
2245
2246 if( showCourtyardConflicts )
2247 {
2248 footprint->Move( offset );
2249 courtyardClearanceDRC.Run();
2250 courtyardClearanceDRC.UpdateConflicts( getView(), false );
2251 footprint->Move( -offset );
2252 }
2253
2254 // Update ratsnest
2255 dynamicData->Move( offset - lastOffset );
2256 lastOffset = offset;
2257 connectivityData->ComputeLocalRatsnest( dynamicItems, dynamicData.get(), offset );
2258 }
2259 }
2260 else if( hasMouseMoved && ( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) ) )
2261 {
2262 updateEndItem( *evt );
2264 break;
2265 }
2266 else if( evt->IsUndoRedo() )
2267 {
2268 // We're in an UndoRedoBlock. If we get here, something's broken.
2269 wxFAIL;
2270 break;
2271 }
2272 else if( evt->Category() == TC_COMMAND )
2273 {
2274 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
2275 // but we don't at present have that, so we just knock out some of the egregious ones.
2276 if( evt->IsAction( &ACTIONS::cut )
2277 || evt->IsAction( &ACTIONS::copy )
2278 || evt->IsAction( &ACTIONS::paste )
2279 || evt->IsAction( &ACTIONS::pasteSpecial )
2281 {
2282 wxBell();
2283 }
2284 // treat an undo as an escape
2285 else if( evt->IsAction( &ACTIONS::undo ) )
2286 {
2287 if( wasLocked )
2288 item->SetLocked( true );
2289
2290 break;
2291 }
2292 else
2293 {
2294 evt->SetPassEvent();
2295 }
2296 }
2297 else
2298 {
2299 evt->SetPassEvent();
2300 }
2301
2302 handleCommonEvents( *evt );
2303 }
2304
2305 if( footprint )
2306 {
2307 for( BOARD_ITEM* drawing : footprint->GraphicalItems() )
2308 view()->Hide( drawing, false );
2309
2310 view()->Hide( &footprint->Reference(), false );
2311 view()->Hide( &footprint->Value(), false );
2312
2313 for( ZONE* zone : footprint->Zones() )
2314 view()->Hide( zone, false );
2315
2316 for( PAD* pad : footprint->Pads() )
2317 view()->Hide( pad, false );
2318
2319 view()->ClearPreview();
2320 view()->ShowPreview( false );
2321
2322 connectivityData->ClearLocalRatsnest();
2323 }
2324
2325 // Clear temporary COURTYARD_CONFLICT flag and ensure the conflict shadow is cleared
2326 courtyardClearanceDRC.ClearConflicts( getView() );
2327
2330
2331 m_gridHelper->SetAuxAxes( false );
2332 controls()->SetAutoPan( false );
2333 controls()->ForceCursorPosition( false );
2334 frame()->UndoRedoBlock( false );
2335 highlightNet( false );
2336
2337 return 0;
2338}
2339
2340
2342{
2343 const SELECTION& selection = m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
2344
2345 if( selection.Size() != 1 )
2346 return 0;
2347
2348 const BOARD_CONNECTED_ITEM* item =
2349 static_cast<const BOARD_CONNECTED_ITEM*>( selection.Front() );
2350
2351 if( item->Type() != PCB_TRACE_T )
2352 return 0;
2353
2355
2356 Activate();
2357
2359
2360 TOOL_MANAGER* toolManager = frame()->GetToolManager();
2361 GAL* gal = toolManager->GetView()->GetGAL();
2362
2364 m_gridHelper->SetSnap( !aEvent.Modifier( MD_SHIFT ) );
2365
2366 if( toolManager->IsContextMenuActive() )
2367 {
2368 // If we're here from a context menu then we need to get the position of the
2369 // cursor when the context menu was invoked. This is used to figure out the
2370 // break point on the track.
2372 }
2373 else
2374 {
2375 // If we're here from a hotkey, then get the current mouse position so we know
2376 // where to break the track.
2377 m_startSnapPoint = snapToItem( m_startItem, controls()->GetCursorPosition() );
2378 }
2379
2380 if( m_startItem && m_startItem->IsLocked() )
2381 {
2382 KIDIALOG dlg( frame(), _( "The selected item is locked." ), _( "Confirmation" ),
2383 wxOK | wxCANCEL | wxICON_WARNING );
2384 dlg.SetOKLabel( _( "Break Track" ) );
2385 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
2386
2387 if( dlg.ShowModal() == wxID_CANCEL )
2388 return 0;
2389 }
2390
2391 frame()->UndoRedoBlock( true );
2392 breakTrack();
2393
2396
2397 frame()->UndoRedoBlock( false );
2398
2399 return 0;
2400}
2401
2402
2404{
2406 DIALOG_TRACK_VIA_SIZE sizeDlg( frame(), bds );
2407
2408 if( sizeDlg.ShowModal() == wxID_OK )
2409 {
2410 bds.m_TempOverrideTrackWidth = true;
2411 bds.UseCustomTrackViaSize( true );
2412
2415 }
2416
2417 return 0;
2418}
2419
2420
2422{
2424
2425 if( !m_router->GetCurrentNets().empty() )
2427
2428 m_router->UpdateSizes( sizes );
2429
2430 // Changing the track width can affect the placement, so call the
2431 // move routine without changing the destination
2432 // Update end item first to avoid moving to an invalid/missing item
2433 updateEndItem( aEvent );
2435
2437
2438 return 0;
2439}
2440
2441
2443{
2444 std::vector<MSG_PANEL_ITEM> items;
2445
2447 {
2450 std::vector<int> nets = m_router->GetCurrentNets();
2451 wxString description;
2452 wxString secondary;
2453
2455 {
2456 wxASSERT( nets.size() >= 2 );
2457
2458 NETINFO_ITEM* netA = board()->FindNet( nets[0] );
2459 NETINFO_ITEM* netB = board()->FindNet( nets[1] );
2460 wxASSERT( netA );
2461 wxASSERT( netB );
2462
2463 description = wxString::Format( _( "Routing Diff Pair: %s" ),
2464 netA->GetNetname() + wxT( ", " ) + netB->GetNetname() );
2465
2466 wxString netclass;
2467 NETCLASS* netclassA = netA->GetNetClass();
2468 NETCLASS* netclassB = netB->GetNetClass();
2469
2470 if( netclassA == netclassB )
2471 netclass = netclassA->GetName();
2472 else
2473 netclass = netclassA->GetName() + wxT( ", " ) + netclassB->GetName();
2474
2475 secondary = wxString::Format( _( "Resolved Netclass: %s" ),
2476 UnescapeString( netclass ) );
2477 }
2478 else if( !nets.empty() )
2479 {
2480 NETINFO_ITEM* net = board()->FindNet( nets[0] );
2481 wxASSERT( net );
2482
2483 description = wxString::Format( _( "Routing Track: %s" ),
2484 net->GetNetname() );
2485
2486 secondary = wxString::Format( _( "Resolved Netclass: %s" ),
2487 UnescapeString( net->GetNetClass()->GetName() ) );
2488 }
2489 else
2490 {
2491 description = _( "Routing Track" );
2492 secondary = _( "(no net)" );
2493 }
2494
2495 items.emplace_back( description, secondary );
2496
2497 wxString cornerMode;
2498
2500 {
2501 cornerMode = _( "Free-angle" );
2502 }
2503 else
2504 {
2505 switch( m_router->Settings().GetCornerMode() )
2506 {
2507 case DIRECTION_45::CORNER_MODE::MITERED_45: cornerMode = _( "45-degree" ); break;
2508 case DIRECTION_45::CORNER_MODE::ROUNDED_45: cornerMode = _( "45-degree rounded" ); break;
2509 case DIRECTION_45::CORNER_MODE::MITERED_90: cornerMode = _( "90-degree" ); break;
2510 case DIRECTION_45::CORNER_MODE::ROUNDED_90: cornerMode = _( "90-degree rounded" ); break;
2511 default: break;
2512 }
2513 }
2514
2515 items.emplace_back( _( "Corner Style" ), cornerMode );
2516
2517#define FORMAT_VALUE( x ) frame()->MessageTextFromValue( x )
2518
2520 {
2521 items.emplace_back( wxString::Format( _( "Track Width: %s" ),
2522 FORMAT_VALUE( sizes.DiffPairWidth() ) ),
2523 wxString::Format( _( "(from %s)" ),
2524 sizes.GetDiffPairWidthSource() ) );
2525
2526 items.emplace_back( wxString::Format( _( "Min Clearance: %s" ),
2527 FORMAT_VALUE( sizes.MinClearance() ) ),
2528 wxString::Format( _( "(from %s)" ),
2529 sizes.GetClearanceSource() ) );
2530
2531 items.emplace_back( wxString::Format( _( "Diff Pair Gap: %s" ),
2532 FORMAT_VALUE( sizes.DiffPairGap() ) ),
2533 wxString::Format( _( "(from %s)" ),
2534 sizes.GetDiffPairGapSource() ) );
2535 }
2536 else
2537 {
2538 items.emplace_back( wxString::Format( _( "Track Width: %s" ),
2539 FORMAT_VALUE( sizes.TrackWidth() ) ),
2540 wxString::Format( _( "(from %s)" ),
2541 sizes.GetWidthSource() ) );
2542
2543 items.emplace_back( wxString::Format( _( "Min Clearance: %s" ),
2544 FORMAT_VALUE( sizes.MinClearance() ) ),
2545 wxString::Format( _( "(from %s)" ),
2546 sizes.GetClearanceSource() ) );
2547 }
2548
2549#undef FORMAT_VALUE
2550
2551 frame()->SetMsgPanel( items );
2552 }
2553 else
2554 {
2555 frame()->SetMsgPanel( board() );
2556 return;
2557 }
2558}
2559
2560
2562{
2564
2578
2585
2620
2623}
#define LEGACY_HK_NAME(x)
Definition: actions.h:32
@ select_w_layer
@ width_track_via
@ change_entry_orient
@ switch_corner_rounding_shape
@ via_microvia
#define APPEND_UNDO
Definition: board_commit.h:40
BOX2< VECTOR2I > BOX2I
Definition: box2.h:847
static TOOL_ACTION paste
Definition: actions.h:69
static TOOL_ACTION cancelInteractive
Definition: actions.h:63
static TOOL_ACTION copy
Definition: actions.h:68
static TOOL_ACTION pasteSpecial
Definition: actions.h:70
static TOOL_ACTION undo
Definition: actions.h:65
static TOOL_ACTION cut
Definition: actions.h:67
Defines the structure of a menu based on ACTIONs.
Definition: action_menu.h:49
void Clear()
Remove all the entries from the menu (as well as its title).
void SetTitle(const wxString &aTitle) override
Set title for the menu.
Definition: action_menu.cpp:87
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
Definition: action_menu.cpp:73
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
void SetLayerVisible(int aLayer, bool isVisible)
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
Container for design settings for a BOARD object.
void UseCustomTrackViaSize(bool aEnabled)
Enables/disables custom track/via size settings.
void SetCustomDiffPairWidth(int aWidth)
Sets custom track width for differential pairs (i.e.
void SetDiffPairIndex(unsigned aIndex)
std::shared_ptr< DRC_ENGINE > m_DRCEngine
std::vector< DIFF_PAIR_DIMENSION > m_DiffPairDimensionsList
void SetCustomDiffPairGap(int aGap)
Sets custom gap for differential pairs (i.e.
void SetTrackWidthIndex(unsigned aIndex)
Set the current track width list index to aIndex.
void SetViaSizeIndex(unsigned aIndex)
Set the current via size list index to aIndex.
unsigned GetTrackWidthIndex() const
bool UseNetClassVia() const
Return true if netclass values should be used to obtain appropriate via size.
unsigned GetViaSizeIndex() const
bool UseNetClassTrack() const
Return true if netclass values should be used to obtain appropriate track width.
bool UseNetClassDiffPair() const
Return true if netclass values should be used to obtain appropriate diff pair dimensions.
void UseCustomDiffPairDimensions(bool aEnabled)
Enables/disables custom differential pair dimensions.
std::vector< int > m_TrackWidthList
unsigned GetDiffPairIndex() const
std::vector< VIA_DIMENSION > m_ViasDimensionsList
void SetCustomDiffPairViaGap(int aGap)
Sets custom via gap for differential pairs (i.e.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:58
virtual void SetLocked(bool aLocked)
Definition: board_item.h:254
virtual void Move(const VECTOR2I &aMoveVector)
Move this object.
Definition: board_item.h:266
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:214
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:43
virtual bool IsLocked() const
Definition: board_item.cpp:71
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:265
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1402
PROJECT * GetProject() const
Definition: board.h:440
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:628
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition: board.h:424
const Vec & GetOrigin() const
Definition: box2.h:183
const Vec & GetSize() const
Definition: box2.h:179
CN_EDGE represents a point-to-point connection, whether realized or unrealized (ie: tracks etc.
void Empty()
Clear the list.
Definition: collector.h:89
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:81
int CountType(KICAD_T aType)
Count the number of items matching aType.
Definition: collector.h:221
void Append(EDA_ITEM *item)
Add an item to the end of the list.
Definition: collector.h:99
Implementing DIALOG_TRACK_VIA_SIZE_BASE.
PCB_EDIT_FRAME & m_frame
OPT_TOOL_EVENT eventHandler(const wxMenuEvent &aEvent) override
Event handler stub.
ACTION_MENU * create() const override
< Return an instance of this class. It has to be overridden in inheriting classes.
DIFF_PAIR_MENU(PCB_EDIT_FRAME &aFrame)
void update() override
Update menu state stub.
wxString GetName() const
Definition: drc_rule.h:147
MINOPTMAX< int > m_Value
Definition: drc_rule.h:170
bool IsNull() const
Definition: drc_rule.h:134
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
void UpdateConflicts(KIGFX::VIEW *aView, bool aHighlightMoved)
void ShowInfoBarError(const wxString &aErrorMsg, bool aShowCloseButton=false, WX_INFOBAR::MESSAGE_TYPE aType=WX_INFOBAR::MESSAGE_TYPE::GENERIC)
Show the WX_INFOBAR displayed on the top of the canvas with a message and an error icon on the left o...
WX_INFOBAR * GetInfoBar()
void AddStandardSubMenus(TOOL_MENU &aMenu)
Construct a "basic" menu for a tool, containing only items that apply to all tools (e....
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
virtual void UpdateMsgPanel()
Redraw the message panel.
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:85
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition: eda_item.h:183
EDA_ANGLE GetOrientation() const
Definition: footprint.h:191
PADS & Pads()
Definition: footprint.h:170
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition: footprint.cpp:1530
FP_TEXT & Value()
read/write accessors:
Definition: footprint.h:558
FP_ZONES & Zones()
Definition: footprint.h:176
VECTOR2I GetPosition() const override
Definition: footprint.h:188
DRAWINGS & GraphicalItems()
Definition: footprint.h:173
FP_TEXT & Reference()
Definition: footprint.h:559
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: fp_text.cpp:343
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:204
static const std::vector< KICAD_T > DraggableItems
A scan list for items that can be dragged.
Definition: collectors.h:270
void SetSnap(bool aSnap)
Definition: grid_helper.h:64
void SetUseGrid(bool aSnapToGrid)
Definition: grid_helper.h:67
void SetAuxAxes(bool aEnable, const VECTOR2I &aOrigin=VECTOR2I(0, 0))
Definition: grid_helper.cpp:67
const std::string FormatAsString() const
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition: confirm.h:46
void DoNotShowCheckbox(wxString file, int line)
Checks the 'do not show again' setting for the dialog.
Definition: confirm.cpp:56
int ShowModal() override
Definition: confirm.cpp:100
Abstract interface for drawing on a 2D-surface.
BOX2D GetVisibleWorldExtents() const
bool GetGridSnapping() const
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
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.
An interface for classes handling user events controlling the view behavior such as zooming,...
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
virtual void WarpMouseCursor(const VECTOR2D &aPosition, bool aWorldCoordinates=false, bool aWarpView=false)=0
If enabled (.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
virtual void SetCursorPosition(const VECTOR2D &aPosition, bool aWarpView=true, bool aTriggeredByArrows=false, long aArrowCommand=0)=0
Move cursor to the requested position expressed in world coordinates.
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
void ShowPreview(bool aShow=true)
Definition: view.cpp:1632
VECTOR2D ToScreen(const VECTOR2D &aCoord, bool aAbsolute=true) const
Convert a world space point/vector to a point/vector in screen space coordinates.
Definition: view.cpp:464
virtual int GetTopLayer() const
Definition: view.cpp:813
void AddToPreview(EDA_ITEM *aItem, bool aTakeOwnership=true)
Definition: view.cpp:1618
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:195
void Hide(VIEW_ITEM *aItem, bool aHide=true)
Temporarily hide the item in the view (e.g.
Definition: view.cpp:1533
void InitPreview()
Definition: view.cpp:1611
void ClearPreview()
Definition: view.cpp:1596
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:213
Represent a contiguous set of PCB layers.
Definition: pns_layerset.h:32
int Start() const
Definition: pns_layerset.h:82
bool Overlaps(const LAYER_RANGE &aOther) const
Definition: pns_layerset.h:67
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition: layer_ids.h:491
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:530
static LSET AllLayersMask()
Definition: lset.cpp:808
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:411
static LSET AllNonCuMask()
Return a mask holding all layer minus CU layers.
Definition: lset.cpp:794
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:773
T Opt() const
Definition: minoptmax.h:35
A collection of nets and the parameters used to route or test these nets.
Definition: netclass.h:47
const wxString GetName() const
Definition: netclass.h:65
Handle the data for a net.
Definition: netinfo.h:66
const wxString & GetNetname() const
Definition: netinfo.h:119
NETCLASS * GetNetClass()
Definition: netinfo.h:111
Definition: pad.h:59
bool m_ShowCourtyardCollisions
static TOOL_ACTION layerToggle
Definition: pcb_actions.h:318
static TOOL_ACTION drag45Degree
Definition: pcb_actions.h:162
static TOOL_ACTION layerInner12
Definition: pcb_actions.h:294
static TOOL_ACTION routerUndoLastSegment
Definition: pcb_actions.h:218
static TOOL_ACTION layerInner8
Definition: pcb_actions.h:290
static TOOL_ACTION layerInner3
Definition: pcb_actions.h:285
static TOOL_ACTION layerPrev
Definition: pcb_actions.h:315
static TOOL_ACTION routerSettingsDialog
Activation of the Push and Shove settings dialogs.
Definition: pcb_actions.h:227
static TOOL_ACTION layerInner2
Definition: pcb_actions.h:284
static TOOL_ACTION routerAttemptFinish
Definition: pcb_actions.h:221
static TOOL_ACTION routeDiffPair
Activation of the Push and Shove router (differential pair mode)
Definition: pcb_actions.h:207
static TOOL_ACTION selectionCursor
Select a single item under the cursor position.
Definition: pcb_actions.h:56
static TOOL_ACTION trackViaSizeChanged
Definition: pcb_actions.h:330
static TOOL_ACTION layerChanged
Definition: pcb_actions.h:320
static TOOL_ACTION layerInner25
Definition: pcb_actions.h:307
static TOOL_ACTION breakTrack
Break a single track into two segments at the cursor.
Definition: pcb_actions.h:160
static TOOL_ACTION routerRouteSelectedFromEnd
Definition: pcb_actions.h:223
static TOOL_ACTION routerHighlightMode
Actions to enable switching modes via hotkey assignments.
Definition: pcb_actions.h:232
static TOOL_ACTION routerWalkaroundMode
Definition: pcb_actions.h:234
static TOOL_ACTION routerShoveMode
Definition: pcb_actions.h:233
static TOOL_ACTION layerInner24
Definition: pcb_actions.h:306
static TOOL_ACTION properties
Activation of the edit tool.
Definition: pcb_actions.h:145
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:59
static TOOL_ACTION layerInner29
Definition: pcb_actions.h:311
static TOOL_ACTION routerAutorouteSelected
Definition: pcb_actions.h:224
static TOOL_ACTION layerInner11
Definition: pcb_actions.h:293
static TOOL_ACTION routerDiffPairDialog
Definition: pcb_actions.h:228
static TOOL_ACTION routerContinueFromEnd
Definition: pcb_actions.h:220
static TOOL_ACTION layerInner16
Definition: pcb_actions.h:298
static TOOL_ACTION layerInner26
Definition: pcb_actions.h:308
static TOOL_ACTION layerInner18
Definition: pcb_actions.h:300
static TOOL_ACTION layerInner14
Definition: pcb_actions.h:296
static TOOL_ACTION selectLayerPair
Definition: pcb_actions.h:157
static TOOL_ACTION layerInner6
Definition: pcb_actions.h:288
static TOOL_ACTION dragFreeAngle
Definition: pcb_actions.h:163
static TOOL_ACTION clearHighlight
Definition: pcb_actions.h:486
static TOOL_ACTION layerInner22
Definition: pcb_actions.h:304
static TOOL_ACTION layerInner5
Definition: pcb_actions.h:287
static TOOL_ACTION layerInner20
Definition: pcb_actions.h:302
static TOOL_ACTION layerInner7
Definition: pcb_actions.h:289
static TOOL_ACTION layerInner27
Definition: pcb_actions.h:309
static TOOL_ACTION layerInner1
Definition: pcb_actions.h:283
static TOOL_ACTION layerInner10
Definition: pcb_actions.h:292
static TOOL_ACTION layerInner15
Definition: pcb_actions.h:297
static TOOL_ACTION layerInner17
Definition: pcb_actions.h:299
static TOOL_ACTION layerBottom
Definition: pcb_actions.h:313
static TOOL_ACTION layerInner19
Definition: pcb_actions.h:301
static TOOL_ACTION layerInner9
Definition: pcb_actions.h:291
static TOOL_ACTION routerInlineDrag
Activation of the Push and Shove router (inline dragging mode)
Definition: pcb_actions.h:238
static TOOL_ACTION layerInner30
Definition: pcb_actions.h:312
static TOOL_ACTION layerTop
Definition: pcb_actions.h:282
static TOOL_ACTION cycleRouterMode
Definition: pcb_actions.h:235
static TOOL_ACTION layerInner4
Definition: pcb_actions.h:286
static TOOL_ACTION routeSingleTrack
Activation of the Push and Shove router.
Definition: pcb_actions.h:204
static TOOL_ACTION layerInner13
Definition: pcb_actions.h:295
static TOOL_ACTION layerInner21
Definition: pcb_actions.h:303
static TOOL_ACTION layerNext
Definition: pcb_actions.h:314
static TOOL_ACTION routerRouteSelected
Definition: pcb_actions.h:222
static TOOL_ACTION layerInner23
Definition: pcb_actions.h:305
static TOOL_ACTION layerInner28
Definition: pcb_actions.h:310
Common, abstract interface for edit frames.
APPEARANCE_CONTROLS * GetAppearancePanel()
void UndoRedoBlock(bool aBlock=true)
Enable/disable undo and redo operations.
PCB_LAYER_ID SelectOneLayer(PCB_LAYER_ID aDefaultLayer, LSET aNotAllowedLayersMask=LSET(), wxPoint aDlgPosition=wxDefaultPosition)
Show the dialog box for a layer selection.
Definition: sel_layer.cpp:274
PCBNEW_SETTINGS * GetPcbNewSettings() const
virtual PCB_LAYER_ID GetActiveLayer() const
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
PCB_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
BOARD * GetBoard() const
virtual void SetActiveLayer(PCB_LAYER_ID aLayer)
The main frame for Pcbnew.
void SetActiveLayer(PCB_LAYER_ID aLayer) override
Change the currently active layer to aLayer and also update the APPEARANCE_CONTROLS.
A PLUGIN derivation for saving and loading Pcbnew s-expression formatted files.
Definition: pcb_plugin.h:170
void Save(const wxString &aFileName, BOARD *aBoard, const STRING_UTF8_MAP *aProperties=nullptr) override
Write aBoard to a storage file in a format that this PLUGIN implementation knows about or it can be u...
Definition: pcb_plugin.cpp:342
PCB_LAYER_ID m_Route_Layer_TOP
Definition: pcb_screen.h:43
PCB_LAYER_ID m_Route_Layer_BOTTOM
Definition: pcb_screen.h:44
The selection tool: currently supports:
KIGFX::PCB_VIEW * view() const
PCB_BASE_EDIT_FRAME * frame() const
KIGFX::VIEW_CONTROLS * controls() const
BOARD * board() const
PCBNEW_SETTINGS::DISPLAY_OPTIONS & displayOptions() const
const PCB_SELECTION & selection() const
FOOTPRINT * footprint() const
const VECTOR2I & GetStart() const
Definition: pcb_track.h:112
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:109
EDA_ITEM_FLAGS IsPointOnEnds(const VECTOR2I &point, int min_dist=0) const
Function IsPointOnEnds returns STARTPOINT if point if near (dist = min_dist) start point,...
Definition: pcb_track.cpp:207
void SetLayerPair(PCB_LAYER_ID aTopLayer, PCB_LAYER_ID aBottomLayer)
Function SetLayerPair For a via m_layer contains the top layer, the other layer is in m_bottomLayer.
Definition: pcb_track.cpp:521
void SetViaType(VIATYPE aViaType)
Definition: pcb_track.h:391
void Add(const LINE &aLine)
Definition: pns_itemset.cpp:32
Base class for PNS router board items.
Definition: pns_item.h:56
PnsKind Kind() const
Return the type (kind) of the item.
Definition: pns_item.h:132
@ SEGMENT_T
Definition: pns_item.h:66
const LAYER_RANGE & Layers() const
Definition: pns_item.h:156
bool OfKind(int aKindMask) const
Return true if the item's type matches the mask aKindMask.
Definition: pns_item.h:140
int Net() const
Definition: pns_item.h:154
bool IsLocked() const
Definition: pns_item.h:229
ITEM * FindItemByParent(const BOARD_ITEM *aParent)
Definition: pns_node.cpp:1619
virtual const VECTOR2I & CurrentEnd() const =0
Function CurrentEnd()
virtual bool HasPlacedAnything() const
virtual const VECTOR2I & CurrentStart() const =0
Function CurrentStart()
void SetMode(ROUTER_MODE aMode)
bool SwitchLayer(int layer)
Definition: pns_router.cpp:944
void StopRouting()
Definition: pns_router.cpp:901
void ClearViewDecorations()
Definition: pns_router.cpp:929
void ToggleCornerMode()
PLACEMENT_ALGO * Placer()
Definition: pns_router.h:209
void ClearWorld()
Definition: pns_router.cpp:102
void UpdateSizes(const SIZES_SETTINGS &aSizes)
Applies stored settings.
Definition: pns_router.cpp:719
LOGGER * Logger()
Definition: pns_router.cpp:990
ROUTER_MODE Mode() const
Definition: pns_router.h:132
void UndoLastSegment()
Definition: pns_router.cpp:882
const std::vector< int > GetCurrentNets() const
Definition: pns_router.cpp:968
void CommitRouting()
Definition: pns_router.cpp:892
bool Finish()
Definition: pns_router.cpp:519
void SyncWorld()
Definition: pns_router.cpp:92
bool ContinueFromEnd()
Definition: pns_router.cpp:557
const wxString & FailureReason() const
Definition: pns_router.h:207
bool IsPlacingVia() const
Definition: pns_router.cpp:996
void FlipPosture()
Definition: pns_router.cpp:935
bool GetUpdatedItems(std::vector< PNS::ITEM * > &aRemoved, std::vector< PNS::ITEM * > &aAdded)
Definition: pns_router.cpp:768
ROUTING_SETTINGS & Settings()
Definition: pns_router.h:185
bool FixRoute(const VECTOR2I &aP, ITEM *aItem, bool aForceFinish=false)
Definition: pns_router.cpp:856
bool RoutingInProgress() const
Definition: pns_router.cpp:114
RouterState GetState() const
Definition: pns_router.h:134
void BreakSegment(ITEM *aItem, const VECTOR2I &aP)
bool StartDragging(const VECTOR2I &aP, ITEM *aItem, int aDragMode=DM_ANY)
Definition: pns_router.cpp:149
bool StartRouting(const VECTOR2I &aP, ITEM *aItem, int aLayer)
Definition: pns_router.cpp:388
void SetVisibleViewArea(const BOX2I &aExtents)
Definition: pns_router.h:213
int GetCurrentLayer() const
Definition: pns_router.cpp:979
SIZES_SETTINGS & Sizes()
Definition: pns_router.h:204
void ToggleViaPlacement()
Definition: pns_router.cpp:953
NODE * GetWorld() const
Definition: pns_router.h:157
bool Move(const VECTOR2I &aP, ITEM *aItem)
Definition: pns_router.cpp:455
Contain all persistent settings of the router, such as the mode, optimization effort,...
void SetMode(PNS_MODE aMode)
Return the optimizer effort. Bigger means cleaner traces, but slower routing.
PNS_MODE Mode() const
Set the routing mode.
DIRECTION_45::CORNER_MODE GetCornerMode() const
void SetViaType(VIATYPE aViaType)
void SetTrackWidth(int aWidth)
void SetDiffPairWidth(int aWidth)
void SetDiffPairWidthSource(const wxString &aSource)
void SetDiffPairGapSource(const wxString &aSource)
void SetDiffPairGap(int aGap)
void SetViaDrill(int aDrill)
wxString GetClearanceSource() const
wxString GetDiffPairGapSource() const
wxString GetDiffPairWidthSource() const
void AddLayerPair(int aL1, int aL2)
std::optional< int > PairedLayer(int aLayerId)
bool TrackWidthIsExplicit() const
void SetViaDiameter(int aDiameter)
wxString GetWidthSource() const
void SetWidthSource(const wxString &aSource)
virtual void updateStartItem(const TOOL_EVENT &aEvent, bool aIgnorePads=false)
virtual void highlightNet(bool aEnabled, int aNetcode=-1)
const VECTOR2I snapToItem(ITEM *aSnapToItem, const VECTOR2I &aP)
SIZES_SETTINGS m_savedSizes
Definition: pns_tool_base.h:69
PNS_KICAD_IFACE * m_iface
Definition: pns_tool_base.h:78
ITEM * m_startItem
Definition: pns_tool_base.h:70
virtual void updateEndItem(const TOOL_EVENT &aEvent)
ROUTER * m_router
Definition: pns_tool_base.h:79
VECTOR2I m_endSnapPoint
Definition: pns_tool_base.h:75
PCB_GRID_HELPER * m_gridHelper
Definition: pns_tool_base.h:77
VECTOR2I m_startSnapPoint
Definition: pns_tool_base.h:71
bool ImportSizes(PNS::SIZES_SETTINGS &aSizes, PNS::ITEM *aStartItem, int aNet) override
PNS::RULE_RESOLVER * GetRuleResolver() override
void SetStartLayer(int aLayer)
BOARD * GetBoard() const
void SetCommitFlags(int aCommitFlags)
bool SaveAs(const wxString &aDirectory, const wxString &aFile)
Container for project specific data.
Definition: project.h:63
virtual PROJECT_FILE & GetProjectFile() const
Definition: project.h:148
Describe ratsnest for a single net.
Definition: ratsnest_data.h:63
const std::vector< CN_EDGE > & GetEdges() const
Definition: ratsnest_data.h:90
int onViaCommand(const TOOL_EVENT &aEvent)
int InlineDrag(const TOOL_EVENT &aEvent)
std::shared_ptr< ACTION_MENU > m_trackViaMenu
Definition: router_tool.h:92
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
int onTrackViaSizeChanged(const TOOL_EVENT &aEvent)
int CustomTrackWidthDialog(const TOOL_EVENT &aEvent)
PNS::PNS_MODE GetRouterMode()
void saveRouterDebugLog()
void performDragging(int aMode=PNS::DM_ANY)
PCB_LAYER_ID m_originalActiveLayer
Definition: router_tool.h:95
int onLayerCommand(const TOOL_EVENT &aEvent)
int CycleRouterMode(const TOOL_EVENT &aEvent)
bool m_inRouterTool
Definition: router_tool.h:97
int handleLayerSwitch(const TOOL_EVENT &aEvent, bool aForceVia)
bool prepareInteractive()
int getStartLayer(const PNS::ITEM *aItem)
void switchLayerOnViaPlacement()
int RouteSelected(const TOOL_EVENT &aEvent)
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
static void NeighboringSegmentFilter(const VECTOR2I &aPt, GENERAL_COLLECTOR &aCollector)
bool finishInteractive()
int ChangeRouterMode(const TOOL_EVENT &aEvent)
std::shared_ptr< ACTION_MENU > m_diffPairMenu
Definition: router_tool.h:91
void handleCommonEvents(TOOL_EVENT &evt)
bool Init() override
Init() is called once upon a registration of the tool.
int InlineBreakTrack(const TOOL_EVENT &aEvent)
void performRouting()
bool RoutingInProgress()
Returns whether routing is currently active.
void breakTrack()
void UpdateMessagePanel()
int MainLoop(const TOOL_EVENT &aEvent)
bool CanInlineDrag(int aDragMode)
int SettingsDialog(const TOOL_EVENT &aEvent)
void updateSizesAfterLayerSwitch(PCB_LAYER_ID targetLayer)
int DpDimensionsDialog(const TOOL_EVENT &aEvent)
int m_lastTargetLayer
Definition: router_tool.h:94
int SelectCopperLayerPair(const TOOL_EVENT &aEvent)
Definition: sel_layer.cpp:326
static bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
const std::vector< EDA_ITEM * > GetItemsSortedBySelectionOrder() const
Definition: selection.cpp:202
EDA_ITEM * Front() const
Definition: selection.h:206
int Size() const
Returns the number of selected parts.
Definition: selection.h:113
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:107
virtual void PopTool(const TOOL_EVENT &aEvent)
Pops a tool from the stack.
bool GetMoveWarpsCursor() const
Indicate that a move operation should warp the mouse pointer to the origin of the move object.
Definition: tools_holder.h:153
virtual void PushTool(const TOOL_EVENT &aEvent)
NB: the definition of "tool" is different at the user level.
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:54
Represent a single user action.
Definition: tool_action.h:68
TOOL_EVENT MakeEvent() const
Return the event associated with the action (i.e.
Definition: tool_action.cpp:72
Base abstract interface for all kinds of tools.
Definition: tool_base.h:66
virtual void Reset(RESET_REASON aReason)=0
Bring the tool to a known, initial state.
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:42
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:214
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
bool IsToolActive() const
Definition: tool_base.cpp:31
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:78
@ RUN
Tool is invoked after being inactive.
Definition: tool_base.h:79
Generic, UI-independent tool event.
Definition: tool_event.h:156
bool HasPosition() const
Definition: tool_event.h:243
bool DisableGridSnapping() const
Definition: tool_event.h:344
T Parameter() const
Return a non-standard parameter assigned to the event.
Definition: tool_event.h:442
int KeyCode() const
Definition: tool_event.h:349
bool Matches(const TOOL_EVENT &aEvent) const
Test whether two events match in terms of category & action or command.
Definition: tool_event.h:365
const VECTOR2D Position() const
Returns the point where dragging has started.
Definition: tool_event.h:266
bool IsKeyPressed() const
Definition: tool_event.h:354
TOOL_EVENT_CATEGORY Category() const
Returns more specific information about the type of an event.
Definition: tool_event.h:230
int Modifier(int aMask=MD_MODIFIER_MASK) const
Definition: tool_event.h:339
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
Definition: tool_event.cpp:88
void SetPassEvent(bool aPass=true)
Returns if it this event has a valid position (true for mouse events and context-menu or hotkey-based...
Definition: tool_event.h:239
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 m_menu
The functions below are not yet implemented - their interface may change.
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.
Master controller class:
Definition: tool_manager.h:55
VECTOR2D GetMenuCursorPos() const
Definition: tool_manager.h:442
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:142
void PrimeTool(const VECTOR2D &aPosition)
"Prime" a tool by sending a cursor left-click event with the mouse position set to the passed in posi...
bool IsContextMenuActive() const
True while processing a context menu.
Definition: tool_manager.h:413
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:285
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
void ShowContextMenu(SELECTION &aSelection)
Helper function to set and immediately show a CONDITIONAL_MENU in concert with the given SELECTION.
Definition: tool_menu.cpp:57
OPT_TOOL_EVENT eventHandler(const wxMenuEvent &aEvent) override
Event handler stub.
TRACK_WIDTH_MENU(PCB_EDIT_FRAME &aFrame)
void update() override
Update menu state stub.
PCB_EDIT_FRAME & m_frame
ACTION_MENU * create() const override
< Return an instance of this class. It has to be overridden in inheriting classes.
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
A lower-precision version of StringFromValue().
A modified version of the wxInfoBar class that allows us to:
Definition: infobar.h:75
void ShowMessageFor(const wxString &aMessage, int aTime, int aFlags=wxICON_INFORMATION, MESSAGE_TYPE aType=WX_INFOBAR::MESSAGE_TYPE::GENERIC)
Show the infobar with the provided message and icon for a specific period of time.
Definition: infobar.cpp:128
static bool IsZoneFillAction(const TOOL_EVENT *aEvent)
Handle a list of polygons defining a copper zone.
Definition: zone.h:57
int OKOrCancelDialog(wxWindow *aParent, const wxString &aWarning, const wxString &aMessage, const wxString &aDetailedMessage, const wxString &aOKLabel, const wxString &aCancelLabel, bool *aApplyToAll)
Display a warning dialog with aMessage and returns the user response.
Definition: confirm.cpp:253
This file is part of the common library.
@ VIA_DIAMETER_CONSTRAINT
Definition: drc_rule.h:62
@ DIFF_PAIR_GAP_CONSTRAINT
Definition: drc_rule.h:65
@ TRACK_WIDTH_CONSTRAINT
Definition: drc_rule.h:55
@ HOLE_SIZE_CONSTRAINT
Definition: drc_rule.h:50
#define ENDPOINT
ends. (Used to support dragging.)
std::uint32_t EDA_ITEM_FLAGS
#define STARTPOINT
When a line is selected, these flags indicate which.
static FILENAME_RESOLVER * resolver
Definition: export_idf.cpp:52
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:825
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:59
@ In22_Cu
Definition: layer_ids.h:86
@ In11_Cu
Definition: layer_ids.h:75
@ In29_Cu
Definition: layer_ids.h:93
@ In30_Cu
Definition: layer_ids.h:94
@ In17_Cu
Definition: layer_ids.h:81
@ In9_Cu
Definition: layer_ids.h:73
@ In19_Cu
Definition: layer_ids.h:83
@ In7_Cu
Definition: layer_ids.h:71
@ In28_Cu
Definition: layer_ids.h:92
@ In26_Cu
Definition: layer_ids.h:90
@ B_Cu
Definition: layer_ids.h:95
@ In21_Cu
Definition: layer_ids.h:85
@ In23_Cu
Definition: layer_ids.h:87
@ In15_Cu
Definition: layer_ids.h:79
@ In2_Cu
Definition: layer_ids.h:66
@ In10_Cu
Definition: layer_ids.h:74
@ In4_Cu
Definition: layer_ids.h:68
@ UNDEFINED_LAYER
Definition: layer_ids.h:60
@ In16_Cu
Definition: layer_ids.h:80
@ In24_Cu
Definition: layer_ids.h:88
@ In1_Cu
Definition: layer_ids.h:65
@ In13_Cu
Definition: layer_ids.h:77
@ In8_Cu
Definition: layer_ids.h:72
@ In14_Cu
Definition: layer_ids.h:78
@ In12_Cu
Definition: layer_ids.h:76
@ In27_Cu
Definition: layer_ids.h:91
@ In6_Cu
Definition: layer_ids.h:70
@ In5_Cu
Definition: layer_ids.h:69
@ In3_Cu
Definition: layer_ids.h:67
@ In20_Cu
Definition: layer_ids.h:84
@ F_Cu
Definition: layer_ids.h:64
@ In18_Cu
Definition: layer_ids.h:82
@ In25_Cu
Definition: layer_ids.h:89
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:932
The Cairo implementation of the graphics abstraction layer.
Definition: color4d.cpp:266
PNS_MODE
< Routing modes
@ RM_MarkObstacles
Ignore collisions, mark obstacles.
@ RM_Walkaround
Only walk around.
@ RM_Shove
Only shove.
ROUTER_MODE
Definition: pns_router.h:62
@ PNS_MODE_ROUTE_DIFF_PAIR
Definition: pns_router.h:64
@ DM_ANY
Definition: pns_router.h:77
@ DM_FREE_ANGLE
Definition: pns_router.h:75
VIATYPE
Definition: pcb_track.h:63
@ BLIND_BURIED
@ ID_POPUP_PCB_SELECT_WIDTH1
Definition: pcbnew_id.h:29
@ ID_POPUP_PCB_SELECT_DIFFPAIR16
Definition: pcbnew_id.h:78
@ ID_POPUP_PCB_SELECT_USE_NETCLASS_VALUES
Definition: pcbnew_id.h:28
@ ID_POPUP_PCB_SELECT_WIDTH16
Definition: pcbnew_id.h:44
@ ID_POPUP_PCB_SELECT_AUTO_WIDTH
Definition: pcbnew_id.h:27
@ ID_POPUP_PCB_SELECT_CUSTOM_WIDTH
Definition: pcbnew_id.h:26
@ ID_POPUP_PCB_SELECT_DIFFPAIR1
Definition: pcbnew_id.h:63
@ ID_POPUP_PCB_SELECT_USE_NETCLASS_DIFFPAIR
Definition: pcbnew_id.h:62
@ ID_POPUP_PCB_SELECT_VIASIZE1
Definition: pcbnew_id.h:45
@ ID_POPUP_PCB_SELECT_CUSTOM_DIFFPAIR
Definition: pcbnew_id.h:61
@ ID_POPUP_PCB_SELECT_VIASIZE16
Definition: pcbnew_id.h:60
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
Class that computes missing connections on a PCB.
#define FORMAT_VALUE(x)
static const TOOL_ACTION ACT_SelLayerAndPlaceThroughVia("pcbnew.InteractiveRouter.SelLayerAndPlaceVia", AS_CONTEXT, '<', LEGACY_HK_NAME("Select Layer and Add Through Via"), _("Select Layer and Place Through Via..."), _("Select a layer, then add a through-hole via at the end of currently routed track."), BITMAPS::select_w_layer, AF_NONE,(void *)(VIA_ACTION_FLAGS::VIA|VIA_ACTION_FLAGS::SELECT_LAYER))
static VIATYPE getViaTypeFromFlags(int aFlags)
static const TOOL_ACTION ACT_SwitchCornerMode("pcbnew.InteractiveRouter.SwitchRounding", AS_CONTEXT, MD_CTRL+'/', "", _("Track Corner Mode"), _("Switches between sharp/rounded and 45°/90° corners when routing tracks."), BITMAPS::switch_corner_rounding_shape)
VIA_ACTION_FLAGS
Flags used by via tool actions.
Definition: router_tool.cpp:86
@ BLIND_VIA
blind/buried via
Definition: router_tool.cpp:90
@ SELECT_LAYER
Ask user to select layer before adding via.
Definition: router_tool.cpp:94
@ MICROVIA
Microvia.
Definition: router_tool.cpp:91
@ VIA_MASK
Definition: router_tool.cpp:88
@ VIA
Normal via.
Definition: router_tool.cpp:89
static const TOOL_ACTION ACT_EndTrack("pcbnew.InteractiveRouter.EndTrack", AS_CONTEXT, WXK_END, "", _("Finish Track"), _("Stops laying the current track."), BITMAPS::checked_ok)
static const TOOL_ACTION ACT_SelLayerAndPlaceMicroVia("pcbnew.InteractiveRouter.SelLayerAndPlaceMicroVia", AS_CONTEXT, 0, "", _("Select Layer and Place Micro Via..."), _("Select a layer, then add a micro via at the end of currently routed track."), BITMAPS::select_w_layer, AF_NONE,(void *)(VIA_ACTION_FLAGS::MICROVIA|VIA_ACTION_FLAGS::SELECT_LAYER))
static PCB_LAYER_ID getTargetLayerFromEvent(const TOOL_EVENT &aEvent)
static const TOOL_ACTION ACT_PlaceMicroVia("pcbnew.InteractiveRouter.PlaceMicroVia", AS_CONTEXT, MD_CTRL+ 'V', LEGACY_HK_NAME("Add MicroVia"), _("Place Microvia"), _("Adds a microvia at the end of currently routed track."), BITMAPS::via_microvia, AF_NONE,(void *) VIA_ACTION_FLAGS::MICROVIA)
static const TOOL_ACTION ACT_PlaceThroughVia("pcbnew.InteractiveRouter.PlaceVia", AS_CONTEXT, 'V', LEGACY_HK_NAME("Add Through Via"), _("Place Through Via"), _("Adds a through-hole via at the end of currently routed track."), BITMAPS::via, AF_NONE,(void *) VIA_ACTION_FLAGS::VIA)
static const TOOL_ACTION ACT_SelLayerAndPlaceBlindVia("pcbnew.InteractiveRouter.SelLayerAndPlaceBlindVia", AS_CONTEXT, MD_ALT+'<', LEGACY_HK_NAME("Select Layer and Add Blind/Buried Via"), _("Select Layer and Place Blind/Buried Via..."), _("Select a layer, then add a blind or buried via at the end of currently routed track."), BITMAPS::select_w_layer, AF_NONE,(void *)(VIA_ACTION_FLAGS::BLIND_VIA|VIA_ACTION_FLAGS::SELECT_LAYER))
static const TOOL_ACTION ACT_SwitchPosture("pcbnew.InteractiveRouter.SwitchPosture", AS_CONTEXT, '/', LEGACY_HK_NAME("Switch Track Posture"), _("Switch Track Posture"), _("Switches posture of the currently routed track."), BITMAPS::change_entry_orient)
static const TOOL_ACTION ACT_PlaceBlindVia("pcbnew.InteractiveRouter.PlaceBlindVia", AS_CONTEXT, MD_ALT+MD_SHIFT+ 'V', LEGACY_HK_NAME("Add Blind/Buried Via"), _("Place Blind/Buried Via"), _("Adds a blind or buried via at the end of currently routed track."), BITMAPS::via_buried, AF_NONE,(void *) VIA_ACTION_FLAGS::BLIND_VIA)
static const TOOL_ACTION ACT_CustomTrackWidth("pcbnew.InteractiveRouter.CustomTrackViaSize", AS_CONTEXT, 'Q', LEGACY_HK_NAME("Custom Track/Via Size"), _("Custom Track/Via Size..."), _("Shows a dialog for changing the track width and via size."), BITMAPS::width_track)
#define _(s)
static LIB_SYMBOL * dummy()
Used to draw a dummy shape when a LIB_SYMBOL is not found in library.
Definition: sch_symbol.cpp:74
wxString UnescapeString(const wxString &aSource)
Container to handle a stock of specific differential pairs each with unique track width,...
Container to handle a stock of specific vias each with unique diameter and drill sizes in the BOARD c...
@ AS_CONTEXT
Action belongs to a particular tool (i.e. a part of a pop-up menu)
Definition: tool_action.h:43
@ AF_NONE
Definition: tool_action.h:51
std::optional< TOOL_EVENT > OPT_TOOL_EVENT
Definition: tool_event.h:557
@ TA_MODEL_CHANGE
Definition: tool_event.h:116
@ TA_UNDO_REDO_PRE
Definition: tool_event.h:101
@ TA_UNDO_REDO_POST
Definition: tool_event.h:104
@ TC_COMMAND
Definition: tool_event.h:52
@ TC_MOUSE
Definition: tool_event.h:50
@ TC_VIEW
Definition: tool_event.h:54
@ MD_ALT
Definition: tool_event.h:140
@ MD_CTRL
Definition: tool_event.h:139
@ MD_SHIFT
Definition: tool_event.h:138
@ BUT_LEFT
Definition: tool_event.h:127
@ BUT_RIGHT
Definition: tool_event.h:128
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Definition: trigo.cpp:183
@ PCB_FP_SHAPE_T
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:94
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:102
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition: typeinfo.h:86
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:103
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:101