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