28#include <wx/statline.h>
29#include <wx/checkbox.h>
31#include <wx/radiobut.h>
65 bool aShowCopyLineWidthOption,
bool aShowCenterlineOption,
66 bool aShowBoundingHullOption ) :
67 DIALOG_SHIM( aParent, wxID_ANY,
_(
"Conversion Settings" ), wxDefaultPosition,
68 wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ),
74 aShowCopyLineWidthOption,
75 aShowCenterlineOption,
76 aShowBoundingHullOption ) );
78 wxBoxSizer* mainSizer =
new wxBoxSizer( wxVERTICAL );
79 wxBoxSizer* topSizer =
new wxBoxSizer( wxVERTICAL );
80 SetSizer( mainSizer );
82 m_rbMimicLineWidth =
new wxRadioButton(
this, wxID_ANY,
_(
"Copy line width of first object" ) );
84 if( aShowCopyLineWidthOption )
89 m_rbCenterline =
new wxRadioButton(
this, wxID_ANY,
_(
"Use centerlines" ) );
91 if( aShowCenterlineOption )
93 topSizer->AddSpacer( 6 );
101 m_rbBoundingHull =
new wxRadioButton(
this, wxID_ANY,
_(
"Create bounding hull" ) );
103 m_gapLabel =
new wxStaticText(
this, wxID_ANY,
_(
"Gap:" ) );
104 m_gapCtrl =
new wxTextCtrl(
this, wxID_ANY );
105 m_gapUnits =
new wxStaticText(
this, wxID_ANY,
_(
"mm" ) );
108 m_widthLabel =
new wxStaticText(
this, wxID_ANY,
_(
"Line width:" ) );
110 m_widthUnits =
new wxStaticText(
this, wxID_ANY,
_(
"mm" ) );
113 if( aShowBoundingHullOption )
115 topSizer->AddSpacer( 6 );
118 wxBoxSizer* hullParamsSizer =
new wxBoxSizer( wxHORIZONTAL );
119 hullParamsSizer->Add(
m_gapLabel, 0, wxALIGN_CENTRE_VERTICAL, 5 );
120 hullParamsSizer->Add(
m_gapCtrl, 1, wxALIGN_CENTRE_VERTICAL|wxLEFT|wxRIGHT, 3 );
121 hullParamsSizer->Add(
m_gapUnits, 0, wxALIGN_CENTRE_VERTICAL, 5 );
122 hullParamsSizer->AddSpacer( 18 );
123 hullParamsSizer->Add(
m_widthLabel, 0, wxALIGN_CENTRE_VERTICAL, 5 );
124 hullParamsSizer->Add(
m_widthCtrl, 1, wxALIGN_CENTRE_VERTICAL|wxLEFT|wxRIGHT, 3 );
125 hullParamsSizer->Add(
m_widthUnits, 0, wxALIGN_CENTRE_VERTICAL, 5 );
127 topSizer->AddSpacer( 2 );
128 topSizer->Add( hullParamsSizer, 0, wxLEFT, 26 );
130 topSizer->AddSpacer( 15 );
135 m_gap->Show(
false,
true );
139 m_cbDeleteOriginals =
new wxCheckBox(
this, wxID_ANY,
_(
"Delete source objects after conversion" ) );
142 mainSizer->Add( topSizer, 1, wxALL|wxEXPAND, 10 );
144 wxBoxSizer* buttonsSizer =
new wxBoxSizer( wxHORIZONTAL );
145 buttonsSizer->AddStretchSpacer();
147 wxStdDialogButtonSizer* sdbSizer =
new wxStdDialogButtonSizer();
148 wxButton* sdbSizerOK =
new wxButton(
this, wxID_OK );
149 sdbSizer->AddButton( sdbSizerOK );
150 wxButton* sdbSizerCancel =
new wxButton(
this, wxID_CANCEL );
151 sdbSizer->AddButton( sdbSizerCancel );
154 buttonsSizer->Add( sdbSizer, 1, 0, 5 );
155 mainSizer->Add( buttonsSizer, 0, wxALL|wxEXPAND, 5 );
265 m_menu->SetTitle(
_(
"Create from Selection" ) );
268 static const std::vector<KICAD_T> toArcTypes = {
PCB_ARC_T,
283 static const std::vector<KICAD_T> polyTypes = {
PCB_ZONE_T,
296 auto canCreatePoly = shapes || anyPolys || anyTracks;
301 canCreatePoly = shapes || anyPolys || anyTracks || anyPads;
303 auto canCreateLines = anyPolys;
304 auto canCreateTracks = anyPolys || graphicToTrack;
305 auto canCreate = canCreatePoly
351 std::vector<SHAPE_POLY_SET> polys;
369 item->ClearTempFlags();
398 for(
int jj = 0; jj < polySet.
HoleCount( ii ); ++jj )
399 polys.back().AddHole( polySet.
Hole( ii, jj ) );
409 if( !getPolys( preflightSettings ) )
420 bool showCopyLineWidth =
true;
428 showCopyLineWidth =
false;
448 if( resolvedSettings.
m_Gap > 0 )
452 if( !getPolys( resolvedSettings ) )
457 msg =
_(
"Resulting polygon would be empty" );
459 msg =
_(
"Objects must form a closed shape" );
478 if( !item->IsBOARD_ITEM() )
492 topLeftItem = candidate;
506 commit.
Add( graphic );
542 if( ret == wxID_CANCEL )
566 for(
EDA_ITEM* item : selectionCopy )
576 commit.
Push(
_(
"Convert to Polygon" ) );
578 commit.
Push(
_(
"Create Polygon" ) );
583 commit.
Push(
_(
"Convert to Zone" ) );
585 commit.
Push(
_(
"Create Zone" ) );
602 int chainingEpsilon = 100;
607 std::map<VECTOR2I, std::vector<std::pair<int, EDA_ITEM*>>> connections;
608 std::deque<EDA_ITEM*> toCheck;
613 return ( aLeft - aRight ).SquaredEuclideanNorm() <=
SEG::Square( aLimit );
616 auto findInsertionPoint =
619 if( connections.count( aPoint ) )
622 for(
const auto& candidatePair : connections )
624 if( closeEnough( aPoint, candidatePair.first, chainingEpsilon ) )
625 return candidatePair.first;
635 toCheck.push_back( item );
636 connections[findInsertionPoint( seg->A )].emplace_back( std::make_pair( 0, item ) );
637 connections[findInsertionPoint( seg->B )].emplace_back( std::make_pair( 1, item ) );
641 while( !toCheck.empty() )
643 std::vector<BOARD_ITEM*> insertedItems;
645 EDA_ITEM* candidate = toCheck.front();
656 if( aItem->
IsType( { PCB_ARC_T, PCB_SHAPE_LOCATE_ARC_T } ) )
677 insertedItems.push_back(
static_cast<BOARD_ITEM*
>( aItem ) );
679 else if( aItem->
IsType( { PCB_SHAPE_LOCATE_BEZIER_T } ) )
683 if( aAnchor == graphic->
GetStart() )
705 insertedItems.push_back(
static_cast<BOARD_ITEM*
>( aItem ) );
709 VECTOR2I& point = ( aAnchor == nextSeg->A ) ? nextSeg->B : nextSeg->A;
714 outline.
Insert( 0, point );
716 insertedItems.push_back(
static_cast<BOARD_ITEM*
>( aItem ) );
730 insert( aItem, aAnchor, aDirection );
735 VECTOR2I nextAnchor = ( aAnchor == anchors->A ) ? anchors->B : anchors->A;
737 for( std::pair<int, EDA_ITEM*> pair : connections[nextAnchor] )
739 if( pair.second == aItem )
742 process( pair.second, nextAnchor, aDirection );
752 if( !candidate->
IsType( { PCB_ARC_T, PCB_SHAPE_LOCATE_ARC_T } ) )
753 insert( candidate, anchors->A,
true );
755 process( candidate, anchors->B,
true );
760 for( std::pair<int, EDA_ITEM*> possibleLeft : connections[anchors->A] )
762 if( possibleLeft.second != candidate )
764 left = possibleLeft.second;
773 || !closeEnough( outline.
GetPoint( 0 ), outline.
GetPoint( -1 ), chainingEpsilon ) )
775 for(
EDA_ITEM* item : insertedItems )
791 insertedItems.clear();
807 switch( item->Type() )
853 switch( item->Type() )
889 poly.
Append( *
static_cast<ZONE*
>( item )->Outline() );
906 pad->Padstack().ForEachUniqueLayer(
910 pad->TransformShapeToPolygon( layerPoly, aLayer, 0,
pad->GetMaxError(),
ERROR_INSIDE );
933 for(
int i = aCollector.
GetCount() - 1; i >= 0; --i )
937 switch( item->
Type() )
940 switch(
static_cast<PCB_SHAPE*
>( item )->GetShape() )
949 aCollector.
Remove( item );
958 aCollector.
Remove( item );
971 switch( aItem->Type() )
974 set = *
static_cast<ZONE*
>( aItem )->Outline();
991 wxFAIL_MSG( wxT(
"Unhandled graphic shape type in PolyToLines - getPolySet" ) );
997 wxFAIL_MSG( wxT(
"Unhandled type in PolyToLines - getPolySet" ) );
1007 std::vector<SEG> segs;
1010 wxASSERT( aPoly.VertexCount() >= 2 );
1012 for(
int i = 1; i < aPoly.VertexCount(); i++ )
1013 segs.emplace_back(
SEG( aPoly.CVertex( i - 1 ), aPoly.CVertex( i ) ) );
1015 segs.emplace_back(
SEG( aPoly.CVertex( aPoly.VertexCount() - 1 ), aPoly.CVertex( 0 ) ) );
1030 auto handleGraphicSeg =
1046 commit.
Add( track );
1087 if( !item->IsBOARD_ITEM() )
1090 if( handleGraphicSeg( item ) )
1095 std::vector<SEG> segs = getSegList( polySet );
1101 for(
SEG& seg : segs )
1110 if( itemWidth && *itemWidth > 0 )
1113 commit.
Add( graphic );
1123 for(
SEG& seg : segs )
1133 commit.
Add( graphic );
1139 for(
SEG& seg : segs )
1146 commit.
Add( track );
1157 for(
EDA_ITEM* item : selectionCopy )
1161 commit.
Push(
_(
"Create Lines" ) );
1172 for(
int i = aCollector.
GetCount() - 1; i >= 0; --i )
1176 if( !item->
IsType( { PCB_SHAPE_T, PCB_TRACE_T, PCB_ARC_T } ) )
1177 aCollector.
Remove( item );
1188 const double offsetRatio = 0.1;
1195 VECTOR2I normal = ( seg->B - seg->A ).Perpendicular().Resize( offsetRatio * seg->Length() );
1196 mid = seg->Center() +
normal;
1264 commit.
Push(
_(
"Create Arc" ) );
1272 switch( aItem->
Type() )
1285 return std::nullopt;
1290 return std::nullopt;
1307 return std::nullopt;
1319 for(
int i = aCollector.
GetCount() - 1; i >= 0; --i )
1325 if( !item->
IsType( { PCB_PAD_T, PCB_SHAPE_T } ) )
1326 aCollector.
Remove( item );
1339 std::vector<BOARD_ITEM*> items_to_select_on_success;
1344 auto item_modification_handler =
1349 bool any_items_created =
false;
1351 auto item_creation_handler =
1352 [&]( std::unique_ptr<BOARD_ITEM> aItem )
1354 any_items_created =
true;
1355 items_to_select_on_success.push_back( aItem.get() );
1356 commit.
Add( aItem.release() );
1359 auto item_removal_handler =
1364 if( !aItem.GetParentFootprint() )
1372 item_modification_handler,
1373 item_removal_handler );
1400 : outset_params_pcb_edit;
1413 if( !item->IsBOARD_ITEM() )
1424 for(
BOARD_ITEM* item : items_to_select_on_success )
1427 if( any_items_created )
1435 if(
const std::optional<wxString> msg = outset_routine.
GetStatusMessage() )
1436 frame.ShowInfoBarMsg( *msg );
constexpr EDA_IU_SCALE pcbIUScale
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
BASE_SET & reset(size_t pos)
BASE_SET & set(size_t pos)
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
Container for design settings for a BOARD object.
int GetLayerClass(PCB_LAYER_ID aLayer) const
int m_LineThickness[LAYER_CLASS_COUNT]
ZONE_SETTINGS & GetDefaultZoneSettings()
Abstract interface for BOARD_ITEMs capable of storing other items inside.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
virtual STROKE_PARAMS GetStroke() const
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
FOOTPRINT * GetParentFootprint() const
virtual bool HasLineStroke() const
Check if this item has line stoke properties.
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
int GetCount() const
Return the number of objects in the list.
void Remove(int aIndex)
Remove the item at aIndex (first position is 0).
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
COMMIT & Remove(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Remove a new item from the model.
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
CONVERT_SETTINGS * m_settings
bool TransferDataToWindow() override
wxRadioButton * m_rbBoundingHull
wxStaticText * m_gapLabel
wxRadioButton * m_rbMimicLineWidth
wxRadioButton * m_rbCenterline
void onRadioButton(wxCommandEvent &aEvent)
wxStaticText * m_gapUnits
bool TransferDataFromWindow() override
wxCheckBox * m_cbDeleteOriginals
CONVERT_SETTINGS_DIALOG(EDA_DRAW_FRAME *aParent, CONVERT_SETTINGS *aSettings, bool aShowCopyLineWidthOption, bool aShowCenterlineOption, bool aShowBoundingHullOption)
wxStaticText * m_widthLabel
~CONVERT_SETTINGS_DIALOG()
wxStaticText * m_widthUnits
DIALOG_OUTSET_ITEMS, derived from DIALOG_OUTSET_ITEMS_BASE, created by wxFormBuilder.
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...
DIALOG_SHIM(wxWindow *aParent, wxWindowID id, const wxString &title, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER, const wxString &name=wxDialogNameStr)
The base class for create windows for drawing purpose.
A base class for most all the KiCad significant classes used in schematics and boards.
virtual VECTOR2I GetPosition() const
void SetFlags(EDA_ITEM_FLAGS aMask)
KICAD_T Type() const
Returns the type of object.
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
EDA_ITEM_FLAGS GetFlags() const
void SetCenter(const VECTOR2I &aCenter)
FILL_T GetFillMode() const
SHAPE_POLY_SET & GetPolyShape()
void SetPolyShape(const SHAPE_POLY_SET &aShape)
virtual void SetFilled(bool aFlag)
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
void SetStart(const VECTOR2I &aStart)
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
void SetShape(SHAPE_T aShape)
const std::vector< VECTOR2I > & GetBezierPoints() const
void SetEnd(const VECTOR2I &aEnd)
void SetArcGeometry(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Set the three controlling points for an arc.
void SetWidth(int aWidth)
void SetFillMode(FILL_T aFill)
VECTOR2I GetArcMid() const
static const TOOL_EVENT SelectedEvent
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Used when the right click button is pressed, or when the select tool is in effect.
A handler that is based on a set of callbacks provided by the user of the ITEM_MODIFICATION_ROUTINE.
static LSET AllNonCuMask()
Return a mask holding all layer minus CU layers.
void ProcessItem(BOARD_ITEM &aItem)
wxString GetCommitDescription() const override
std::optional< wxString > GetStatusMessage() const
static TOOL_ACTION convertToKeepout
static TOOL_ACTION convertToTracks
static TOOL_ACTION convertToLines
static TOOL_ACTION convertToZone
static TOOL_ACTION convertToPoly
static TOOL_ACTION outsetItems
Create outset items from selection.
static TOOL_ACTION convertToArc
static TOOL_ACTION createArray
Tool for creating an array of objects.
void SetMid(const VECTOR2I &aMid)
const VECTOR2I & GetMid() const
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.
Common, abstract interface for edit frames.
static SELECTION_CONDITION SameLayer()
Creates a functor that tests if selection contains items that belong exclusively to the same layer.
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
int GetWidth() const override
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
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.
STROKE_PARAMS GetStroke() const override
void SetStroke(const STROKE_PARAMS &aStroke) override
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
void SetEnd(const VECTOR2I &aEnd)
void SetStart(const VECTOR2I &aStart)
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.
const VECTOR2I & GetStart() const
const VECTOR2I & GetEnd() const
virtual void SetWidth(int aWidth)
virtual int GetWidth() const
static SEG::ecoord Square(int a)
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.
SHAPE_ARC Reversed() const
const VECTOR2I & GetP0() const
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 BooleanAdd(const SHAPE_POLY_SET &b)
Perform boolean polyset union.
void ClearArcs()
Removes all arc references from all the outlines and holes in the polyset.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
int HoleCount(int aOutline) const
Returns the number of holes in a given outline.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
SHAPE_LINE_CHAIN & Hole(int aOutline, int aHole)
Return the reference to aHole-th hole in the aIndex-th outline.
int NewOutline()
Creates a new empty polygon in the set and returns its index.
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.
ZONE_SETTINGS handles zones parameters.
void SetIsRuleArea(bool aEnable)
void ExportSetting(ZONE &aTarget, bool aFullExport=true) const
Function ExportSetting copy settings to a given zone.
Handle a list of polygons defining a copper zone.
void HatchBorder()
Compute the hatch lines depending on the hatch parameters and stores it in the zone's attribute m_bor...
SHAPE_POLY_SET * Outline()
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
This file is part of the common library.
@ ROUND_ALL_CORNERS
All angles are rounded.
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, BOARD *aBoard, CONVERT_SETTINGS *aConvertSettings)
Function InvokeRuleAreaEditor invokes up a modal dialog window for copper zone editing.
#define STRUCT_DELETED
flag indication structures to be erased
#define SKIP_STRUCT
flag indicating that the structure should be ignored
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
bool IsNonCopperLayer(int aLayerId)
Test whether a layer is a non copper layer.
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
PCB_LAYER_ID
A quick note on layer IDs:
This file contains miscellaneous commonly used macros and functions.
static PGM_BASE * process
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
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.
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
@ PCB_ZONE_T
class ZONE, a copper pour area
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
@ PCB_SHAPE_LOCATE_CIRCLE_T
@ PCB_SHAPE_LOCATE_SEGMENT_T
@ PCB_SHAPE_LOCATE_RECT_T
@ PCB_SHAPE_LOCATE_BEZIER_T
@ PCB_PAD_T
class PAD, a pad in a footprint
@ PCB_SHAPE_LOCATE_POLY_T
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
VECTOR2< int32_t > VECTOR2I