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