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 aShowCopyLineWidth ) :
61 DIALOG_SHIM( aParent, wxID_ANY, _( "Conversion Settings" ), wxDefaultPosition,
62 wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ),
63 m_settings( aSettings )
64 {
65 wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL );
66 wxBoxSizer* topSizer = new wxBoxSizer( wxVERTICAL );
67 SetSizer( mainSizer );
68
69 m_rbMimicLineWidth = new wxRadioButton( this, wxID_ANY, _( "Copy line width of first object" ) );
70
71 if( aShowCopyLineWidth )
72 topSizer->Add( m_rbMimicLineWidth, 0, wxLEFT|wxRIGHT, 5 );
73 else
74 m_rbMimicLineWidth->Hide();
75
76 topSizer->AddSpacer( 6 );
77 m_rbCenterline = new wxRadioButton( this, wxID_ANY, _( "Use centerlines" ) );
78 topSizer->Add( m_rbCenterline, 0, wxLEFT|wxRIGHT, 5 );
79
80 topSizer->AddSpacer( 6 );
81 m_rbEnvelope = new wxRadioButton( this, wxID_ANY, _( "Create bounding hull" ) );
82 topSizer->Add( m_rbEnvelope, 0, wxLEFT|wxRIGHT, 5 );
83
84 m_gapLabel = new wxStaticText( this, wxID_ANY, _( "Gap:" ) );
85 m_gapCtrl = new wxTextCtrl( this, wxID_ANY );
86 m_gapUnits = new wxStaticText( this, wxID_ANY, _( "mm" ) );
88
89 m_widthLabel = new wxStaticText( this, wxID_ANY, _( "Line width:" ) );
90 m_widthCtrl = new wxTextCtrl( this, wxID_ANY );
91 m_widthUnits = new wxStaticText( this, wxID_ANY, _( "mm" ) );
93
94 wxBoxSizer* hullParamsSizer = new wxBoxSizer( wxHORIZONTAL );
95 hullParamsSizer->Add( m_gapLabel, 0, wxALIGN_CENTRE_VERTICAL, 5 );
96 hullParamsSizer->Add( m_gapCtrl, 1, wxALIGN_CENTRE_VERTICAL|wxLEFT|wxRIGHT, 3 );
97 hullParamsSizer->Add( m_gapUnits, 0, wxALIGN_CENTRE_VERTICAL, 5 );
98 hullParamsSizer->AddSpacer( 18 );
99 hullParamsSizer->Add( m_widthLabel, 0, wxALIGN_CENTRE_VERTICAL, 5 );
100 hullParamsSizer->Add( m_widthCtrl, 1, wxALIGN_CENTRE_VERTICAL|wxLEFT|wxRIGHT, 3 );
101 hullParamsSizer->Add( m_widthUnits, 0, wxALIGN_CENTRE_VERTICAL, 5 );
102
103 topSizer->AddSpacer( 2 );
104 topSizer->Add( hullParamsSizer, 0, wxLEFT, 26 );
105
106 topSizer->AddSpacer( 15 );
107 m_cbDeleteOriginals = new wxCheckBox( this, wxID_ANY, _( "Delete source objects after conversion" ) );
108 topSizer->Add( m_cbDeleteOriginals, 0, wxALL, 5 );
109
110 wxStaticLine* line = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
111 wxLI_HORIZONTAL );
112 topSizer->Add( line, 0, wxLEFT|wxRIGHT|wxTOP|wxEXPAND, 5 );
113
114 mainSizer->Add( topSizer, 1, wxALL|wxEXPAND, 10 );
115
116 wxBoxSizer* buttonsSizer = new wxBoxSizer( wxHORIZONTAL );
117 buttonsSizer->AddStretchSpacer();
118
119 wxStdDialogButtonSizer* sdbSizer = new wxStdDialogButtonSizer();
120 wxButton* sdbSizerOK = new wxButton( this, wxID_OK );
121 sdbSizer->AddButton( sdbSizerOK );
122 wxButton* sdbSizerCancel = new wxButton( this, wxID_CANCEL );
123 sdbSizer->AddButton( sdbSizerCancel );
124 sdbSizer->Realize();
125
126 buttonsSizer->Add( sdbSizer, 1, 0, 5 );
127 mainSizer->Add( buttonsSizer, 0, wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND, 5 );
128
130
131 m_rbMimicLineWidth->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED,
132 wxCommandEventHandler( CONVERT_SETTINGS_DIALOG::onRadioButton ),
133 nullptr, this );
134 m_rbCenterline->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED,
135 wxCommandEventHandler( CONVERT_SETTINGS_DIALOG::onRadioButton ),
136 nullptr, this );
137 m_rbEnvelope->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED,
138 wxCommandEventHandler( CONVERT_SETTINGS_DIALOG::onRadioButton ),
139 nullptr, this );
140
142 }
143
145 {
146 delete m_gap;
147 delete m_width;
148 };
149
150protected:
151 bool TransferDataToWindow() override
152 {
153 switch( m_settings->m_Strategy )
154 {
155 case COPY_LINEWIDTH: m_rbMimicLineWidth->SetValue( true ); break;
156 case CENTERLINE: m_rbCenterline->SetValue( true ); break;
157 case BOUNDING_HULL: m_rbEnvelope->SetValue( true ); break;
158 }
159
160 m_gap->Enable( m_rbEnvelope->GetValue() );
161 m_width->Enable( m_rbEnvelope->GetValue() );
164
166 return true;
167 }
168
170 {
171 if( m_rbEnvelope->GetValue() )
173 else if( m_rbCenterline->GetValue() )
175 else
177
180
182 return true;
183 }
184
185 void onRadioButton( wxCommandEvent& aEvent )
186 {
187 m_gap->Enable( m_rbEnvelope->GetValue() );
188 m_width->Enable( m_rbEnvelope->GetValue() );
189 }
190
191private:
193
194 wxRadioButton* m_rbMimicLineWidth;
195 wxRadioButton* m_rbCenterline;
196 wxRadioButton* m_rbEnvelope;
197 wxStaticText* m_gapLabel;
198 wxTextCtrl* m_gapCtrl;
199 wxStaticText* m_gapUnits;
201 wxStaticText* m_widthLabel;
202 wxTextCtrl* m_widthCtrl;
203 wxStaticText* m_widthUnits;
206};
207
208
210 TOOL_INTERACTIVE( "pcbnew.Convert" ),
211 m_selectionTool( nullptr ),
212 m_menu( nullptr ),
213 m_frame( nullptr )
214{
219}
220
221
223{
224 delete m_menu;
225}
226
227
230
231
233{
235 m_frame = getEditFrame<PCB_BASE_FRAME>();
236
237 // Create a context menu and make it available through selection tool
238 m_menu = new CONDITIONAL_MENU( this );
239 m_menu->SetIcon( BITMAPS::convert );
240 m_menu->SetTitle( _( "Create from Selection" ) );
241
246 && P_S_C::SameLayer();
247
249
250 auto anyTracks = S_C::MoreThan( 0 ) && S_C::OnlyTypes( { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T } )
251 && P_S_C::SameLayer();
252
254
255 auto anyPads = S_C::OnlyTypes( { PCB_PAD_T } );
256
257 auto canCreateArcs = S_C::Count( 1 )
259 auto canCreateArray = S_C::MoreThan( 0 );
260 auto canCreatePolyType = shapes || anyPolys || anyTracks;
261
263 canCreatePolyType = shapes || anyPolys || anyTracks || anyPads;
264
265 auto canCreateLines = anyPolys;
266 auto canCreateTracks = anyPolys || graphicToTrack;
267 auto canCreate = canCreatePolyType
268 || canCreateLines
269 || canCreateTracks
270 || canCreateArcs
271 || canCreateArray;
272
273 m_menu->AddItem( PCB_ACTIONS::convertToPoly, canCreatePolyType );
274
276 m_menu->AddItem( PCB_ACTIONS::convertToZone, canCreatePolyType );
277
278 m_menu->AddItem( PCB_ACTIONS::convertToKeepout, canCreatePolyType );
279 m_menu->AddItem( PCB_ACTIONS::convertToLines, canCreateLines );
280 m_menu->AppendSeparator();
281
282 // Currently the code exists, but tracks are not really existing in footprints
283 // only segments on copper layers
285 m_menu->AddItem( PCB_ACTIONS::convertToTracks, canCreateTracks );
286
287 m_menu->AddItem( PCB_ACTIONS::convertToArc, canCreateArcs );
288
289 m_menu->AppendSeparator();
290 m_menu->AddItem( PCB_ACTIONS::createArray, canCreateArray );
291
293 selToolMenu.AddMenu( m_menu, canCreate, 100 );
294
295 return true;
296}
297
298
300{
301 std::vector<SHAPE_POLY_SET> polys;
302 PCB_LAYER_ID destLayer = m_frame->GetActiveLayer();
303 FOOTPRINT* parentFootprint = nullptr;
304
306 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
307 {
308 } );
309
310 if( selection.Empty() )
311 return 0;
312
313 auto getPolys =
314 [&]( CONVERT_SETTINGS cfg )
315 {
316 polys.clear();
317
318 for( EDA_ITEM* item : selection )
319 item->ClearTempFlags();
320
321 SHAPE_POLY_SET polySet;
322
323 polySet.Append( makePolysFromClosedGraphics( selection.GetItems(), cfg.m_Strategy ) );
324
325 polySet.Append( makePolysFromChainedSegs( selection.GetItems(), cfg.m_Strategy ) );
326
327 if( cfg.m_Strategy == BOUNDING_HULL )
328 polySet.Append( makePolysFromOpenGraphics( selection.GetItems(), cfg.m_Gap ) );
329
330 if( polySet.IsEmpty() )
331 return false;
332
333 if( cfg.m_Strategy == BOUNDING_HULL )
334 {
335 polySet.ClearArcs();
337 }
338
339 for( int ii = 0; ii < polySet.OutlineCount(); ++ii )
340 {
341 polys.emplace_back( SHAPE_POLY_SET( polySet.COutline( ii ) ) );
342
343 for( int jj = 0; jj < polySet.HoleCount( ii ); ++jj )
344 polys.back().AddHole( polySet.Hole( ii, jj ) );
345 }
346
347 return true;
348 };
349
350 // Pre-flight getPolys() to see if there's anything to convert.
351 CONVERT_SETTINGS preflightSettings = m_userSettings;
352 preflightSettings.m_Strategy = BOUNDING_HULL;
353
354 if( !getPolys( preflightSettings ) )
355 return 0;
356
357 if( BOARD_ITEM* item = dynamic_cast<BOARD_ITEM*>( selection.Front() ) )
358 parentFootprint = item->GetParentFootprint();
359
362 BOARD_COMMIT commit( m_frame );
363
364 if( aEvent.IsAction( &PCB_ACTIONS::convertToPoly ) )
365 {
366 bool showCopyLineWidth = true;
367
368 // No copy-line-width option for pads
369 if( dynamic_cast<PAD*>( selection.Front() ) )
370 {
373
374 showCopyLineWidth = false;
375 }
376
377 CONVERT_SETTINGS_DIALOG dlg( m_frame, &m_userSettings, showCopyLineWidth );
378
379 if( dlg.ShowModal() != wxID_OK )
380 return 0;
381
382 CONVERT_SETTINGS resolvedSettings = m_userSettings;
383
384 if( resolvedSettings.m_Strategy != CENTERLINE )
385 {
386 if( resolvedSettings.m_LineWidth == 0 )
387 resolvedSettings.m_LineWidth = bds.m_LineThickness[ bds.GetLayerClass( layer ) ];
388 }
389
390 if( resolvedSettings.m_Strategy == BOUNDING_HULL )
391 {
392 if( resolvedSettings.m_Gap > 0 )
393 resolvedSettings.m_Gap += KiROUND( (double) resolvedSettings.m_LineWidth / 2 );
394 }
395
396 if( !getPolys( resolvedSettings ) )
397 {
398 DisplayErrorMessage( m_frame, _( "Could not convert selection" ), _( "Objects must form a closed shape" ) );
399 return 0;
400 }
401
402 for( const SHAPE_POLY_SET& poly : polys )
403 {
404 PCB_SHAPE* graphic = new PCB_SHAPE( parentFootprint );
405
406 if( resolvedSettings.m_Strategy == COPY_LINEWIDTH )
407 {
408 BOARD_ITEM* topLeftItem = nullptr;
409 VECTOR2I pos;
410
411 for( EDA_ITEM* item : selection )
412 {
413 if( BOARD_ITEM* candidate = dynamic_cast<BOARD_ITEM*>( item ) )
414 {
415 if( candidate->HasLineStroke() )
416 {
417 pos = candidate->GetPosition();
418
419 if( !topLeftItem
420 || ( pos.x < topLeftItem->GetPosition().x )
421 || ( topLeftItem->GetPosition().x == pos.x
422 && pos.y < topLeftItem->GetPosition().y ) )
423 {
424 topLeftItem = candidate;
425 resolvedSettings.m_LineWidth = topLeftItem->GetStroke().GetWidth();
426 }
427 }
428 }
429 }
430 }
431
432 graphic->SetShape( SHAPE_T::POLY );
433 graphic->SetStroke( STROKE_PARAMS( resolvedSettings.m_LineWidth, PLOT_DASH_TYPE::SOLID,
434 COLOR4D::UNSPECIFIED ) );
435 graphic->SetFilled( resolvedSettings.m_Strategy == CENTERLINE );
436 graphic->SetLayer( destLayer );
437 graphic->SetPolyShape( poly );
438
439 commit.Add( graphic );
440 }
441 }
442 else
443 {
444 // Creating zone or keepout
445 PCB_BASE_EDIT_FRAME* frame = getEditFrame<PCB_BASE_EDIT_FRAME>();
446 BOARD_ITEM_CONTAINER* parent = frame->GetModel();
447 ZONE_SETTINGS zoneInfo = frame->GetZoneSettings();
448
449 bool nonCopper = IsNonCopperLayer( destLayer );
450 zoneInfo.m_Layers.reset().set( destLayer );
451 zoneInfo.m_Name.Empty();
452
453 int ret;
454
455 // No copy-line-width option for zones/keepouts
458
460 {
461 zoneInfo.SetIsRuleArea( true );
462 ret = InvokeRuleAreaEditor( frame, &zoneInfo, &m_userSettings );
463 }
464 else if( nonCopper )
465 {
466 zoneInfo.SetIsRuleArea( false );
467 ret = InvokeNonCopperZonesEditor( frame, &zoneInfo, &m_userSettings );
468 }
469 else
470 {
471 zoneInfo.SetIsRuleArea( false );
472 ret = InvokeCopperZonesEditor( frame, &zoneInfo, &m_userSettings );
473 }
474
475 if( ret == wxID_CANCEL )
476 return 0;
477
478 if( !getPolys( m_userSettings ) )
479 return 0;
480
481 for( const SHAPE_POLY_SET& poly : polys )
482 {
483 ZONE* zone = new ZONE( parent );
484
485 *zone->Outline() = poly;
486 zone->HatchBorder();
487
488 zoneInfo.ExportSetting( *zone );
489
490 commit.Add( zone );
491 }
492 }
493
495 {
496 PCB_SELECTION selectionCopy = selection;
498
499 for( EDA_ITEM* item : selectionCopy )
500 {
501 if( item->GetFlags() & SKIP_STRUCT )
502 commit.Remove( item );
503 }
504 }
505
506 if( aEvent.IsAction( &PCB_ACTIONS::convertToPoly ) )
507 {
509 commit.Push( _( "Convert to Polygon" ) );
510 else
511 commit.Push( _( "Create Polygon" ) );
512 }
513 else
514 {
516 commit.Push( _( "Convert to Zone" ) );
517 else
518 commit.Push( _( "Create Zone" ) );
519 }
520
521 return 0;
522}
523
524
525SHAPE_POLY_SET CONVERT_TOOL::makePolysFromChainedSegs( const std::deque<EDA_ITEM*>& aItems,
526 CONVERT_STRATEGY aStrategy )
527{
528 // TODO: This code has a somewhat-similar purpose to ConvertOutlineToPolygon but is slightly
529 // different, so this remains a separate algorithm. It might be nice to analyze the dfiferences
530 // in requirements and refactor this.
531
532 // Using a large epsilon here to allow for sloppy drawing can cause the algorithm to miss very
533 // short segments in a converted bezier. So use an epsilon only large enough to cover for
534 // rouding errors in the conversion.
535 int chainingEpsilon = 100; // max dist from one endPt to next startPt in IU
536
538 SHAPE_POLY_SET poly;
539
540 // Stores pairs of (anchor, item) where anchor == 0 -> SEG.A, anchor == 1 -> SEG.B
541 std::map<VECTOR2I, std::vector<std::pair<int, EDA_ITEM*>>> connections;
542 std::deque<EDA_ITEM*> toCheck;
543
544 auto closeEnough =
545 []( VECTOR2I aLeft, VECTOR2I aRight, int aLimit )
546 {
547 return ( aLeft - aRight ).SquaredEuclideanNorm() <= SEG::Square( aLimit );
548 };
549
550 auto findInsertionPoint =
551 [&]( VECTOR2I aPoint ) -> VECTOR2I
552 {
553 if( connections.count( aPoint ) )
554 return aPoint;
555
556 for( const auto& candidatePair : connections )
557 {
558 if( closeEnough( aPoint, candidatePair.first, chainingEpsilon ) )
559 return candidatePair.first;
560 }
561
562 return aPoint;
563 };
564
565 for( EDA_ITEM* item : aItems )
566 {
567 if( std::optional<SEG> seg = getStartEndPoints( item ) )
568 {
569 toCheck.push_back( item );
570 connections[findInsertionPoint( seg->A )].emplace_back( std::make_pair( 0, item ) );
571 connections[findInsertionPoint( seg->B )].emplace_back( std::make_pair( 1, item ) );
572 }
573 }
574
575 while( !toCheck.empty() )
576 {
577 std::vector<BOARD_ITEM*> insertedItems;
578
579 EDA_ITEM* candidate = toCheck.front();
580 toCheck.pop_front();
581
582 if( candidate->GetFlags() & SKIP_STRUCT )
583 continue;
584
585 SHAPE_LINE_CHAIN outline;
586
587 auto insert =
588 [&]( EDA_ITEM* aItem, VECTOR2I aAnchor, bool aDirection )
589 {
590 if( aItem->Type() == PCB_ARC_T
591 || ( aItem->Type() == PCB_SHAPE_T
592 && static_cast<PCB_SHAPE*>( aItem )->GetShape() == SHAPE_T::ARC ) )
593 {
594 SHAPE_ARC arc;
595
596 if( aItem->Type() == PCB_ARC_T )
597 {
598 PCB_ARC* pcb_arc = static_cast<PCB_ARC*>( aItem );
599 arc = *static_cast<SHAPE_ARC*>( pcb_arc->GetEffectiveShape().get() );
600 }
601 else
602 {
603 PCB_SHAPE* pcb_shape = static_cast<PCB_SHAPE*>( aItem );
604 arc = SHAPE_ARC( pcb_shape->GetStart(), pcb_shape->GetArcMid(),
605 pcb_shape->GetEnd(), pcb_shape->GetWidth() );
606 }
607
608 if( aDirection )
609 outline.Append( aAnchor == arc.GetP0() ? arc : arc.Reversed() );
610 else
611 outline.Insert( 0, aAnchor == arc.GetP0() ? arc : arc.Reversed() );
612
613 insertedItems.push_back( static_cast<BOARD_ITEM*>( aItem ) );
614 }
615 else if( aItem->IsType( { PCB_SHAPE_LOCATE_BEZIER_T } ) )
616 {
617 PCB_SHAPE* graphic = static_cast<PCB_SHAPE*>( aItem );
618
619 if( aAnchor == graphic->GetStart() )
620 {
621 for( auto it = graphic->GetBezierPoints().begin();
622 it != graphic->GetBezierPoints().end();
623 ++it )
624 {
625 if( aDirection )
626 outline.Append( *it );
627 else
628 outline.Insert( 0, *it );
629 }
630
631 }
632 else
633 {
634 for( auto it = graphic->GetBezierPoints().rbegin();
635 it != graphic->GetBezierPoints().rend();
636 ++it )
637 {
638 if( aDirection )
639 outline.Append( *it );
640 else
641 outline.Insert( 0, *it );
642 }
643 }
644
645 insertedItems.push_back( static_cast<BOARD_ITEM*>( aItem ) );
646 }
647 else if( std::optional<SEG> nextSeg = getStartEndPoints( aItem ) )
648 {
649 VECTOR2I& point = ( aAnchor == nextSeg->A ) ? nextSeg->B : nextSeg->A;
650
651 if( aDirection )
652 outline.Append( point );
653 else
654 outline.Insert( 0, point );
655
656 insertedItems.push_back( static_cast<BOARD_ITEM*>( aItem ) );
657 }
658 };
659
660 // aDirection == true for walking "right" and appending to the end of points
661 // false for walking "left" and prepending to the beginning
662 std::function<void( EDA_ITEM*, VECTOR2I, bool )> process =
663 [&]( EDA_ITEM* aItem, VECTOR2I aAnchor, bool aDirection )
664 {
665 if( aItem->GetFlags() & SKIP_STRUCT )
666 return;
667
668 aItem->SetFlags( SKIP_STRUCT );
669
670 insert( aItem, aAnchor, aDirection );
671
672 std::optional<SEG> anchors = getStartEndPoints( aItem );
673 wxASSERT( anchors );
674
675 VECTOR2I nextAnchor = ( aAnchor == anchors->A ) ? anchors->B : anchors->A;
676
677 for( std::pair<int, EDA_ITEM*> pair : connections[nextAnchor] )
678 {
679 if( pair.second == aItem )
680 continue;
681
682 process( pair.second, nextAnchor, aDirection );
683 }
684 };
685
686 std::optional<SEG> anchors = getStartEndPoints( candidate );
687 wxASSERT( anchors );
688
689 // Start with the first object and walk "right"
690 // Note if the first object is an arc, we don't need to insert its first point here, the
691 // whole arc will be inserted at anchor B inside process()
692 if( !( candidate->Type() == PCB_ARC_T
693 || ( candidate->Type() == PCB_SHAPE_T
694 && static_cast<PCB_SHAPE*>( candidate )->GetShape() == SHAPE_T::ARC ) ) )
695 {
696 insert( candidate, anchors->A, true );
697 }
698
699 process( candidate, anchors->B, true );
700
701 // check for any candidates on the "left"
702 EDA_ITEM* left = nullptr;
703
704 for( std::pair<int, EDA_ITEM*> possibleLeft : connections[anchors->A] )
705 {
706 if( possibleLeft.second != candidate )
707 {
708 left = possibleLeft.second;
709 break;
710 }
711 }
712
713 if( left )
714 process( left, anchors->A, false );
715
716 if( outline.PointCount() < 3
717 || !closeEnough( outline.GetPoint( 0 ), outline.GetPoint( -1 ), chainingEpsilon ) )
718 {
719 for( EDA_ITEM* item : insertedItems )
720 item->ClearFlags( SKIP_STRUCT );
721
722 continue;
723 }
724
725 outline.SetClosed( true );
726
727 poly.AddOutline( outline );
728
729 if( aStrategy == BOUNDING_HULL )
730 {
731 for( BOARD_ITEM* item : insertedItems )
732 {
733 item->TransformShapeToPolygon( poly, UNDEFINED_LAYER, 0, bds.m_MaxError,
734 ERROR_INSIDE, false );
735 }
736 }
737
738 insertedItems.clear();
739 }
740
741 return poly;
742}
743
744
745SHAPE_POLY_SET CONVERT_TOOL::makePolysFromOpenGraphics( const std::deque<EDA_ITEM*>& aItems,
746 int aGap )
747{
749 SHAPE_POLY_SET poly;
750
751 for( EDA_ITEM* item : aItems )
752 {
753 if( item->GetFlags() & SKIP_STRUCT )
754 continue;
755
756 switch( item->Type() )
757 {
758 case PCB_SHAPE_T:
759 {
760 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
761
762 if( shape->IsClosed() )
763 continue;
764
765 shape->TransformShapeToPolygon( poly, UNDEFINED_LAYER, aGap, bds.m_MaxError,
766 ERROR_INSIDE, false );
767 shape->SetFlags( SKIP_STRUCT );
768
769 break;
770 }
771
772 case PCB_TRACE_T:
773 case PCB_ARC_T:
774 case PCB_VIA_T:
775 {
776 PCB_TRACK* track = static_cast<PCB_TRACK*>( item );
777
778 track->TransformShapeToPolygon( poly, UNDEFINED_LAYER, aGap, bds.m_MaxError,
779 ERROR_INSIDE, false );
780 track->SetFlags( SKIP_STRUCT );
781
782 break;
783 }
784
785 default:
786 continue;
787 }
788 }
789
790 return poly;
791}
792
793
795 CONVERT_STRATEGY aStrategy )
796{
798 SHAPE_POLY_SET poly;
799
800 for( EDA_ITEM* item : aItems )
801 {
802 if( item->GetFlags() & SKIP_STRUCT )
803 continue;
804
805 switch( item->Type() )
806 {
807 case PCB_SHAPE_T:
808 {
809 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
810 FILL_T wasFilled = shape->GetFillMode();
811
812 if( !shape->IsClosed() )
813 continue;
814
815 shape->SetFilled( true );
817 aStrategy == COPY_LINEWIDTH || aStrategy == CENTERLINE );
818 shape->SetFillMode( wasFilled );
819 shape->SetFlags( SKIP_STRUCT );
820 break;
821 }
822
823 case PCB_ZONE_T:
824 poly.Append( *static_cast<ZONE*>( item )->Outline() );
825 item->SetFlags( SKIP_STRUCT );
826 break;
827
828 case PCB_FIELD_T:
829 case PCB_TEXT_T:
830 {
831 PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
832 text->TransformTextToPolySet( poly, 0, bds.m_MaxError, ERROR_INSIDE );
833 text->SetFlags( SKIP_STRUCT );
834 break;
835 }
836
837 case PCB_PAD_T:
838 {
839 PAD* pad = static_cast<PAD*>( item );
840 pad->TransformShapeToPolygon( poly, UNDEFINED_LAYER, 0, bds.m_MaxError, ERROR_INSIDE,
841 false );
842 pad->SetFlags( SKIP_STRUCT );
843 break;
844 }
845
846
847 default:
848 continue;
849 }
850 }
851
852 return poly;
853}
854
855
857{
858 auto& selection = m_selectionTool->RequestSelection(
859 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
860 {
861 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
862 {
863 BOARD_ITEM* item = aCollector[i];
864
865 switch( item->Type() )
866 {
867 case PCB_SHAPE_T:
868 switch( static_cast<PCB_SHAPE*>( item )->GetShape() )
869 {
870 case SHAPE_T::SEGMENT:
871 case SHAPE_T::ARC:
872 case SHAPE_T::POLY:
873 case SHAPE_T::RECTANGLE:
874 break;
875
876 default:
877 aCollector.Remove( item );
878 }
879
880 break;
881
882 case PCB_ZONE_T:
883 break;
884
885 default:
886 aCollector.Remove( item );
887 }
888 }
889 } );
890
891 if( selection.Empty() )
892 return 0;
893
894 auto getPolySet =
895 []( EDA_ITEM* aItem )
896 {
897 SHAPE_POLY_SET set;
898
899 switch( aItem->Type() )
900 {
901 case PCB_ZONE_T:
902 set = *static_cast<ZONE*>( aItem )->Outline();
903 break;
904
905 case PCB_SHAPE_T:
906 {
907 PCB_SHAPE* graphic = static_cast<PCB_SHAPE*>( aItem );
908
909 if( graphic->GetShape() == SHAPE_T::POLY )
910 {
911 set = graphic->GetPolyShape();
912 }
913 else if( graphic->GetShape() == SHAPE_T::RECTANGLE )
914 {
915 SHAPE_LINE_CHAIN outline;
916 VECTOR2I start( graphic->GetStart() );
917 VECTOR2I end( graphic->GetEnd() );
918
919 outline.Append( start );
920 outline.Append( VECTOR2I( end.x, start.y ) );
921 outline.Append( end );
922 outline.Append( VECTOR2I( start.x, end.y ) );
923 outline.SetClosed( true );
924
925 set.AddOutline( outline );
926 }
927 else
928 {
929 wxFAIL_MSG( wxT( "Unhandled graphic shape type in PolyToLines - getPolySet" ) );
930 }
931 break;
932 }
933
934 default:
935 wxFAIL_MSG( wxT( "Unhandled type in PolyToLines - getPolySet" ) );
936 break;
937 }
938
939 return set;
940 };
941
942 auto getSegList =
943 []( SHAPE_POLY_SET& aPoly )
944 {
945 std::vector<SEG> segs;
946
947 // Our input should be valid polys, so OK to assert here
948 wxASSERT( aPoly.VertexCount() >= 2 );
949
950 for( int i = 1; i < aPoly.VertexCount(); i++ )
951 segs.emplace_back( SEG( aPoly.CVertex( i - 1 ), aPoly.CVertex( i ) ) );
952
953 segs.emplace_back( SEG( aPoly.CVertex( aPoly.VertexCount() - 1 ),
954 aPoly.CVertex( 0 ) ) );
955
956 return segs;
957 };
958
959 BOARD_COMMIT commit( m_frame );
960 PCB_BASE_EDIT_FRAME* frame = getEditFrame<PCB_BASE_EDIT_FRAME>();
961 FOOTPRINT_EDIT_FRAME* fpEditor = dynamic_cast<FOOTPRINT_EDIT_FRAME*>( m_frame );
962 FOOTPRINT* footprint = nullptr;
963 PCB_LAYER_ID targetLayer = m_frame->GetActiveLayer();
964 BOARD_ITEM_CONTAINER* parent = frame->GetModel();
965
966 if( fpEditor )
967 footprint = fpEditor->GetBoard()->GetFirstFootprint();
968
969 auto handleGraphicSeg =
970 [&]( EDA_ITEM* aItem )
971 {
972 if( aItem->Type() != PCB_SHAPE_T )
973 return false;
974
975 PCB_SHAPE* graphic = static_cast<PCB_SHAPE*>( aItem );
976
977 if( graphic->GetShape() == SHAPE_T::SEGMENT )
978 {
979 PCB_TRACK* track = new PCB_TRACK( parent );
980
981 track->SetLayer( targetLayer );
982 track->SetStart( graphic->GetStart() );
983 track->SetEnd( graphic->GetEnd() );
984 track->SetWidth( graphic->GetWidth() );
985 commit.Add( track );
986
987 return true;
988 }
989 else if( graphic->GetShape() == SHAPE_T::ARC )
990 {
991 PCB_ARC* arc = new PCB_ARC( parent );
992
993 arc->SetLayer( targetLayer );
994 arc->SetStart( graphic->GetStart() );
995 arc->SetEnd( graphic->GetEnd() );
996 arc->SetMid( graphic->GetArcMid() );
997 arc->SetWidth( graphic->GetWidth() );
998 commit.Add( arc );
999
1000 return true;
1001 }
1002
1003 return false;
1004 };
1005
1006 if( aEvent.IsAction( &PCB_ACTIONS::convertToTracks ) )
1007 {
1008 if( !IsCopperLayer( targetLayer ) )
1009 {
1010 targetLayer = frame->SelectOneLayer( F_Cu, LSET::AllNonCuMask() );
1011
1012 if( targetLayer == UNDEFINED_LAYER ) // User canceled
1013 return true;
1014 }
1015 }
1016
1017 for( EDA_ITEM* item : selection )
1018 {
1019 if( handleGraphicSeg( item ) )
1020 continue;
1021
1022 SHAPE_POLY_SET polySet = getPolySet( item );
1023 std::vector<SEG> segs = getSegList( polySet );
1024
1025 if( aEvent.IsAction( &PCB_ACTIONS::convertToLines ) )
1026 {
1027 for( SEG& seg : segs )
1028 {
1029 PCB_SHAPE* graphic = new PCB_SHAPE( footprint, SHAPE_T::SEGMENT );
1030
1031 graphic->SetLayer( targetLayer );
1032 graphic->SetStart( VECTOR2I( seg.A ) );
1033 graphic->SetEnd( VECTOR2I( seg.B ) );
1034 commit.Add( graphic );
1035 }
1036 }
1037 else
1038 {
1039 // I am really unsure converting a polygon to "tracks" (i.e. segments on
1040 // copper layers) make sense for footprints, but anyway this code exists
1041 if( fpEditor )
1042 {
1043 // Creating segments on copper layer
1044 for( SEG& seg : segs )
1045 {
1046 PCB_SHAPE* graphic = new PCB_SHAPE( footprint, SHAPE_T::SEGMENT );
1047 graphic->SetLayer( targetLayer );
1048 graphic->SetStart( VECTOR2I( seg.A ) );
1049 graphic->SetEnd( VECTOR2I( seg.B ) );
1050 commit.Add( graphic );
1051 }
1052 }
1053 else
1054 {
1055 // Creating tracks
1056 for( SEG& seg : segs )
1057 {
1058 PCB_TRACK* track = new PCB_TRACK( parent );
1059
1060 track->SetLayer( targetLayer );
1061 track->SetStart( VECTOR2I( seg.A ) );
1062 track->SetEnd( VECTOR2I( seg.B ) );
1063 commit.Add( track );
1064 }
1065 }
1066 }
1067 }
1068
1069 commit.Push( _( "Create Lines" ) );
1070
1071 return 0;
1072}
1073
1074
1076{
1077 auto& selection = m_selectionTool->RequestSelection(
1078 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
1079 {
1080 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
1081 {
1082 BOARD_ITEM* item = aCollector[i];
1083
1084 if( !( item->Type() == PCB_SHAPE_T ||
1085 item->Type() == PCB_TRACE_T ) )
1086 {
1087 aCollector.Remove( item );
1088 }
1089 }
1090 } );
1091
1092 EDA_ITEM* source = selection.Front();
1093 VECTOR2I start, end, mid;
1094
1095 // Offset the midpoint along the normal a little bit so that it's more obviously an arc
1096 const double offsetRatio = 0.1;
1097
1098 if( std::optional<SEG> seg = getStartEndPoints( source ) )
1099 {
1100 start = seg->A;
1101 end = seg->B;
1102
1103 VECTOR2I normal = ( seg->B - seg->A ).Perpendicular().Resize( offsetRatio * seg->Length() );
1104 mid = seg->Center() + normal;
1105 }
1106 else
1107 {
1108 return -1;
1109 }
1110
1111 PCB_BASE_EDIT_FRAME* frame = getEditFrame<PCB_BASE_EDIT_FRAME>();
1112 BOARD_ITEM_CONTAINER* parent = frame->GetModel();
1113
1114 BOARD_ITEM* boardItem = dynamic_cast<BOARD_ITEM*>( source );
1115
1116 // Don't continue processing if we don't actually have a board item
1117 if( !boardItem )
1118 return 0;
1119
1120 PCB_LAYER_ID layer = boardItem->GetLayer();
1121
1122 BOARD_COMMIT commit( m_frame );
1123
1124 if( source->Type() == PCB_SHAPE_T )
1125 {
1126 PCB_SHAPE* line = static_cast<PCB_SHAPE*>( source );
1127 PCB_SHAPE* arc = new PCB_SHAPE( parent, SHAPE_T::ARC );
1128
1129 VECTOR2I center = CalcArcCenter( start, mid, end );
1130
1131 arc->SetFilled( false );
1132 arc->SetLayer( layer );
1133 arc->SetStroke( line->GetStroke() );
1134
1135 arc->SetCenter( VECTOR2I( center ) );
1136 arc->SetStart( VECTOR2I( start ) );
1137 arc->SetEnd( VECTOR2I( end ) );
1138
1139 commit.Add( arc );
1140 }
1141 else
1142 {
1143 wxASSERT( source->Type() == PCB_TRACE_T );
1144 PCB_TRACK* line = static_cast<PCB_TRACK*>( source );
1145 PCB_ARC* arc = new PCB_ARC( parent );
1146
1147 arc->SetLayer( layer );
1148 arc->SetWidth( line->GetWidth() );
1149 arc->SetStart( VECTOR2I( start ) );
1150 arc->SetMid( VECTOR2I( mid ) );
1151 arc->SetEnd( VECTOR2I( end ) );
1152
1153 commit.Add( arc );
1154 }
1155
1156 commit.Push( _( "Create Arc" ) );
1157
1158 return 0;
1159}
1160
1161
1162std::optional<SEG> CONVERT_TOOL::getStartEndPoints( EDA_ITEM* aItem )
1163{
1164 switch( aItem->Type() )
1165 {
1166 case PCB_SHAPE_T:
1167 {
1168 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( aItem );
1169
1170 switch( shape->GetShape() )
1171 {
1172 case SHAPE_T::SEGMENT:
1173 case SHAPE_T::ARC:
1174 case SHAPE_T::POLY:
1175 case SHAPE_T::BEZIER:
1176 if( shape->GetStart() == shape->GetEnd() )
1177 return std::nullopt;
1178
1179 return std::make_optional<SEG>( VECTOR2I( shape->GetStart() ),
1180 VECTOR2I( shape->GetEnd() ) );
1181
1182 default:
1183 return std::nullopt;
1184 }
1185 }
1186
1187 case PCB_TRACE_T:
1188 {
1189 PCB_TRACK* line = static_cast<PCB_TRACK*>( aItem );
1190 return std::make_optional<SEG>( VECTOR2I( line->GetStart() ), VECTOR2I( line->GetEnd() ) );
1191 }
1192
1193 case PCB_ARC_T:
1194 {
1195 PCB_ARC* arc = static_cast<PCB_ARC*>( aItem );
1196 return std::make_optional<SEG>( VECTOR2I( arc->GetStart() ), VECTOR2I( arc->GetEnd() ) );
1197 }
1198
1199 default:
1200 return std::nullopt;
1201 }
1202}
1203
1204
1206{
1213}
static PGM_BASE * process
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
virtual void Push(const wxString &aMessage=wxT("A commit"), 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]
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:204
virtual STROKE_PARAMS GetStroke() const
Definition: board_item.cpp:84
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:238
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:247
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
Definition: board.h:406
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:731
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:90
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been added.
Definition: commit.h:78
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.
wxRadioButton * m_rbEnvelope
CONVERT_SETTINGS * m_settings
bool TransferDataToWindow() override
CONVERT_SETTINGS_DIALOG(EDA_DRAW_FRAME *aParent, CONVERT_SETTINGS *aSettings, bool aShowCopyLineWidth)
wxStaticText * m_gapLabel
wxRadioButton * m_rbMimicLineWidth
wxRadioButton * m_rbCenterline
void onRadioButton(wxCommandEvent &aEvent)
wxStaticText * m_gapUnits
bool TransferDataFromWindow() override
wxCheckBox * m_cbDeleteOriginals
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:83
void SetupStandardButtons(std::map< int, wxString > aLabels={})
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:85
virtual VECTOR2I GetPosition() const
Definition: eda_item.h:239
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:123
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:172
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:126
void SetCenter(const VECTOR2I &aCenter)
Definition: eda_shape.cpp:540
FILL_T GetFillMode() const
Definition: eda_shape.h:102
SHAPE_POLY_SET & GetPolyShape()
Definition: eda_shape.h:256
void SetFilled(bool aFlag)
Definition: eda_shape.h:96
SHAPE_T GetShape() const
Definition: eda_shape.h:117
void SetPolyShape(const SHAPE_POLY_SET &aShape)
Definition: eda_shape.h:264
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:149
bool IsClosed() const
Definition: eda_shape.cpp:211
void SetStart(const VECTOR2I &aStart)
Definition: eda_shape.h:128
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:124
void SetShape(SHAPE_T aShape)
Definition: eda_shape.h:116
const std::vector< VECTOR2I > & GetBezierPoints() const
Definition: eda_shape.h:239
void SetEnd(const VECTOR2I &aEnd)
Definition: eda_shape.h:153
void SetFillMode(FILL_T aFill)
Definition: eda_shape.h:101
VECTOR2I GetArcMid() const
Definition: eda_shape.cpp:558
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:204
static LSET AllNonCuMask()
Return a mask holding all layer minus CU layers.
Definition: lset.cpp:794
Definition: pad.h:58
static TOOL_ACTION convertToKeepout
Definition: pcb_actions.h:547
static TOOL_ACTION convertToTracks
Definition: pcb_actions.h:550
static TOOL_ACTION convertToLines
Definition: pcb_actions.h:548
static TOOL_ACTION convertToZone
Definition: pcb_actions.h:546
static TOOL_ACTION convertToPoly
Definition: pcb_actions.h:545
static TOOL_ACTION convertToArc
Definition: pcb_actions.h:549
static TOOL_ACTION createArray
Tool for creating an array of objects.
Definition: pcb_actions.h:458
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:1224
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:275
virtual PCB_LAYER_ID GetActiveLayer() const
const ZONE_SETTINGS & GetZoneSettings() 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:149
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition: pcb_shape.cpp:97
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:568
STROKE_PARAMS GetStroke() const override
Definition: pcb_shape.h:82
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: pcb_shape.h:83
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:1230
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.
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:588
const VECTOR2I & GetP0() const
Definition: shape_arc.h:112
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)
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:81
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
virtual long long int GetValue()
Return the current value in Internal Units.
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.
ZONE_SETTINGS handles zones parameters.
Definition: zone_settings.h:70
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:97
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:914
SHAPE_POLY_SET * Outline()
Definition: zone.h:325
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:40
@ FRAME_FOOTPRINT_EDITOR
Definition: frame_type.h:41
@ ERROR_INSIDE
bool IsNonCopperLayer(int aLayerId)
Test whether a layer is a non copper layer.
Definition: layer_ids.h:858
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:847
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:65
This file contains miscellaneous commonly used macros and functions.
CONVERT_STRATEGY
@ COPY_LINEWIDTH
@ CENTERLINE
@ BOUNDING_HULL
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:458
@ 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:94
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:104
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:91
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition: typeinfo.h:90
@ PCB_SHAPE_LOCATE_CIRCLE_T
Definition: typeinfo.h:132
@ PCB_SHAPE_LOCATE_SEGMENT_T
Definition: typeinfo.h:130
@ PCB_SHAPE_LOCATE_RECT_T
Definition: typeinfo.h:131
@ PCB_SHAPE_LOCATE_BEZIER_T
Definition: typeinfo.h:135
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
@ PCB_SHAPE_LOCATE_POLY_T
Definition: typeinfo.h:134
@ PCB_SHAPE_LOCATE_ARC_T
Definition: typeinfo.h:133
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:95
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:93
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:85
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588