KiCad PCB EDA Suite
Loading...
Searching...
No Matches
microwave_polygon.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) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
6 * Copyright (C) 2015-2016 Wayne Stambaugh <[email protected]>
7 * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, you may find one here:
21 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22 * or you may search the http://www.gnu.org website for the version 2 license,
23 * or you may write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 */
26
27#include <confirm.h>
28#include <widgets/unit_binder.h>
29#include <pcb_edit_frame.h>
30#include <dialog_shim.h>
31#include <locale_io.h>
32#include <filter_reader.h>
34#include <board.h>
35#include <footprint.h>
36#include <pcb_shape.h>
38#include <pad.h>
39#include <math/util.h> // for KiROUND
40
41#include <wx/button.h>
42#include <wx/dialog.h>
43#include <wx/filedlg.h>
44#include <wx/radiobox.h>
45#include <wx/sizer.h>
46#include <wx/statbox.h>
47
48static std::vector< wxRealPoint > g_PolyEdges;
50static wxSize g_ShapeSize;
51static int g_PolyShapeType;
52
53
56};
57
58
60{
61public:
62 MWAVE_POLYGONAL_SHAPE_DLG( PCB_EDIT_FRAME* parent, const wxPoint& pos );
63
65 {
66 delete m_sizeX;
67 delete m_sizeY;
68 };
69
70 bool TransferDataFromWindow() override;
71
72private:
73 void OnCancelClick( wxCommandEvent& event );
74
91 void ReadDataShapeDescr( wxCommandEvent& event );
92
94
96 wxRadioBox* m_shapeOptionCtrl;
99};
100
101
102BEGIN_EVENT_TABLE( MWAVE_POLYGONAL_SHAPE_DLG, DIALOG_SHIM )
103 EVT_BUTTON( wxID_CANCEL, MWAVE_POLYGONAL_SHAPE_DLG::OnCancelClick )
105END_EVENT_TABLE()
106
107
109 const wxPoint& framepos ) :
110 DIALOG_SHIM( parent, -1, _( "Complex Shape" ), framepos, wxDefaultSize,
111 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ),
112 m_sizeX(),
113 m_sizeY()
114{
115 m_frame = parent;
116
117 g_PolyEdges.clear();
118
119 wxBoxSizer* mainBoxSizer = new wxBoxSizer( wxVERTICAL );
120 SetSizer( mainBoxSizer );
121
122 // Controls
123
124 wxBoxSizer* topBoxSizer = new wxBoxSizer( wxHORIZONTAL );
125 mainBoxSizer->Add( topBoxSizer, 1, wxGROW | wxALL, 5 );
126
127 wxString shapelist[] = { _( "Normal" ), _( "Symmetrical" ), _( "Mirrored" ) };
128
129 m_shapeOptionCtrl = new wxRadioBox( this, -1, _( "Shape" ),
130 wxDefaultPosition, wxDefaultSize, 3,
131 shapelist, 1,
132 wxRA_SPECIFY_COLS );
133 topBoxSizer->Add( m_shapeOptionCtrl, 1, wxGROW | wxALL, 5 );
134
135 auto sizeSizer = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _( "Size" ) ),
136 wxVERTICAL );
137 wxBoxSizer* xSizer = new wxBoxSizer( wxHORIZONTAL );
138 wxBoxSizer* ySizer = new wxBoxSizer( wxHORIZONTAL );
139
140 topBoxSizer->Add( sizeSizer, 1, wxGROW | wxALL, 5 );
141 sizeSizer->Add( xSizer, 0, 0, 5 );
142 sizeSizer->Add( ySizer, 0, 0, 5 );
143
144 wxStaticText* xLabel = new wxStaticText( this, -1, _( "X:" ) );
145 wxTextCtrl* xCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString );
146 wxStaticText* xUnits = new wxStaticText( this, -1, _( "units" ) );
147
148 xSizer->Add( xLabel, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
149 xSizer->Add( xCtrl, 1, wxALIGN_CENTER_VERTICAL, 5 );
150 xSizer->Add( xUnits, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
151 m_sizeX = new UNIT_BINDER( m_frame, xLabel, xCtrl, xUnits );
152
153 wxStaticText* yLabel = new wxStaticText( this, -1, _( "Y:" ) );
154 wxTextCtrl* yCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString );
155 wxStaticText* yUnits = new wxStaticText( this, -1, _( "units" ) );
156
157 ySizer->Add( yLabel, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
158 ySizer->Add( yCtrl, 1, wxALIGN_CENTER_VERTICAL, 5 );
159 ySizer->Add( yUnits, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
160 m_sizeY = new UNIT_BINDER( m_frame, yLabel, yCtrl, yUnits );
161
162 // Buttons
163
164 wxBoxSizer* buttonsBoxSizer = new wxBoxSizer( wxHORIZONTAL );
165 mainBoxSizer->Add( buttonsBoxSizer, 0, wxALL, 5 );
166
167 wxButton* btn = new wxButton( this, ID_READ_SHAPE_FILE, _( "Read Shape Description File..." ) );
168 buttonsBoxSizer->Add( btn, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, 10 );
169 buttonsBoxSizer->AddStretchSpacer();
170
171 wxStdDialogButtonSizer* sdbSizer = new wxStdDialogButtonSizer();
172 buttonsBoxSizer->Add( sdbSizer, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
173 wxButton* sdbSizerOK = new wxButton( this, wxID_OK );
174 sdbSizer->AddButton( sdbSizerOK );
175 wxButton* sdbSizerCancel = new wxButton( this, wxID_CANCEL );
176 sdbSizer->AddButton( sdbSizerCancel );
177 sdbSizer->Realize();
178
179 GetSizer()->SetSizeHints( this );
180}
181
182
183void MWAVE_POLYGONAL_SHAPE_DLG::OnCancelClick( wxCommandEvent& event )
184{
185 g_PolyEdges.clear();
186 event.Skip();
187}
188
189
191{
192 if( !wxDialog::TransferDataFromWindow() )
193 return false;
194
197 g_PolyShapeType = m_shapeOptionCtrl->GetSelection();
198
199 return true;
200}
201
202
204{
205 static wxString s_lastpath; // To remember the last open path during a session
206 wxString fullFileName;
207 wxString mask = wxFileSelectorDefaultWildcardStr;
208
209 fullFileName = wxFileSelector( _( "Shape Description File" ), s_lastpath,
210 fullFileName, wxEmptyString, mask, wxFD_OPEN, this );
211
212 if( fullFileName.IsEmpty() )
213 return;
214
215 wxFileName fn( fullFileName );
216 s_lastpath = fn.GetPath();
217 g_PolyEdges.clear();
218
219 FILE* File = wxFopen( fullFileName, wxT( "rt" ) );
220
221 if( File == nullptr )
222 {
223 DisplayError( this, _( "File not found" ) );
224 return;
225 }
226
227 double unitconv = pcbIUScale.IU_PER_MM;
229
230 FILE_LINE_READER fileReader( File, fullFileName );
231 FILTER_READER reader( fileReader );
232
233 LOCALE_IO toggle;
234
235 while( reader.ReadLine() )
236 {
237 char* Line = reader.Line();
238 char* param1 = strtok( Line, " =\n\r" );
239 char* param2 = strtok( nullptr, " \t\n\r" );
240
241 if( strncasecmp( param1, "Unit", 4 ) == 0 )
242 {
243 if( strncasecmp( param2, "inch", 4 ) == 0 )
244 unitconv = pcbIUScale.IU_PER_MILS*1000;
245
246 if( strncasecmp( param2, "mm", 2 ) == 0 )
247 unitconv = pcbIUScale.IU_PER_MM;
248 }
249
250 if( strncasecmp( param1, "$ENDCOORD", 8 ) == 0 )
251 break;
252
253 if( strncasecmp( param1, "$COORD", 6 ) == 0 )
254 {
255 while( reader.ReadLine() )
256 {
257 Line = reader.Line();
258 param1 = strtok( Line, " \t\n\r" );
259 param2 = strtok( nullptr, " \t\n\r" );
260
261 if( strncasecmp( param1, "$ENDCOORD", 8 ) == 0 )
262 break;
263
264 wxRealPoint coord( atof( param1 ), atof( param2 ) );
265 g_PolyEdges.push_back( coord );
266 }
267 }
268
269 if( strncasecmp( Line, "XScale", 6 ) == 0 )
270 g_ShapeScaleX = atof( param2 );
271
272 if( strncasecmp( Line, "YScale", 6 ) == 0 )
273 g_ShapeScaleY = atof( param2 );
274 }
275
276 g_ShapeScaleX *= unitconv;
277 g_ShapeScaleY *= unitconv;
278
281}
282
283
285{
286 PAD* pad1;
287 PAD* pad2;
288 FOOTPRINT* footprint;
289 wxString cmp_name;
290 int pad_count = 2;
291 PCB_SHAPE* shape;
292
293 PCB_EDIT_FRAME& editFrame = *getEditFrame<PCB_EDIT_FRAME>();
294
295 MWAVE_POLYGONAL_SHAPE_DLG dlg( &editFrame, wxDefaultPosition );
296
297 int ret = dlg.ShowModal();
298
299 if( ret != wxID_OK )
300 {
301 g_PolyEdges.clear();
302 return nullptr;
303 }
304
305 if( g_PolyShapeType == 2 ) // mirrored
307
310
311 if(( g_ShapeSize.x ) == 0 || ( g_ShapeSize.y == 0 ) )
312 {
313 editFrame.ShowInfoBarError( _( "Shape has a null size." ) );
314 return nullptr;
315 }
316
317 if( g_PolyEdges.size() == 0 )
318 {
319 editFrame.ShowInfoBarError( _( "Shape has no points." ) );
320 return nullptr;
321 }
322
323 cmp_name = wxT( "muwave_polygon" );
324
325 // Create a footprint with 2 pads, orientation = 0, pos 0
326 footprint = createBaseFootprint( cmp_name, 0, pad_count );
327
328 // We try to place the footprint anchor to the middle of the shape len
329 VECTOR2I offset;
330 offset.x = -g_ShapeSize.x / 2;
331
332 auto it = footprint->Pads().begin();
333
334 pad1 = *it;
335 pad1->SetX( offset.x );
336
337 pad2 = *( ++it );
338 pad2->SetX( offset.x + g_ShapeSize.x );
339
340 // Add a polygonal edge (corners will be added later) on copper layer
341 shape = new PCB_SHAPE( footprint, SHAPE_T::POLY );
342 shape->SetFilled( true );
343 shape->SetLayer( F_Cu );
344
345 footprint->Add( shape, ADD_MODE::INSERT );
346
347 // Get the corner buffer of the polygonal edge
348 std::vector<VECTOR2I> polyPoints;
349 polyPoints.reserve( g_PolyEdges.size() + 2 );
350
351 // Init start point coord:
352 polyPoints.emplace_back( VECTOR2I( offset.x, 0 ) );
353
354 VECTOR2I last_coordinate;
355
356 for( wxRealPoint& pt: g_PolyEdges ) // Copy points
357 {
358 last_coordinate.x = KiROUND( pt.x * g_ShapeScaleX );
359 last_coordinate.y = -KiROUND( pt.y * g_ShapeScaleY );
360 last_coordinate += offset;
361 polyPoints.push_back( last_coordinate );
362 }
363
364 // finish the polygonal shape
365 if( last_coordinate.y != 0 )
366 polyPoints.emplace_back( VECTOR2I( last_coordinate.x, 0 ) );
367
368 switch( g_PolyShapeType )
369 {
370 case 0: // shape from file
371 case 2: // shape from file, mirrored (the mirror is already done)
372 break;
373
374 case 1: // Symmetric shape: add the symmetric (mirrored) shape
375 for( int ndx = (int) polyPoints.size() - 1; ndx >= 0; --ndx )
376 {
377 VECTOR2I pt = polyPoints[ndx];
378 pt.y = -pt.y; // mirror about X axis
379 polyPoints.push_back( pt );
380 }
381
382 break;
383 }
384
385 shape->SetPolyPoints( polyPoints );
386
387 // Set the polygon outline thickness to 0, only the polygonal shape is filled
388 // without extra thickness.
389 shape->SetStroke( STROKE_PARAMS( 0, LINE_STYLE::SOLID ) );
390 g_PolyEdges.clear();
391
392 editFrame.OnModify();
393 return footprint;
394}
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:108
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
Definition: dialog_shim.h:88
void ShowInfoBarError(const wxString &aErrorMsg, bool aShowCloseButton=false, WX_INFOBAR::MESSAGE_TYPE aType=WX_INFOBAR::MESSAGE_TYPE::GENERIC)
Show the WX_INFOBAR displayed on the top of the canvas with a message and an error icon on the left o...
void SetFilled(bool aFlag)
Definition: eda_shape.h:101
void SetPolyPoints(const std::vector< VECTOR2I > &aPoints)
Definition: eda_shape.cpp:1236
A LINE_READER that reads from an open file.
Definition: richio.h:185
Read lines of text from another LINE_READER but only returns non-comment lines and non-blank lines fr...
Definition: filter_reader.h:37
char * ReadLine() override
Read a line of text into the buffer and increments the line number counter.
PADS & Pads()
Definition: footprint.h:194
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: footprint.cpp:969
char * Line() const
Return a pointer to the last line that was read in.
Definition: richio.h:129
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:49
FOOTPRINT * createPolygonShape()
void OnCancelClick(wxCommandEvent &event)
bool TransferDataFromWindow() override
void ReadDataShapeDescr(wxCommandEvent &event)
Read a description shape file.
Definition: pad.h:54
void SetX(int x)
Definition: pad.h:249
The main frame for Pcbnew.
void OnModify() override
Must be called after a board change to set the modified flag.
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition: pcb_shape.cpp:317
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: pcb_shape.h:86
Simple container to manage line stroke parameters.
Definition: stroke_params.h:81
virtual long long int GetValue()
Return the current value in Internal Units.
virtual void SetValue(long long int aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion.
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:170
This file is part of the common library.
#define _(s)
@ F_Cu
Definition: layer_ids.h:64
static double g_ShapeScaleX
static double g_ShapeScaleY
static std::vector< wxRealPoint > g_PolyEdges
static int g_PolyShapeType
static wxSize g_ShapeSize
@ ID_READ_SHAPE_FILE
const double IU_PER_MM
Definition: base_units.h:76
const double IU_PER_MILS
Definition: base_units.h:77
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:121
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:673