KiCad PCB EDA Suite
Loading...
Searching...
No Matches
convert_tool.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
5 * @author Jon Evans <[email protected]>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include <bitmaps.h>
26#include <dialog_shim.h>
27#include <wx/statline.h>
28#include <wx/checkbox.h>
29#include <wx/button.h>
30#include <wx/radiobut.h>
31#include <widgets/unit_binder.h>
32#include <board.h>
33#include <board_commit.h>
35#include <collectors.h>
36#include <confirm.h>
38#include <footprint.h>
41#include <pcb_edit_frame.h>
42#include <pcb_shape.h>
43#include <pcb_track.h>
44#include <pad.h>
45#include <tool/tool_manager.h>
46#include <tools/edit_tool.h>
47#include <tools/pcb_actions.h>
49#include <trigo.h>
50#include <macros.h>
51#include <zone.h>
52
53#include "convert_tool.h"
54
55
57{
58public:
60 bool aShowCopyLineWidthOption, bool aShowCenterlineOption,
61 bool aShowBoundingHullOption ) :
62 DIALOG_SHIM( aParent, wxID_ANY, _( "Conversion Settings" ), wxDefaultPosition,
63 wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ),
64 m_settings( aSettings )
65 {
66 // Allow each distinct version of the dialog to have a different size
67 m_hash_key = TO_UTF8( wxString::Format( wxS( "%s%c%c%c" ),
68 GetTitle(),
69 aShowCopyLineWidthOption,
70 aShowCenterlineOption,
71 aShowBoundingHullOption ) );
72
73 wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL );
74 wxBoxSizer* topSizer = new wxBoxSizer( wxVERTICAL );
75 SetSizer( mainSizer );
76
77 m_rbMimicLineWidth = new wxRadioButton( this, wxID_ANY, _( "Copy line width of first object" ) );
78
79 if( aShowCopyLineWidthOption )
80 topSizer->Add( m_rbMimicLineWidth, 0, wxLEFT|wxRIGHT, 5 );
81 else
82 m_rbMimicLineWidth->Hide();
83
84 m_rbCenterline = new wxRadioButton( this, wxID_ANY, _( "Use centerlines" ) );
85
86 if( aShowCenterlineOption )
87 {
88 topSizer->AddSpacer( 6 );
89 topSizer->Add( m_rbCenterline, 0, wxLEFT|wxRIGHT, 5 );
90 }
91 else
92 {
93 m_rbCenterline->Hide();
94 }
95
96 m_rbBoundingHull = new wxRadioButton( this, wxID_ANY, _( "Create bounding hull" ) );
97
98 m_gapLabel = new wxStaticText( this, wxID_ANY, _( "Gap:" ) );
99 m_gapCtrl = new wxTextCtrl( this, wxID_ANY );
100 m_gapUnits = new wxStaticText( this, wxID_ANY, _( "mm" ) );
101 m_gap = new UNIT_BINDER( aParent, m_gapLabel, m_gapCtrl, m_gapUnits );
102
103 m_widthLabel = new wxStaticText( this, wxID_ANY, _( "Line width:" ) );
104 m_widthCtrl = new wxTextCtrl( this, wxID_ANY );
105 m_widthUnits = new wxStaticText( this, wxID_ANY, _( "mm" ) );
107
108 if( aShowBoundingHullOption )
109 {
110 topSizer->AddSpacer( 6 );
111 topSizer->Add( m_rbBoundingHull, 0, wxLEFT|wxRIGHT, 5 );
112
113 wxBoxSizer* hullParamsSizer = new wxBoxSizer( wxHORIZONTAL );
114 hullParamsSizer->Add( m_gapLabel, 0, wxALIGN_CENTRE_VERTICAL, 5 );
115 hullParamsSizer->Add( m_gapCtrl, 1, wxALIGN_CENTRE_VERTICAL|wxLEFT|wxRIGHT, 3 );
116 hullParamsSizer->Add( m_gapUnits, 0, wxALIGN_CENTRE_VERTICAL, 5 );
117 hullParamsSizer->AddSpacer( 18 );
118 hullParamsSizer->Add( m_widthLabel, 0, wxALIGN_CENTRE_VERTICAL, 5 );
119 hullParamsSizer->Add( m_widthCtrl, 1, wxALIGN_CENTRE_VERTICAL|wxLEFT|wxRIGHT, 3 );
120 hullParamsSizer->Add( m_widthUnits, 0, wxALIGN_CENTRE_VERTICAL, 5 );
121
122 topSizer->AddSpacer( 2 );
123 topSizer->Add( hullParamsSizer, 0, wxLEFT, 26 );
124
125 topSizer->AddSpacer( 15 );
126 }
127 else
128 {
129 m_rbBoundingHull->Hide();
130 m_gap->Show( false, true );
131 m_width->Show( false, true );
132 }
133
134 m_cbDeleteOriginals = new wxCheckBox( this, wxID_ANY, _( "Delete source objects after conversion" ) );
135 topSizer->Add( m_cbDeleteOriginals, 0, wxALL, 5 );
136
137 mainSizer->Add( topSizer, 1, wxALL|wxEXPAND, 10 );
138
139 wxBoxSizer* buttonsSizer = new wxBoxSizer( wxHORIZONTAL );
140 buttonsSizer->AddStretchSpacer();
141
142 wxStdDialogButtonSizer* sdbSizer = new wxStdDialogButtonSizer();
143 wxButton* sdbSizerOK = new wxButton( this, wxID_OK );
144 sdbSizer->AddButton( sdbSizerOK );
145 wxButton* sdbSizerCancel = new wxButton( this, wxID_CANCEL );
146 sdbSizer->AddButton( sdbSizerCancel );
147 sdbSizer->Realize();
148
149 buttonsSizer->Add( sdbSizer, 1, 0, 5 );
150 mainSizer->Add( buttonsSizer, 0, wxALL|wxEXPAND, 5 );
151
153
154 m_rbMimicLineWidth->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED,
155 wxCommandEventHandler( CONVERT_SETTINGS_DIALOG::onRadioButton ),
156 nullptr, this );
157 m_rbCenterline->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED,
158 wxCommandEventHandler( CONVERT_SETTINGS_DIALOG::onRadioButton ),
159 nullptr, this );
160 m_rbBoundingHull->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED,
161 wxCommandEventHandler( CONVERT_SETTINGS_DIALOG::onRadioButton ),
162 nullptr, this );
163
165 }
166
168 {
169 delete m_gap;
170 delete m_width;
171 };
172
173protected:
174 bool TransferDataToWindow() override
175 {
176 switch( m_settings->m_Strategy )
177 {
178 case COPY_LINEWIDTH: m_rbMimicLineWidth->SetValue( true ); break;
179 case CENTERLINE: m_rbCenterline->SetValue( true ); break;
180 case BOUNDING_HULL: m_rbBoundingHull->SetValue( true ); break;
181 }
182
183 m_gap->Enable( m_rbBoundingHull->GetValue() );
184 m_width->Enable( m_rbBoundingHull->GetValue() );
187
189 return true;
190 }
191
193 {
194 if( m_rbBoundingHull->GetValue() )
196 else if( m_rbCenterline->GetValue() )
198 else
200
203
205 return true;
206 }
207
208 void onRadioButton( wxCommandEvent& aEvent )
209 {
210 m_gap->Enable( m_rbBoundingHull->GetValue() );
211 m_width->Enable( m_rbBoundingHull->GetValue() );
212 }
213
214private:
216
217 wxRadioButton* m_rbMimicLineWidth;
218 wxRadioButton* m_rbCenterline;
219 wxRadioButton* m_rbBoundingHull;
220 wxStaticText* m_gapLabel;
221 wxTextCtrl* m_gapCtrl;
222 wxStaticText* m_gapUnits;
224 wxStaticText* m_widthLabel;
225 wxTextCtrl* m_widthCtrl;
226 wxStaticText* m_widthUnits;
229};
230
231
233 TOOL_INTERACTIVE( "pcbnew.Convert" ),
234 m_selectionTool( nullptr ),
235 m_menu( nullptr ),
236 m_frame( nullptr )
237{
242}
243
244
246{
247 delete m_menu;
248}
249
250
253
254
256{
258 m_frame = getEditFrame<PCB_BASE_FRAME>();
259
260 // Create a context menu and make it available through selection tool
261 m_menu = new CONDITIONAL_MENU( this );
262 m_menu->SetIcon( BITMAPS::convert );
263 m_menu->SetTitle( _( "Create from Selection" ) );
264
269 && P_S_C::SameLayer();
270
272
273 auto anyTracks = S_C::MoreThan( 0 ) && S_C::OnlyTypes( { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T } )
274 && P_S_C::SameLayer();
275
277
278 auto anyPads = S_C::OnlyTypes( { PCB_PAD_T } );
279
280 auto canCreateArcs = S_C::Count( 1 )
282 auto canCreateArray = S_C::MoreThan( 0 );
283 auto canCreatePolyType = shapes || anyPolys || anyTracks;
284
286 canCreatePolyType = shapes || anyPolys || anyTracks || anyPads;
287
288 auto canCreateLines = anyPolys;
289 auto canCreateTracks = anyPolys || graphicToTrack;
290 auto canCreate = canCreatePolyType
291 || canCreateLines
292 || canCreateTracks
293 || canCreateArcs
294 || canCreateArray;
295
296 m_menu->AddItem( PCB_ACTIONS::convertToPoly, canCreatePolyType );
297
299 m_menu->AddItem( PCB_ACTIONS::convertToZone, canCreatePolyType );
300
301 m_menu->AddItem( PCB_ACTIONS::convertToKeepout, canCreatePolyType );
302 m_menu->AddItem( PCB_ACTIONS::convertToLines, canCreateLines );
303 m_menu->AppendSeparator();
304
305 // Currently the code exists, but tracks are not really existing in footprints
306 // only segments on copper layers
308 m_menu->AddItem( PCB_ACTIONS::convertToTracks, canCreateTracks );
309
310 m_menu->AddItem( PCB_ACTIONS::convertToArc, canCreateArcs );
311
312 m_menu->AppendSeparator();
313 m_menu->AddItem( PCB_ACTIONS::createArray, canCreateArray );
314
316 selToolMenu.AddMenu( m_menu, canCreate, 100 );
317
318 return true;
319}
320
321
323{
325 std::vector<SHAPE_POLY_SET> polys;
326 PCB_LAYER_ID destLayer = m_frame->GetActiveLayer();
327 FOOTPRINT* parentFootprint = nullptr;
328
330 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
331 {
332 } );
333
334 if( selection.Empty() )
335 return 0;
336
337 auto getPolys =
338 [&]( CONVERT_SETTINGS cfg )
339 {
340 polys.clear();
341
342 for( EDA_ITEM* item : selection )
343 item->ClearTempFlags();
344
345 SHAPE_POLY_SET polySet;
346
347 polySet.Append( makePolysFromClosedGraphics( selection.GetItems(), cfg.m_Strategy ) );
348
349 if( cfg.m_Strategy == BOUNDING_HULL )
350 {
351 polySet.Append( makePolysFromOpenGraphics( selection.GetItems(), cfg.m_Gap ) );
352
353 polySet.ClearArcs();
355 polySet.Inflate( cfg.m_Gap, CORNER_STRATEGY::ROUND_ALL_CORNERS, bds.m_MaxError,
357 }
358 else
359 {
360 polySet.Append( makePolysFromChainedSegs( selection.GetItems(), cfg.m_Strategy ) );
361 }
362
363 if( polySet.IsEmpty() )
364 return false;
365
366 for( int ii = 0; ii < polySet.OutlineCount(); ++ii )
367 {
368 polys.emplace_back( SHAPE_POLY_SET( polySet.COutline( ii ) ) );
369
370 for( int jj = 0; jj < polySet.HoleCount( ii ); ++jj )
371 polys.back().AddHole( polySet.Hole( ii, jj ) );
372 }
373
374 return true;
375 };
376
377 // Pre-flight getPolys() to see if there's anything to convert.
378 CONVERT_SETTINGS preflightSettings = m_userSettings;
379 preflightSettings.m_Strategy = BOUNDING_HULL;
380
381 if( !getPolys( preflightSettings ) )
382 return 0;
383
384 if( BOARD_ITEM* item = dynamic_cast<BOARD_ITEM*>( selection.Front() ) )
385 parentFootprint = item->GetParentFootprint();
386
388 BOARD_COMMIT commit( m_frame );
389
390 if( aEvent.IsAction( &PCB_ACTIONS::convertToPoly ) )
391 {
392 bool showCopyLineWidth = true;
393
394 // No copy-line-width option for pads
395 if( dynamic_cast<PAD*>( selection.Front() ) )
396 {
399
400 showCopyLineWidth = false;
401 }
402
403 CONVERT_SETTINGS_DIALOG dlg( m_frame, &m_userSettings, showCopyLineWidth, true, true );
404
405 if( dlg.ShowModal() != wxID_OK )
406 return 0;
407
408 CONVERT_SETTINGS resolvedSettings = m_userSettings;
409
410 if( resolvedSettings.m_Strategy != CENTERLINE )
411 {
412 if( resolvedSettings.m_LineWidth == 0 )
413 resolvedSettings.m_LineWidth = bds.m_LineThickness[ bds.GetLayerClass( layer ) ];
414 }
415
416 if( resolvedSettings.m_Strategy == BOUNDING_HULL )
417 {
418 if( resolvedSettings.m_Gap > 0 )
419 resolvedSettings.m_Gap += KiROUND( (double) resolvedSettings.m_LineWidth / 2 );
420 }
421
422 if( !getPolys( resolvedSettings ) )
423 {
424 DisplayErrorMessage( m_frame, _( "Could not convert selection" ), _( "Objects must form a closed shape" ) );
425 return 0;
426 }
427
428 for( const SHAPE_POLY_SET& poly : polys )
429 {
430 PCB_SHAPE* graphic = new PCB_SHAPE( parentFootprint );
431
432 if( resolvedSettings.m_Strategy == COPY_LINEWIDTH )
433 {
434 BOARD_ITEM* topLeftItem = nullptr;
435 VECTOR2I pos;
436
437 for( EDA_ITEM* item : selection )
438 {
439 if( BOARD_ITEM* candidate = dynamic_cast<BOARD_ITEM*>( item ) )
440 {
441 if( candidate->HasLineStroke() )
442 {
443 pos = candidate->GetPosition();
444
445 if( !topLeftItem
446 || ( pos.x < topLeftItem->GetPosition().x )
447 || ( topLeftItem->GetPosition().x == pos.x
448 && pos.y < topLeftItem->GetPosition().y ) )
449 {
450 topLeftItem = candidate;
451 resolvedSettings.m_LineWidth = topLeftItem->GetStroke().GetWidth();
452 }
453 }
454 }
455 }
456 }
457
458 graphic->SetShape( SHAPE_T::POLY );
459 graphic->SetStroke( STROKE_PARAMS( resolvedSettings.m_LineWidth, LINE_STYLE::SOLID,
460 COLOR4D::UNSPECIFIED ) );
461 graphic->SetFilled( resolvedSettings.m_Strategy == CENTERLINE );
462 graphic->SetLayer( destLayer );
463 graphic->SetPolyShape( poly );
464
465 commit.Add( graphic );
466 }
467 }
468 else
469 {
470 // Creating zone or keepout
471 PCB_BASE_EDIT_FRAME* frame = getEditFrame<PCB_BASE_EDIT_FRAME>();
472 BOARD_ITEM_CONTAINER* parent = frame->GetModel();
473 ZONE_SETTINGS zoneInfo = bds.GetDefaultZoneSettings();
474
475 bool nonCopper = IsNonCopperLayer( destLayer );
476 zoneInfo.m_Layers.reset().set( destLayer );
477 zoneInfo.m_Name.Empty();
478
479 int ret;
480
481 // No copy-line-width option for zones/keepouts
484
486 {
487 zoneInfo.SetIsRuleArea( true );
488 ret = InvokeRuleAreaEditor( frame, &zoneInfo, &m_userSettings );
489 }
490 else if( nonCopper )
491 {
492 zoneInfo.SetIsRuleArea( false );
493 ret = InvokeNonCopperZonesEditor( frame, &zoneInfo, &m_userSettings );
494 }
495 else
496 {
497 zoneInfo.SetIsRuleArea( false );
498 ret = InvokeCopperZonesEditor( frame, &zoneInfo, &m_userSettings );
499 }
500
501 if( ret == wxID_CANCEL )
502 return 0;
503
504 if( !getPolys( m_userSettings ) )
505 return 0;
506
507 for( const SHAPE_POLY_SET& poly : polys )
508 {
509 ZONE* zone = new ZONE( parent );
510
511 *zone->Outline() = poly;
512 zone->HatchBorder();
513
514 zoneInfo.ExportSetting( *zone );
515
516 commit.Add( zone );
517 }
518 }
519
521 {
522 PCB_SELECTION selectionCopy = selection;
524
525 for( EDA_ITEM* item : selectionCopy )
526 {
527 if( item->GetFlags() & SKIP_STRUCT )
528 commit.Remove( item );
529 }
530 }
531
532 if( aEvent.IsAction( &PCB_ACTIONS::convertToPoly ) )
533 {
535 commit.Push( _( "Convert to Polygon" ) );
536 else
537 commit.Push( _( "Create Polygon" ) );
538 }
539 else
540 {
542 commit.Push( _( "Convert to Zone" ) );
543 else
544 commit.Push( _( "Create Zone" ) );
545 }
546
547 return 0;
548}
549
550
551SHAPE_POLY_SET CONVERT_TOOL::makePolysFromChainedSegs( const std::deque<EDA_ITEM*>& aItems,
552 CONVERT_STRATEGY aStrategy )
553{
554 // TODO: This code has a somewhat-similar purpose to ConvertOutlineToPolygon but is slightly
555 // different, so this remains a separate algorithm. It might be nice to analyze the dfiferences
556 // in requirements and refactor this.
557
558 // Using a large epsilon here to allow for sloppy drawing can cause the algorithm to miss very
559 // short segments in a converted bezier. So use an epsilon only large enough to cover for
560 // rouding errors in the conversion.
561 int chainingEpsilon = 100; // max dist from one endPt to next startPt in IU
562
564 SHAPE_POLY_SET poly;
565
566 // Stores pairs of (anchor, item) where anchor == 0 -> SEG.A, anchor == 1 -> SEG.B
567 std::map<VECTOR2I, std::vector<std::pair<int, EDA_ITEM*>>> connections;
568 std::deque<EDA_ITEM*> toCheck;
569
570 auto closeEnough =
571 []( VECTOR2I aLeft, VECTOR2I aRight, int aLimit )
572 {
573 return ( aLeft - aRight ).SquaredEuclideanNorm() <= SEG::Square( aLimit );
574 };
575
576 auto findInsertionPoint =
577 [&]( VECTOR2I aPoint ) -> VECTOR2I
578 {
579 if( connections.count( aPoint ) )
580 return aPoint;
581
582 for( const auto& candidatePair : connections )
583 {
584 if( closeEnough( aPoint, candidatePair.first, chainingEpsilon ) )
585 return candidatePair.first;
586 }
587
588 return aPoint;
589 };
590
591 for( EDA_ITEM* item : aItems )
592 {
593 if( std::optional<SEG> seg = getStartEndPoints( item ) )
594 {
595 toCheck.push_back( item );
596 connections[findInsertionPoint( seg->A )].emplace_back( std::make_pair( 0, item ) );
597 connections[findInsertionPoint( seg->B )].emplace_back( std::make_pair( 1, item ) );
598 }
599 }
600
601 while( !toCheck.empty() )
602 {
603 std::vector<BOARD_ITEM*> insertedItems;
604
605 EDA_ITEM* candidate = toCheck.front();
606 toCheck.pop_front();
607
608 if( candidate->GetFlags() & SKIP_STRUCT )
609 continue;
610
611 SHAPE_LINE_CHAIN outline;
612
613 auto insert =
614 [&]( EDA_ITEM* aItem, VECTOR2I aAnchor, bool aDirection )
615 {
616 if( aItem->Type() == PCB_ARC_T
617 || ( aItem->Type() == PCB_SHAPE_T
618 && static_cast<PCB_SHAPE*>( aItem )->GetShape() == SHAPE_T::ARC ) )
619 {
620 SHAPE_ARC arc;
621
622 if( aItem->Type() == PCB_ARC_T )
623 {
624 PCB_ARC* pcb_arc = static_cast<PCB_ARC*>( aItem );
625 arc = *static_cast<SHAPE_ARC*>( pcb_arc->GetEffectiveShape().get() );
626 }
627 else
628 {
629 PCB_SHAPE* pcb_shape = static_cast<PCB_SHAPE*>( aItem );
630 arc = SHAPE_ARC( pcb_shape->GetStart(), pcb_shape->GetArcMid(),
631 pcb_shape->GetEnd(), pcb_shape->GetWidth() );
632 }
633
634 if( aDirection )
635 outline.Append( aAnchor == arc.GetP0() ? arc : arc.Reversed() );
636 else
637 outline.Insert( 0, aAnchor == arc.GetP0() ? arc : arc.Reversed() );
638
639 insertedItems.push_back( static_cast<BOARD_ITEM*>( aItem ) );
640 }
641 else if( aItem->IsType( { PCB_SHAPE_LOCATE_BEZIER_T } ) )
642 {
643 PCB_SHAPE* graphic = static_cast<PCB_SHAPE*>( aItem );
644
645 if( aAnchor == graphic->GetStart() )
646 {
647 for( auto it = graphic->GetBezierPoints().begin();
648 it != graphic->GetBezierPoints().end();
649 ++it )
650 {
651 if( aDirection )
652 outline.Append( *it );
653 else
654 outline.Insert( 0, *it );
655 }
656
657 }
658 else
659 {
660 for( auto it = graphic->GetBezierPoints().rbegin();
661 it != graphic->GetBezierPoints().rend();
662 ++it )
663 {
664 if( aDirection )
665 outline.Append( *it );
666 else
667 outline.Insert( 0, *it );
668 }
669 }
670
671 insertedItems.push_back( static_cast<BOARD_ITEM*>( aItem ) );
672 }
673 else if( std::optional<SEG> nextSeg = getStartEndPoints( aItem ) )
674 {
675 VECTOR2I& point = ( aAnchor == nextSeg->A ) ? nextSeg->B : nextSeg->A;
676
677 if( aDirection )
678 outline.Append( point );
679 else
680 outline.Insert( 0, point );
681
682 insertedItems.push_back( static_cast<BOARD_ITEM*>( aItem ) );
683 }
684 };
685
686 // aDirection == true for walking "right" and appending to the end of points
687 // false for walking "left" and prepending to the beginning
688 std::function<void( EDA_ITEM*, VECTOR2I, bool )> process =
689 [&]( EDA_ITEM* aItem, VECTOR2I aAnchor, bool aDirection )
690 {
691 if( aItem->GetFlags() & SKIP_STRUCT )
692 return;
693
694 aItem->SetFlags( SKIP_STRUCT );
695
696 insert( aItem, aAnchor, aDirection );
697
698 std::optional<SEG> anchors = getStartEndPoints( aItem );
699 wxASSERT( anchors );
700
701 VECTOR2I nextAnchor = ( aAnchor == anchors->A ) ? anchors->B : anchors->A;
702
703 for( std::pair<int, EDA_ITEM*> pair : connections[nextAnchor] )
704 {
705 if( pair.second == aItem )
706 continue;
707
708 process( pair.second, nextAnchor, aDirection );
709 }
710 };
711
712 std::optional<SEG> anchors = getStartEndPoints( candidate );
713 wxASSERT( anchors );
714
715 // Start with the first object and walk "right"
716 // Note if the first object is an arc, we don't need to insert its first point here, the
717 // whole arc will be inserted at anchor B inside process()
718 if( !( candidate->Type() == PCB_ARC_T
719 || ( candidate->Type() == PCB_SHAPE_T
720 && static_cast<PCB_SHAPE*>( candidate )->GetShape() == SHAPE_T::ARC ) ) )
721 {
722 insert( candidate, anchors->A, true );
723 }
724
725 process( candidate, anchors->B, true );
726
727 // check for any candidates on the "left"
728 EDA_ITEM* left = nullptr;
729
730 for( std::pair<int, EDA_ITEM*> possibleLeft : connections[anchors->A] )
731 {
732 if( possibleLeft.second != candidate )
733 {
734 left = possibleLeft.second;
735 break;
736 }
737 }
738
739 if( left )
740 process( left, anchors->A, false );
741
742 if( outline.PointCount() < 3
743 || !closeEnough( outline.GetPoint( 0 ), outline.GetPoint( -1 ), chainingEpsilon ) )
744 {
745 for( EDA_ITEM* item : insertedItems )
746 item->ClearFlags( SKIP_STRUCT );
747
748 continue;
749 }
750
751 outline.SetClosed( true );
752
753 poly.AddOutline( outline );
754
755 if( aStrategy == BOUNDING_HULL )
756 {
757 for( BOARD_ITEM* item : insertedItems )
758 {
759 item->TransformShapeToPolygon( poly, UNDEFINED_LAYER, 0, bds.m_MaxError,
760 ERROR_INSIDE, false );
761 }
762 }
763
764 insertedItems.clear();
765 }
766
767 return poly;
768}
769
770
771SHAPE_POLY_SET CONVERT_TOOL::makePolysFromOpenGraphics( const std::deque<EDA_ITEM*>& aItems,
772 int aGap )
773{
775 SHAPE_POLY_SET poly;
776
777 for( EDA_ITEM* item : aItems )
778 {
779 if( item->GetFlags() & SKIP_STRUCT )
780 continue;
781
782 switch( item->Type() )
783 {
784 case PCB_SHAPE_T:
785 {
786 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
787
788 if( shape->IsClosed() )
789 continue;
790
791 shape->TransformShapeToPolygon( poly, UNDEFINED_LAYER, aGap, bds.m_MaxError,
792 ERROR_INSIDE, false );
793 shape->SetFlags( SKIP_STRUCT );
794
795 break;
796 }
797
798 case PCB_TRACE_T:
799 case PCB_ARC_T:
800 case PCB_VIA_T:
801 {
802 PCB_TRACK* track = static_cast<PCB_TRACK*>( item );
803
804 track->TransformShapeToPolygon( poly, UNDEFINED_LAYER, aGap, bds.m_MaxError,
805 ERROR_INSIDE, false );
806 track->SetFlags( SKIP_STRUCT );
807
808 break;
809 }
810
811 default:
812 continue;
813 }
814 }
815
816 return poly;
817}
818
819
821 CONVERT_STRATEGY aStrategy )
822{
824 SHAPE_POLY_SET poly;
825
826 for( EDA_ITEM* item : aItems )
827 {
828 if( item->GetFlags() & SKIP_STRUCT )
829 continue;
830
831 switch( item->Type() )
832 {
833 case PCB_SHAPE_T:
834 {
835 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
836 FILL_T wasFilled = shape->GetFillMode();
837
838 if( !shape->IsClosed() )
839 continue;
840
841 if( aStrategy != BOUNDING_HULL )
842 shape->SetFilled( true );
843
845 aStrategy == COPY_LINEWIDTH || aStrategy == CENTERLINE );
846
847 if( aStrategy != BOUNDING_HULL )
848 shape->SetFillMode( wasFilled );
849
850 shape->SetFlags( SKIP_STRUCT );
851 break;
852 }
853
854 case PCB_ZONE_T:
855 poly.Append( *static_cast<ZONE*>( item )->Outline() );
856 item->SetFlags( SKIP_STRUCT );
857 break;
858
859 case PCB_FIELD_T:
860 case PCB_TEXT_T:
861 {
862 PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
863 text->TransformTextToPolySet( poly, 0, bds.m_MaxError, ERROR_INSIDE );
864 text->SetFlags( SKIP_STRUCT );
865 break;
866 }
867
868 case PCB_PAD_T:
869 {
870 PAD* pad = static_cast<PAD*>( item );
871 pad->TransformShapeToPolygon( poly, UNDEFINED_LAYER, 0, bds.m_MaxError, ERROR_INSIDE,
872 false );
873 pad->SetFlags( SKIP_STRUCT );
874 break;
875 }
876
877
878 default:
879 continue;
880 }
881 }
882
883 return poly;
884}
885
886
888{
889 auto& selection = m_selectionTool->RequestSelection(
890 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
891 {
892 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
893 {
894 BOARD_ITEM* item = aCollector[i];
895
896 switch( item->Type() )
897 {
898 case PCB_SHAPE_T:
899 switch( static_cast<PCB_SHAPE*>( item )->GetShape() )
900 {
901 case SHAPE_T::SEGMENT:
902 case SHAPE_T::ARC:
903 case SHAPE_T::POLY:
904 case SHAPE_T::RECTANGLE:
905 break;
906
907 default:
908 aCollector.Remove( item );
909 }
910
911 break;
912
913 case PCB_ZONE_T:
914 break;
915
916 default:
917 aCollector.Remove( item );
918 }
919 }
920 } );
921
922 if( selection.Empty() )
923 return 0;
924
925 auto getPolySet =
926 []( EDA_ITEM* aItem )
927 {
928 SHAPE_POLY_SET set;
929
930 switch( aItem->Type() )
931 {
932 case PCB_ZONE_T:
933 set = *static_cast<ZONE*>( aItem )->Outline();
934 break;
935
936 case PCB_SHAPE_T:
937 {
938 PCB_SHAPE* graphic = static_cast<PCB_SHAPE*>( aItem );
939
940 if( graphic->GetShape() == SHAPE_T::POLY )
941 {
942 set = graphic->GetPolyShape();
943 }
944 else if( graphic->GetShape() == SHAPE_T::RECTANGLE )
945 {
946 SHAPE_LINE_CHAIN outline;
947 VECTOR2I start( graphic->GetStart() );
948 VECTOR2I end( graphic->GetEnd() );
949
950 outline.Append( start );
951 outline.Append( VECTOR2I( end.x, start.y ) );
952 outline.Append( end );
953 outline.Append( VECTOR2I( start.x, end.y ) );
954 outline.SetClosed( true );
955
956 set.AddOutline( outline );
957 }
958 else
959 {
960 wxFAIL_MSG( wxT( "Unhandled graphic shape type in PolyToLines - getPolySet" ) );
961 }
962 break;
963 }
964
965 default:
966 wxFAIL_MSG( wxT( "Unhandled type in PolyToLines - getPolySet" ) );
967 break;
968 }
969
970 return set;
971 };
972
973 auto getSegList =
974 []( SHAPE_POLY_SET& aPoly )
975 {
976 std::vector<SEG> segs;
977
978 // Our input should be valid polys, so OK to assert here
979 wxASSERT( aPoly.VertexCount() >= 2 );
980
981 for( int i = 1; i < aPoly.VertexCount(); i++ )
982 segs.emplace_back( SEG( aPoly.CVertex( i - 1 ), aPoly.CVertex( i ) ) );
983
984 segs.emplace_back( SEG( aPoly.CVertex( aPoly.VertexCount() - 1 ),
985 aPoly.CVertex( 0 ) ) );
986
987 return segs;
988 };
989
990 BOARD_COMMIT commit( m_frame );
991 PCB_BASE_EDIT_FRAME* frame = getEditFrame<PCB_BASE_EDIT_FRAME>();
992 FOOTPRINT_EDIT_FRAME* fpEditor = dynamic_cast<FOOTPRINT_EDIT_FRAME*>( m_frame );
993 FOOTPRINT* footprint = nullptr;
994 PCB_LAYER_ID targetLayer = m_frame->GetActiveLayer();
995 BOARD_ITEM_CONTAINER* parent = frame->GetModel();
996
997 if( fpEditor )
998 footprint = fpEditor->GetBoard()->GetFirstFootprint();
999
1000 auto handleGraphicSeg =
1001 [&]( EDA_ITEM* aItem )
1002 {
1003 if( aItem->Type() != PCB_SHAPE_T )
1004 return false;
1005
1006 PCB_SHAPE* graphic = static_cast<PCB_SHAPE*>( aItem );
1007
1008 if( graphic->GetShape() == SHAPE_T::SEGMENT )
1009 {
1010 PCB_TRACK* track = new PCB_TRACK( parent );
1011
1012 track->SetLayer( targetLayer );
1013 track->SetStart( graphic->GetStart() );
1014 track->SetEnd( graphic->GetEnd() );
1015 track->SetWidth( graphic->GetWidth() );
1016 commit.Add( track );
1017
1018 return true;
1019 }
1020 else if( graphic->GetShape() == SHAPE_T::ARC )
1021 {
1022 PCB_ARC* arc = new PCB_ARC( parent );
1023
1024 arc->SetLayer( targetLayer );
1025 arc->SetStart( graphic->GetStart() );
1026 arc->SetEnd( graphic->GetEnd() );
1027 arc->SetMid( graphic->GetArcMid() );
1028 arc->SetWidth( graphic->GetWidth() );
1029 commit.Add( arc );
1030
1031 return true;
1032 }
1033
1034 return false;
1035 };
1036
1037 if( aEvent.IsAction( &PCB_ACTIONS::convertToTracks ) )
1038 {
1039 if( !IsCopperLayer( targetLayer ) )
1040 {
1041 targetLayer = frame->SelectOneLayer( F_Cu, LSET::AllNonCuMask() );
1042
1043 if( targetLayer == UNDEFINED_LAYER ) // User canceled
1044 return true;
1045 }
1046 }
1047 else
1048 {
1049 CONVERT_SETTINGS_DIALOG dlg( m_frame, &m_userSettings, false, false, false );
1050
1051 if( dlg.ShowModal() != wxID_OK )
1052 return true;
1053 }
1054
1055 for( EDA_ITEM* item : selection )
1056 {
1057 if( handleGraphicSeg( item ) )
1058 continue;
1059
1060 SHAPE_POLY_SET polySet = getPolySet( item );
1061 std::vector<SEG> segs = getSegList( polySet );
1062
1063 if( aEvent.IsAction( &PCB_ACTIONS::convertToLines ) )
1064 {
1065 for( SEG& seg : segs )
1066 {
1067 PCB_SHAPE* graphic = new PCB_SHAPE( footprint, SHAPE_T::SEGMENT );
1068
1069 graphic->SetLayer( targetLayer );
1070 graphic->SetStart( VECTOR2I( seg.A ) );
1071 graphic->SetEnd( VECTOR2I( seg.B ) );
1072 commit.Add( graphic );
1073 }
1074 }
1075 else
1076 {
1077 // I am really unsure converting a polygon to "tracks" (i.e. segments on
1078 // copper layers) make sense for footprints, but anyway this code exists
1079 if( fpEditor )
1080 {
1081 // Creating segments on copper layer
1082 for( SEG& seg : segs )
1083 {
1084 PCB_SHAPE* graphic = new PCB_SHAPE( footprint, SHAPE_T::SEGMENT );
1085 graphic->SetLayer( targetLayer );
1086 graphic->SetStart( VECTOR2I( seg.A ) );
1087 graphic->SetEnd( VECTOR2I( seg.B ) );
1088 commit.Add( graphic );
1089 }
1090 }
1091 else
1092 {
1093 // Creating tracks
1094 for( SEG& seg : segs )
1095 {
1096 PCB_TRACK* track = new PCB_TRACK( parent );
1097
1098 track->SetLayer( targetLayer );
1099 track->SetStart( VECTOR2I( seg.A ) );
1100 track->SetEnd( VECTOR2I( seg.B ) );
1101 commit.Add( track );
1102 }
1103 }
1104 }
1105 }
1106
1107 if( m_userSettings.m_DeleteOriginals )
1108 {
1109 PCB_SELECTION selectionCopy = selection;
1110 m_selectionTool->ClearSelection();
1111
1112 for( EDA_ITEM* item : selectionCopy )
1113 commit.Remove( item );
1114 }
1115
1116 commit.Push( _( "Create Lines" ) );
1117
1118 return 0;
1119}
1120
1121
1123{
1124 auto& selection = m_selectionTool->RequestSelection(
1125 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
1126 {
1127 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
1128 {
1129 BOARD_ITEM* item = aCollector[i];
1130
1131 if( !( item->Type() == PCB_SHAPE_T ||
1132 item->Type() == PCB_TRACE_T ) )
1133 {
1134 aCollector.Remove( item );
1135 }
1136 }
1137 } );
1138
1139 EDA_ITEM* source = selection.Front();
1140 VECTOR2I start, end, mid;
1141
1142 // Offset the midpoint along the normal a little bit so that it's more obviously an arc
1143 const double offsetRatio = 0.1;
1144
1145 if( std::optional<SEG> seg = getStartEndPoints( source ) )
1146 {
1147 start = seg->A;
1148 end = seg->B;
1149
1150 VECTOR2I normal = ( seg->B - seg->A ).Perpendicular().Resize( offsetRatio * seg->Length() );
1151 mid = seg->Center() + normal;
1152 }
1153 else
1154 {
1155 return -1;
1156 }
1157
1158 PCB_BASE_EDIT_FRAME* frame = getEditFrame<PCB_BASE_EDIT_FRAME>();
1159 BOARD_ITEM_CONTAINER* parent = frame->GetModel();
1160
1161 BOARD_ITEM* boardItem = dynamic_cast<BOARD_ITEM*>( source );
1162
1163 // Don't continue processing if we don't actually have a board item
1164 if( !boardItem )
1165 return 0;
1166
1167 PCB_LAYER_ID layer = boardItem->GetLayer();
1168
1169 BOARD_COMMIT commit( m_frame );
1170
1171 if( source->Type() == PCB_SHAPE_T )
1172 {
1173 PCB_SHAPE* line = static_cast<PCB_SHAPE*>( source );
1174 PCB_SHAPE* arc = new PCB_SHAPE( parent, SHAPE_T::ARC );
1175
1176 VECTOR2I center = CalcArcCenter( start, mid, end );
1177
1178 arc->SetFilled( false );
1179 arc->SetLayer( layer );
1180 arc->SetStroke( line->GetStroke() );
1181
1182 arc->SetCenter( VECTOR2I( center ) );
1183 arc->SetStart( VECTOR2I( start ) );
1184 arc->SetEnd( VECTOR2I( end ) );
1185
1186 commit.Add( arc );
1187 }
1188 else
1189 {
1190 wxASSERT( source->Type() == PCB_TRACE_T );
1191 PCB_TRACK* line = static_cast<PCB_TRACK*>( source );
1192 PCB_ARC* arc = new PCB_ARC( parent );
1193
1194 arc->SetLayer( layer );
1195 arc->SetWidth( line->GetWidth() );
1196 arc->SetStart( VECTOR2I( start ) );
1197 arc->SetMid( VECTOR2I( mid ) );
1198 arc->SetEnd( VECTOR2I( end ) );
1199
1200 commit.Add( arc );
1201 }
1202
1203 commit.Push( _( "Create Arc" ) );
1204
1205 return 0;
1206}
1207
1208
1209std::optional<SEG> CONVERT_TOOL::getStartEndPoints( EDA_ITEM* aItem )
1210{
1211 switch( aItem->Type() )
1212 {
1213 case PCB_SHAPE_T:
1214 {
1215 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( aItem );
1216
1217 switch( shape->GetShape() )
1218 {
1219 case SHAPE_T::SEGMENT:
1220 case SHAPE_T::ARC:
1221 case SHAPE_T::POLY:
1222 case SHAPE_T::BEZIER:
1223 if( shape->GetStart() == shape->GetEnd() )
1224 return std::nullopt;
1225
1226 return std::make_optional<SEG>( VECTOR2I( shape->GetStart() ),
1227 VECTOR2I( shape->GetEnd() ) );
1228
1229 default:
1230 return std::nullopt;
1231 }
1232 }
1233
1234 case PCB_TRACE_T:
1235 {
1236 PCB_TRACK* line = static_cast<PCB_TRACK*>( aItem );
1237 return std::make_optional<SEG>( VECTOR2I( line->GetStart() ), VECTOR2I( line->GetEnd() ) );
1238 }
1239
1240 case PCB_ARC_T:
1241 {
1242 PCB_ARC* arc = static_cast<PCB_ARC*>( aItem );
1243 return std::make_optional<SEG>( VECTOR2I( arc->GetStart() ), VECTOR2I( arc->GetEnd() ) );
1244 }
1245
1246 default:
1247 return std::nullopt;
1248 }
1249}
1250
1251
1253{
1260}
void SetTitle(const wxString &aTitle) override
Set title for the menu.
Definition: action_menu.cpp:92
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
Definition: action_menu.cpp:78
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Revert the commit by restoring the modified items state.
Container for design settings for a BOARD object.
int GetLayerClass(PCB_LAYER_ID aLayer) const
int m_LineThickness[LAYER_CLASS_COUNT]
ZONE_SETTINGS & GetDefaultZoneSettings()
Abstract interface for BOARD_ITEMs capable of storing other items inside.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:77
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:226
virtual STROKE_PARAMS GetStroke() const
Definition: board_item.cpp:85
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:260
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:248
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
Definition: board.h:433
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:797
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:81
COMMIT & Remove(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been removed.
Definition: commit.h:92
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been added.
Definition: commit.h:80
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Add a menu entry to run a TOOL_ACTION on selected items.
void AddMenu(ACTION_MENU *aMenu, const SELECTION_CONDITION &aCondition=SELECTION_CONDITIONS::ShowAlways, int aOrder=ANY_ORDER)
Add a submenu to the menu.
CONVERT_SETTINGS * m_settings
bool TransferDataToWindow() override
wxRadioButton * m_rbBoundingHull
wxStaticText * m_gapLabel
wxRadioButton * m_rbMimicLineWidth
wxRadioButton * m_rbCenterline
void onRadioButton(wxCommandEvent &aEvent)
wxStaticText * m_gapUnits
bool TransferDataFromWindow() override
wxCheckBox * m_cbDeleteOriginals
CONVERT_SETTINGS_DIALOG(EDA_DRAW_FRAME *aParent, CONVERT_SETTINGS *aSettings, bool aShowCopyLineWidthOption, bool aShowCenterlineOption, bool aShowBoundingHullOption)
wxStaticText * m_widthLabel
wxStaticText * m_widthUnits
int CreateLines(const TOOL_EVENT &aEvent)
Convert selected polygon-like object to graphic lines, if possible.
bool Init() override
Init() is called once upon a registration of the tool.
int SegmentToArc(const TOOL_EVENT &aEvent)
Convert selected segment (graphic or track) to an arc of the same type.
SHAPE_POLY_SET makePolysFromChainedSegs(const std::deque< EDA_ITEM * > &aItems, CONVERT_STRATEGY aStrategy)
Try to make polygons from chained segments in the selected items.
SHAPE_POLY_SET makePolysFromOpenGraphics(const std::deque< EDA_ITEM * > &aItems, int aGap)
Make polygons from graphic shapes and zones.
static std::optional< SEG > getStartEndPoints(EDA_ITEM *aItem)
Retrieve the start and end points for a generic item.
SHAPE_POLY_SET makePolysFromClosedGraphics(const std::deque< EDA_ITEM * > &aItems, CONVERT_STRATEGY aStrategy)
int CreatePolys(const TOOL_EVENT &aEvent)
Convert selected lines to a polygon, if possible.
PCB_SELECTION_TOOL * m_selectionTool
Definition: convert_tool.h:100
virtual ~CONVERT_TOOL()
CONVERT_SETTINGS m_userSettings
Definition: convert_tool.h:103
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
CONDITIONAL_MENU * m_menu
Definition: convert_tool.h:101
PCB_BASE_FRAME * m_frame
Definition: convert_tool.h:102
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
Definition: dialog_shim.h:84
void SetupStandardButtons(std::map< int, wxString > aLabels={})
std::string m_hash_key
Definition: dialog_shim.h:206
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
bool IsType(FRAME_T aType) const
The base class for create windows for drawing purpose.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:88
virtual VECTOR2I GetPosition() const
Definition: eda_item.h:242
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:126
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:100
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition: eda_item.h:175
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:129
void SetCenter(const VECTOR2I &aCenter)
Definition: eda_shape.cpp:543
FILL_T GetFillMode() const
Definition: eda_shape.h:102
SHAPE_POLY_SET & GetPolyShape()
Definition: eda_shape.h:262
void SetFilled(bool aFlag)
Definition: eda_shape.h:96
SHAPE_T GetShape() const
Definition: eda_shape.h:120
void SetPolyShape(const SHAPE_POLY_SET &aShape)
Definition: eda_shape.h:270
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:150
bool IsClosed() const
Definition: eda_shape.cpp:210
void SetStart(const VECTOR2I &aStart)
Definition: eda_shape.h:129
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:125
void SetShape(SHAPE_T aShape)
Definition: eda_shape.h:119
const std::vector< VECTOR2I > & GetBezierPoints() const
Definition: eda_shape.h:245
void SetEnd(const VECTOR2I &aEnd)
Definition: eda_shape.h:154
void SetFillMode(FILL_T aFill)
Definition: eda_shape.h:101
VECTOR2I GetArcMid() const
Definition: eda_shape.cpp:561
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:206
static LSET AllNonCuMask()
Return a mask holding all layer minus CU layers.
Definition: lset.cpp:884
Definition: pad.h:59
static TOOL_ACTION convertToKeepout
Definition: pcb_actions.h:571
static TOOL_ACTION convertToTracks
Definition: pcb_actions.h:574
static TOOL_ACTION convertToLines
Definition: pcb_actions.h:572
static TOOL_ACTION convertToZone
Definition: pcb_actions.h:570
static TOOL_ACTION convertToPoly
Definition: pcb_actions.h:569
static TOOL_ACTION convertToArc
Definition: pcb_actions.h:573
static TOOL_ACTION createArray
Tool for creating an array of objects.
Definition: pcb_actions.h:481
void SetMid(const VECTOR2I &aMid)
Definition: pcb_track.h:314
std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: pcb_track.cpp:1635
Common, abstract interface for edit frames.
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:285
virtual PCB_LAYER_ID GetActiveLayer() const
BOARD * GetBoard() const
virtual BOARD_ITEM_CONTAINER * GetModel() const =0
static SELECTION_CONDITION SameLayer()
Creates a functor that tests if selection contains items that belong exclusively to the same layer.
The selection tool: currently supports:
PCB_SELECTION & RequestSelection(CLIENT_SELECTION_FILTER aClientFilter, bool aConfirmLockedItems=false)
Return the current selection, filtered according to aClientFilter.
int ClearSelection(const TOOL_EVENT &aEvent)
int GetWidth() const override
Definition: pcb_shape.cpp:366
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition: pcb_shape.cpp:314
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Convert the shape to a closed polygon.
Definition: pcb_shape.cpp:785
STROKE_PARAMS GetStroke() const override
Definition: pcb_shape.h:85
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: pcb_shape.h:86
void SetWidth(int aWidth)
Definition: pcb_track.h:106
int GetWidth() const
Definition: pcb_track.h:107
void SetEnd(const VECTOR2I &aEnd)
Definition: pcb_track.h:109
void SetStart(const VECTOR2I &aStart)
Definition: pcb_track.h:112
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Convert the track shape to a closed polygon.
Definition: pcb_track.cpp:1641
const VECTOR2I & GetStart() const
Definition: pcb_track.h:113
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:110
Definition: seg.h:42
static SEG::ecoord Square(int a)
Definition: seg.h:123
Class that groups generic conditions for selected items.
static SELECTION_CONDITION MoreThan(int aNumber)
Create a functor that tests if the number of selected items is greater than the value given as parame...
static SELECTION_CONDITION Count(int aNumber)
Create a functor that tests if the number of selected items is equal to the value given as parameter.
static SELECTION_CONDITION OnlyTypes(std::vector< KICAD_T > aTypes)
Create a functor that tests if the selected items are only of given types.
virtual void Remove(EDA_ITEM *aItem)
Definition: selection.cpp:60
EDA_ITEM * Front() const
Definition: selection.h:208
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:109
SHAPE_ARC Reversed() const
Definition: shape_arc.cpp:633
const VECTOR2I & GetP0() const
Definition: shape_arc.h:113
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
virtual const VECTOR2I GetPoint(int aIndex) const override
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int PointCount() const
Return the number of points (vertices) in this line chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
void Insert(size_t aVertex, const VECTOR2I &aP)
Represent a set of closed polygons.
void ClearArcs()
Removes all arc references from all the outlines and holes in the polyset.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
int HoleCount(int aOutline) const
Returns the number of holes in a given outline.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
void Simplify(POLYGON_MODE aFastMode)
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFastMo...
SHAPE_LINE_CHAIN & Hole(int aOutline, int aHole)
Return the reference to aHole-th hole in the aIndex-th outline.
int OutlineCount() const
Return the number of outlines in the set.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
Simple container to manage line stroke parameters.
Definition: stroke_params.h:81
int GetWidth() const
Definition: stroke_params.h:91
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:216
Generic, UI-independent tool event.
Definition: tool_event.h:167
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
Definition: tool_event.cpp:82
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
TOOL_MENU & GetToolMenu()
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:44
int GetIntValue()
Definition: unit_binder.h:127
void Enable(bool aEnable)
Enable/disable the label, widget and units label.
virtual void SetValue(long long int aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion.
void Show(bool aShow, bool aResize=false)
Show/hide the label, widget and units label.
ZONE_SETTINGS handles zones parameters.
Definition: zone_settings.h:71
void SetIsRuleArea(bool aEnable)
void ExportSetting(ZONE &aTarget, bool aFullExport=true) const
Function ExportSetting copy settings to a given zone.
wxString m_Name
Definition: zone_settings.h:98
Handle a list of polygons defining a copper zone.
Definition: zone.h:72
void HatchBorder()
Compute the hatch lines depending on the hatch parameters and stores it in the zone's attribute m_bor...
Definition: zone.cpp:910
SHAPE_POLY_SET * Outline()
Definition: zone.h:336
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:305
This file is part of the common library.
int InvokeCopperZonesEditor(PCB_BASE_FRAME *aCaller, ZONE_SETTINGS *aSettings, CONVERT_SETTINGS *aConvertSettings)
Function InvokeCopperZonesEditor invokes up a modal dialog window for copper zone editing.
int InvokeNonCopperZonesEditor(PCB_BASE_FRAME *aParent, ZONE_SETTINGS *aSettings, CONVERT_SETTINGS *aConvertSettings)
Function InvokeNonCopperZonesEditor invokes up a modal dialog window for non-copper zone editing.
int InvokeRuleAreaEditor(PCB_BASE_FRAME *aCaller, ZONE_SETTINGS *aZoneSettings, CONVERT_SETTINGS *aConvertSettings)
Function InvokeRuleAreaEditor invokes up a modal dialog window for copper zone editing.
#define _(s)
#define SKIP_STRUCT
flag indicating that the structure should be ignored
@ ARC
use RECTANGLE instead of RECT to avoid collision in a Windows header
FILL_T
Definition: eda_shape.h:55
@ FRAME_PCB_EDITOR
Definition: frame_type.h:42
@ FRAME_FOOTPRINT_EDITOR
Definition: frame_type.h:43
@ ERROR_OUTSIDE
@ ERROR_INSIDE
bool IsNonCopperLayer(int aLayerId)
Test whether a layer is a non copper layer.
Definition: layer_ids.h:892
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:881
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
@ F_Cu
Definition: layer_ids.h:64
This file contains miscellaneous commonly used macros and functions.
CONVERT_STRATEGY
@ COPY_LINEWIDTH
@ CENTERLINE
@ BOUNDING_HULL
static PGM_BASE * process
Definition: pgm_base.cpp:1057
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: string_utils.h:391
CONVERT_STRATEGY m_Strategy
const VECTOR2I CalcArcCenter(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Determine the center of an arc or circle given three points on its circumference.
Definition: trigo.cpp:520
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:88
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:107
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:92
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition: typeinfo.h:90
@ PCB_SHAPE_LOCATE_CIRCLE_T
Definition: typeinfo.h:135
@ PCB_SHAPE_LOCATE_SEGMENT_T
Definition: typeinfo.h:133
@ PCB_SHAPE_LOCATE_RECT_T
Definition: typeinfo.h:134
@ PCB_SHAPE_LOCATE_BEZIER_T
Definition: typeinfo.h:138
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
@ PCB_SHAPE_LOCATE_POLY_T
Definition: typeinfo.h:137
@ PCB_SHAPE_LOCATE_ARC_T
Definition: typeinfo.h:136
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:98
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:118
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588