KiCad PCB EDA Suite
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 <dick@softplc.com>
6  * Copyright (C) 2015-2016 Wayne Stambaugh <stambaughw@verizon.net>
7  * Copyright (C) 1992-2020 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 <fctsys.h>
28 #include <confirm.h>
29 #include <trigo.h>
30 #include <kicad_string.h>
31 #include <gestfich.h>
32 #include <pcb_edit_frame.h>
33 #include <dialog_helpers.h>
34 #include <richio.h>
35 #include <filter_reader.h>
36 #include <base_units.h>
37 #include <validators.h>
38 #include <dialog_text_entry.h>
39 #include <class_board.h>
40 #include <class_module.h>
41 #include <class_edge_mod.h>
43 #include <pcbnew.h>
44 #include <math/util.h> // for KiROUND
45 
46 static std::vector< wxRealPoint > PolyEdges;
47 static double ShapeScaleX, ShapeScaleY;
48 static wxSize ShapeSize;
49 static int PolyShapeType;
50 
51 
52 
53 /**************** Polygon Shapes ***********************/
54 
55 enum id_mw_cmd {
57 };
58 
59 
60 /* Setting polynomial form parameters
61  */
62 class MWAVE_POLYGONAL_SHAPE_DLG : public wxDialog
63 {
64 private:
66  wxRadioBox* m_ShapeOptionCtrl;
68 
69 public:
70  MWAVE_POLYGONAL_SHAPE_DLG( PCB_EDIT_FRAME* parent, const wxPoint& pos );
72 
73 private:
74  void OnOkClick( wxCommandEvent& event );
75  void OnCancelClick( wxCommandEvent& event );
76 
93  void ReadDataShapeDescr( wxCommandEvent& event );
94 
95  DECLARE_EVENT_TABLE()
96 };
97 
98 
99 BEGIN_EVENT_TABLE( MWAVE_POLYGONAL_SHAPE_DLG, wxDialog )
100  EVT_BUTTON( wxID_OK, MWAVE_POLYGONAL_SHAPE_DLG::OnOkClick )
101  EVT_BUTTON( wxID_CANCEL, MWAVE_POLYGONAL_SHAPE_DLG::OnCancelClick )
103 END_EVENT_TABLE()
104 
105 
107  const wxPoint& framepos ) :
108  wxDialog( parent, -1, _( "Complex shape" ), framepos, wxSize( 350, 280 ),
109  wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER )
110 {
111  m_Parent = parent;
112 
113  PolyEdges.clear();
114 
115  wxBoxSizer* MainBoxSizer = new wxBoxSizer( wxHORIZONTAL );
116  SetSizer( MainBoxSizer );
117  wxBoxSizer* LeftBoxSizer = new wxBoxSizer( wxVERTICAL );
118  wxBoxSizer* RightBoxSizer = new wxBoxSizer( wxVERTICAL );
119  MainBoxSizer->Add( LeftBoxSizer, 0, wxGROW | wxALL, 5 );
120  MainBoxSizer->Add( RightBoxSizer, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
121 
122  wxButton* Button = new wxButton( this, wxID_OK, _( "OK" ) );
123  RightBoxSizer->Add( Button, 0, wxGROW | wxALL, 5 );
124 
125  Button = new wxButton( this, wxID_CANCEL, _( "Cancel" ) );
126  RightBoxSizer->Add( Button, 0, wxGROW | wxALL, 5 );
127 
128  Button = new wxButton( this, ID_READ_SHAPE_FILE,
129  _( "Read Shape Description File..." ) );
130  RightBoxSizer->Add( Button, 0, wxGROW | wxALL, 5 );
131 
132  wxString shapelist[] = { _( "Normal" ), _( "Symmetrical" ), _( "Mirrored" ) };
133 
134  m_ShapeOptionCtrl = new wxRadioBox( this, -1, _( "Shape Option" ),
135  wxDefaultPosition, wxDefaultSize, 3,
136  shapelist, 1,
137  wxRA_SPECIFY_COLS );
138  LeftBoxSizer->Add( m_ShapeOptionCtrl, 0, wxGROW | wxALL, 5 );
139 
140  m_SizeCtrl = new EDA_SIZE_CTRL( this, _( "Size" ), ShapeSize, parent->GetUserUnits(),
141  LeftBoxSizer );
142 
143  GetSizer()->SetSizeHints( this );
144 }
145 
146 
147 void MWAVE_POLYGONAL_SHAPE_DLG::OnCancelClick( wxCommandEvent& event )
148 {
149  PolyEdges.clear();
150  EndModal( wxID_CANCEL );
151 }
152 
153 
154 void MWAVE_POLYGONAL_SHAPE_DLG::OnOkClick( wxCommandEvent& event )
155 {
157  PolyShapeType = m_ShapeOptionCtrl->GetSelection();
158  EndModal( wxID_OK );
159 }
160 
161 
163 {
164  static wxString lastpath; // To remember the last open path during a session
165  wxString mask = wxFileSelectorDefaultWildcardStr;
166 
167  wxString FullFileName = EDA_FILE_SELECTOR( _( "Read descr shape file" ), lastpath,
168  FullFileName, wxEmptyString, mask, this,
169  wxFD_OPEN, true );
170  if( FullFileName.IsEmpty() )
171  return;
172 
173  wxFileName fn( FullFileName );
174  lastpath = fn.GetPath();
175  PolyEdges.clear();
176 
177  FILE* File = wxFopen( FullFileName, wxT( "rt" ) );
178 
179  if( File == NULL )
180  {
181  DisplayError( this, _( "File not found" ) );
182  return;
183  }
184 
185  double unitconv = IU_PER_MM;
186  ShapeScaleX = ShapeScaleY = 1.0;
187 
188  FILE_LINE_READER fileReader( File, FullFileName );
189  FILTER_READER reader( fileReader );
190 
191  LOCALE_IO toggle;
192 
193  while( reader.ReadLine() )
194  {
195  char* Line = reader.Line();
196  char* param1 = strtok( Line, " =\n\r" );
197  char* param2 = strtok( NULL, " \t\n\r" );
198 
199  if( strncasecmp( param1, "Unit", 4 ) == 0 )
200  {
201  if( strncasecmp( param2, "inch", 4 ) == 0 )
202  unitconv = IU_PER_MILS*1000;
203 
204  if( strncasecmp( param2, "mm", 2 ) == 0 )
205  unitconv = IU_PER_MM;
206  }
207 
208  if( strncasecmp( param1, "$ENDCOORD", 8 ) == 0 )
209  break;
210 
211  if( strncasecmp( param1, "$COORD", 6 ) == 0 )
212  {
213  while( reader.ReadLine() )
214  {
215  Line = reader.Line();
216  param1 = strtok( Line, " \t\n\r" );
217  param2 = strtok( NULL, " \t\n\r" );
218 
219  if( strncasecmp( param1, "$ENDCOORD", 8 ) == 0 )
220  break;
221 
222  wxRealPoint coord( atof( param1 ), atof( param2 ) );
223  PolyEdges.push_back( coord );
224  }
225  }
226 
227  if( strncasecmp( Line, "XScale", 6 ) == 0 )
228  ShapeScaleX = atof( param2 );
229 
230  if( strncasecmp( Line, "YScale", 6 ) == 0 )
231  ShapeScaleY = atof( param2 );
232  }
233 
234  ShapeScaleX *= unitconv;
235  ShapeScaleY *= unitconv;
236 
237  m_SizeCtrl->SetValue( (int) ShapeScaleX, (int) ShapeScaleY );
238 }
239 
240 
242 {
243  D_PAD* pad1, * pad2;
244  MODULE* module;
245  wxString cmp_name;
246  int pad_count = 2;
247  EDGE_MODULE* edge;
248 
249  PCB_EDIT_FRAME& editFrame = *getEditFrame<PCB_EDIT_FRAME>();
250 
251  MWAVE_POLYGONAL_SHAPE_DLG dlg( &editFrame, wxDefaultPosition );
252 
253  int ret = dlg.ShowModal();
254 
255  if( ret != wxID_OK )
256  {
257  PolyEdges.clear();
258  return NULL;
259  }
260 
261  if( PolyShapeType == 2 ) // mirrored
263 
266 
267  if( ( ShapeSize.x ) == 0 || ( ShapeSize.y == 0 ) )
268  {
269  editFrame.ShowInfoBarError( _( "Shape has a null size!" ) );
270  return NULL;
271  }
272 
273  if( PolyEdges.size() == 0 )
274  {
275  editFrame.ShowInfoBarError( _( "Shape has no points!" ) );
276  return NULL;
277  }
278 
279  cmp_name = wxT( "muwave_polygon" );
280 
281  // Create a footprint with 2 pads, orientation = 0, pos 0
282  module = createBaseFootprint( cmp_name, 0, pad_count );
283 
284  // We try to place the footprint anchor to the middle of the shape len
285  wxPoint offset;
286  offset.x = -ShapeSize.x / 2;
287 
288  auto it = module->Pads().begin();
289 
290  pad1 = *it;
291  pad1->SetX0( offset.x );
292  pad1->SetX( pad1->GetPos0().x );
293 
294  pad2 = *( ++it );
295  pad2->SetX0( offset.x + ShapeSize.x );
296  pad2->SetX( pad2->GetPos0().x );
297 
298  // Add a polygonal edge (corners will be added later) on copper layer
299  edge = new EDGE_MODULE( module );
300  edge->SetShape( S_POLYGON );
301  edge->SetLayer( F_Cu );
302 
303  module->Add( edge, ADD_MODE::INSERT );
304 
305  // Get the corner buffer of the polygonal edge
306  std::vector<wxPoint> polyPoints;
307  polyPoints.reserve( PolyEdges.size() + 2 );
308 
309  // Init start point coord:
310  polyPoints.emplace_back( wxPoint( offset.x, 0 ) );
311 
312  wxPoint last_coordinate;
313 
314  for( wxRealPoint& pt: PolyEdges ) // Copy points
315  {
316  last_coordinate.x = KiROUND( pt.x * ShapeScaleX );
317  last_coordinate.y = -KiROUND( pt.y * ShapeScaleY );
318  last_coordinate += offset;
319  polyPoints.push_back( last_coordinate );
320  }
321 
322  // finish the polygonal shape
323  if( last_coordinate.y != 0 )
324  polyPoints.emplace_back( wxPoint( last_coordinate.x, 0 ) );
325 
326  switch( PolyShapeType )
327  {
328  case 0: // shape from file
329  case 2: // shape from file, mirrored (the mirror is already done)
330  break;
331 
332  case 1: // Symmetric shape: add the symmetric (mirrored) shape
333  for( int ndx = (int) polyPoints.size() - 1; ndx >= 0; --ndx )
334  {
335  wxPoint pt = polyPoints[ndx];
336  pt.y = -pt.y; // mirror about X axis
337  polyPoints.push_back( pt );
338  }
339  break;
340  }
341 
342  edge->SetPolyPoints( polyPoints );
343  // Set the polygon outline thickness to 0, only the polygonal shape is filled
344  // without extra thickness
345  edge->SetWidth( 0 );
346  PolyEdges.clear();
347 
349  editFrame.OnModify();
350  return module;
351 }
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:239
MWAVE_POLYGONAL_SHAPE_DLG(PCB_EDIT_FRAME *parent, const wxPoint &pos)
void OnModify() override
Function OnModify must be called after a board change to set the modified flag.
void SetShape(STROKE_T aShape)
char * Line() const
Function Line returns a pointer to the last line that was read in.
Definition: richio.h:139
const wxPoint & GetPos0() const
Definition: class_pad.h:218
MODULE * createBaseFootprint(const wxString &aValue, int aTextSize, int aPadCount)
Create a basic footprint for micro wave applications.
This file is part of the common library TODO brief description.
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: common.h:216
virtual void SetLayer(PCB_LAYER_ID aLayer)
Function SetLayer sets the layer this item is on.
Implementation of conversion functions that require both schematic and board internal units.
This file is part of the common library.
static constexpr double IU_PER_MM
Mock up a conversion function.
void CalculateBoundingBox()
Function CalculateBoundingBox calculates the bounding box in board coordinates.
polygon (not yet used for tracks, but could be in microwave apps)
PADS & Pads()
Definition: class_module.h:174
MODULE * createPolygonShape()
char * ReadLine() override
Function ReadLine reads a line of text into the buffer and increments the line number counter.
FILE_LINE_READER is a LINE_READER that reads from an open file.
Definition: richio.h:180
#define NULL
void OnOkClick(wxCommandEvent &event)
void ReadDataShapeDescr(wxCommandEvent &event)
Function ReadDataShapeDescr read a description shape file File format is Unit=MM XScale=271....
wxString EDA_FILE_SELECTOR(const wxString &aTitle, const wxString &aPath, const wxString &aFileName, const wxString &aExtension, const wxString &aWildcard, wxWindow *aParent, int aStyle, const bool aKeepWorkingDirectory, const wxPoint &aPosition, wxString *aMruPath)
Function EDA_FILE_SELECTOR.
Definition: gestfich.cpp:52
void OnCancelClick(wxCommandEvent &event)
Helper dialog and control classes.
static double ShapeScaleY
void ShowInfoBarError(const wxString &aErrorMsg)
static int PolyShapeType
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT) override
void SetPolyPoints(const std::vector< wxPoint > &aPoints)
wxSize GetValue()
MODULE * module() const
#define _(s)
Definition: 3d_actions.cpp:33
static std::vector< wxRealPoint > PolyEdges
PCB_EDIT_FRAME is the main frame for Pcbnew.
#define IU_PER_MILS
Definition: plotter.cpp:138
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:68
void SetX0(int x)
Definition: class_pad.h:221
EDGE_MODULE class definition.
void SetX(int x)
Definition: class_pad.h:215
FILTER_READER reads lines of text from another LINE_READER, but only returns non-comment lines and no...
Definition: filter_reader.h:37
void SetValue(int x_value, int y_value)
Custom text control validator definitions.
static double ShapeScaleX
static wxSize ShapeSize
void SetWidth(int aWidth)