KiCad PCB EDA Suite
microwave.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-2019 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 
53  int aTextSize, int aPadCount )
54 {
55  MODULE* module = CreateNewModule( aValue );
56 
57  if( aTextSize > 0 )
58  {
59  module->Reference().SetTextSize( wxSize( aTextSize, aTextSize ) );
60  module->Reference().SetThickness( aTextSize/5 );
61  module->Value().SetTextSize( wxSize( aTextSize, aTextSize ) );
62  module->Value().SetThickness( aTextSize/5 );
63  }
64 
65  // Create 2 pads used in gaps and stubs. The gap is between these 2 pads
66  // the stub is the pad 2
67  wxString Line;
68  int pad_num = 1;
69 
70  while( aPadCount-- )
71  {
72  D_PAD* pad = new D_PAD( module );
73 
74  module->Add( pad, ADD_MODE::INSERT );
75 
77  pad->SetSize( wxSize( tw, tw ) );
78 
79  pad->SetPosition( module->GetPosition() );
80  pad->SetShape( PAD_SHAPE_RECT );
82  pad->SetLayerSet( F_Cu );
83 
84  Line.Printf( wxT( "%d" ), pad_num );
85  pad->SetName( Line );
86  pad_num++;
87  }
88 
89  return module;
90 }
91 
92 
94 {
95  int oX;
96  D_PAD* pad;
97  MODULE* module;
98  wxString msg, cmp_name;
99  int pad_count = 2;
100  int angle = 0;
101  // Ref and value text size (O = use board default value.
102  // will be set to a value depending on the footprint size, if possible
103  int text_size = 0;
104 
105  // Enter the size of the gap or stub
106  int gap_size = GetDesignSettings().GetCurrentTrackWidth();
107 
108  switch( shape_type )
109  {
110  case 0:
111  msg = _( "Gap Size:" );
112  cmp_name = "muwave_gap";
113  text_size = gap_size;
114  break;
115 
116  case 1:
117  msg = _( "Stub Size:" );
118  cmp_name = "muwave_stub";
119  text_size = gap_size;
120  pad_count = 2;
121  break;
122 
123  case 2:
124  msg = _( "Arc Stub Radius Value:" );
125  cmp_name = "muwave_arcstub";
126  pad_count = 1;
127  break;
128 
129  default:
130  msg = wxT( "???" );
131  break;
132  }
133 
134  wxString value = StringFromValue( GetUserUnits(), gap_size );
135  WX_TEXT_ENTRY_DIALOG dlg( this, msg, _( "Create microwave module" ), value );
136 
137  if( dlg.ShowModal() != wxID_OK )
138  return NULL; // cancelled by user
139 
140  value = dlg.GetValue();
141  gap_size = ValueFromString( GetUserUnits(), value );
142 
143  bool abort = false;
144 
145  if( shape_type == 2 )
146  {
147  double fcoeff = 10.0, fval;
148  msg.Printf( wxT( "%3.1f" ), angle / fcoeff );
149  WX_TEXT_ENTRY_DIALOG angledlg( this, _( "Angle in degrees:" ),
150  _( "Create microwave module" ), msg );
151 
152  if( angledlg.ShowModal() != wxID_OK )
153  return NULL; // cancelled by user
154 
155  msg = angledlg.GetValue();
156 
157  if( !msg.ToDouble( &fval ) )
158  {
159  DisplayError( this, _( "Incorrect number, abort" ) );
160  abort = true;
161  }
162 
163  angle = std::abs( KiROUND( fval * fcoeff ) );
164 
165  if( angle > 1800 )
166  angle = 1800;
167  }
168 
169  if( abort )
170  return NULL;
171 
172  module = CreateMuWaveBaseFootprint( cmp_name, text_size, pad_count );
173  auto it = module->Pads().begin();
174  pad = *it;
175 
176  switch( shape_type )
177  {
178  case 0: //Gap :
179  oX = -( gap_size + pad->GetSize().x ) / 2;
180  pad->SetX0( oX );
181 
182  pad->SetX( pad->GetPos0().x + pad->GetPosition().x );
183 
184  pad = *( it + 1 );
185 
186  pad->SetX0( oX + gap_size + pad->GetSize().x );
187  pad->SetX( pad->GetPos0().x + pad->GetPosition().x );
188  break;
189 
190  case 1: //Stub :
191  pad->SetName( wxT( "1" ) );
192  pad = *( it + 1 );
193  pad->SetY0( -( gap_size + pad->GetSize().y ) / 2 );
194  pad->SetSize( wxSize( pad->GetSize().x, gap_size ) );
195  pad->SetY( pad->GetPos0().y + pad->GetPosition().y );
196  break;
197 
198  case 2: // Arc Stub created by a polygonal approach:
199  {
200  pad->SetShape( PAD_SHAPE_CUSTOM );
202 
203  int numPoints = (angle / 50) + 3; // Note: angles are in 0.1 degrees
204  std::vector<wxPoint> polyPoints;
205  polyPoints.reserve( numPoints );
206 
207  polyPoints.emplace_back( wxPoint( 0, 0 ) );
208 
209  int theta = -angle / 2;
210 
211  for( int ii = 1; ii<numPoints - 1; ii++ )
212  {
213  wxPoint pt( 0, -gap_size );
214  RotatePoint( &pt.x, &pt.y, theta );
215  polyPoints.push_back( pt );
216 
217  theta += 50;
218 
219  if( theta > angle / 2 )
220  theta = angle / 2;
221  }
222 
223  // Close the polygon:
224  polyPoints.push_back( polyPoints[0] );
225 
226  pad->AddPrimitivePoly( polyPoints, 0 ); // add a polygonal basic shape
227  }
228  break;
229 
230  default:
231  break;
232  }
233 
234  module->CalculateBoundingBox();
235  OnModify();
236  return module;
237 }
238 
239 
240 /**************** Polygon Shapes ***********************/
241 
242 enum id_mw_cmd {
244 };
245 
246 
247 /* Setting polynomial form parameters
248  */
249 class MWAVE_POLYGONAL_SHAPE_DLG : public wxDialog
250 {
251 private:
253  wxRadioBox* m_ShapeOptionCtrl;
255 
256 public:
257  MWAVE_POLYGONAL_SHAPE_DLG( PCB_EDIT_FRAME* parent, const wxPoint& pos );
259 
260 private:
261  void OnOkClick( wxCommandEvent& event );
262  void OnCancelClick( wxCommandEvent& event );
263 
280  void ReadDataShapeDescr( wxCommandEvent& event );
281 
282  DECLARE_EVENT_TABLE()
283 };
284 
285 
286 BEGIN_EVENT_TABLE( MWAVE_POLYGONAL_SHAPE_DLG, wxDialog )
287  EVT_BUTTON( wxID_OK, MWAVE_POLYGONAL_SHAPE_DLG::OnOkClick )
288  EVT_BUTTON( wxID_CANCEL, MWAVE_POLYGONAL_SHAPE_DLG::OnCancelClick )
290 END_EVENT_TABLE()
291 
292 
294  const wxPoint& framepos ) :
295  wxDialog( parent, -1, _( "Complex shape" ), framepos, wxSize( 350, 280 ),
296  wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER )
297 {
298  m_Parent = parent;
299 
300  PolyEdges.clear();
301 
302  wxBoxSizer* MainBoxSizer = new wxBoxSizer( wxHORIZONTAL );
303  SetSizer( MainBoxSizer );
304  wxBoxSizer* LeftBoxSizer = new wxBoxSizer( wxVERTICAL );
305  wxBoxSizer* RightBoxSizer = new wxBoxSizer( wxVERTICAL );
306  MainBoxSizer->Add( LeftBoxSizer, 0, wxGROW | wxALL, 5 );
307  MainBoxSizer->Add( RightBoxSizer, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
308 
309  wxButton* Button = new wxButton( this, wxID_OK, _( "OK" ) );
310  RightBoxSizer->Add( Button, 0, wxGROW | wxALL, 5 );
311 
312  Button = new wxButton( this, wxID_CANCEL, _( "Cancel" ) );
313  RightBoxSizer->Add( Button, 0, wxGROW | wxALL, 5 );
314 
315  Button = new wxButton( this, ID_READ_SHAPE_FILE,
316  _( "Read Shape Description File..." ) );
317  RightBoxSizer->Add( Button, 0, wxGROW | wxALL, 5 );
318 
319  wxString shapelist[] = { _( "Normal" ), _( "Symmetrical" ), _( "Mirrored" ) };
320 
321  m_ShapeOptionCtrl = new wxRadioBox( this, -1, _( "Shape Option" ),
322  wxDefaultPosition, wxDefaultSize, 3,
323  shapelist, 1,
324  wxRA_SPECIFY_COLS );
325  LeftBoxSizer->Add( m_ShapeOptionCtrl, 0, wxGROW | wxALL, 5 );
326 
327  m_SizeCtrl = new EDA_SIZE_CTRL( this, _( "Size" ), ShapeSize, parent->GetUserUnits(),
328  LeftBoxSizer );
329 
330  GetSizer()->SetSizeHints( this );
331 }
332 
333 
334 void MWAVE_POLYGONAL_SHAPE_DLG::OnCancelClick( wxCommandEvent& event )
335 {
336  PolyEdges.clear();
337  EndModal( wxID_CANCEL );
338 }
339 
340 
341 void MWAVE_POLYGONAL_SHAPE_DLG::OnOkClick( wxCommandEvent& event )
342 {
344  PolyShapeType = m_ShapeOptionCtrl->GetSelection();
345  EndModal( wxID_OK );
346 }
347 
348 
350 {
351  static wxString lastpath; // To remember the last open path during a session
352  wxString mask = wxFileSelectorDefaultWildcardStr;
353 
354  wxString FullFileName = EDA_FILE_SELECTOR( _( "Read descr shape file" ), lastpath,
355  FullFileName, wxEmptyString, mask, this,
356  wxFD_OPEN, true );
357  if( FullFileName.IsEmpty() )
358  return;
359 
360  wxFileName fn( FullFileName );
361  lastpath = fn.GetPath();
362  PolyEdges.clear();
363 
364  FILE* File = wxFopen( FullFileName, wxT( "rt" ) );
365 
366  if( File == NULL )
367  {
368  DisplayError( this, _( "File not found" ) );
369  return;
370  }
371 
372  double unitconv = IU_PER_MM;
373  ShapeScaleX = ShapeScaleY = 1.0;
374 
375  FILE_LINE_READER fileReader( File, FullFileName );
376  FILTER_READER reader( fileReader );
377 
378  LOCALE_IO toggle;
379 
380  while( reader.ReadLine() )
381  {
382  char* Line = reader.Line();
383  char* param1 = strtok( Line, " =\n\r" );
384  char* param2 = strtok( NULL, " \t\n\r" );
385 
386  if( strncasecmp( param1, "Unit", 4 ) == 0 )
387  {
388  if( strncasecmp( param2, "inch", 4 ) == 0 )
389  unitconv = IU_PER_MILS*1000;
390 
391  if( strncasecmp( param2, "mm", 2 ) == 0 )
392  unitconv = IU_PER_MM;
393  }
394 
395  if( strncasecmp( param1, "$ENDCOORD", 8 ) == 0 )
396  break;
397 
398  if( strncasecmp( param1, "$COORD", 6 ) == 0 )
399  {
400  while( reader.ReadLine() )
401  {
402  Line = reader.Line();
403  param1 = strtok( Line, " \t\n\r" );
404  param2 = strtok( NULL, " \t\n\r" );
405 
406  if( strncasecmp( param1, "$ENDCOORD", 8 ) == 0 )
407  break;
408 
409  wxRealPoint coord( atof( param1 ), atof( param2 ) );
410  PolyEdges.push_back( coord );
411  }
412  }
413 
414  if( strncasecmp( Line, "XScale", 6 ) == 0 )
415  ShapeScaleX = atof( param2 );
416 
417  if( strncasecmp( Line, "YScale", 6 ) == 0 )
418  ShapeScaleY = atof( param2 );
419  }
420 
421  ShapeScaleX *= unitconv;
422  ShapeScaleY *= unitconv;
423 
424  m_SizeCtrl->SetValue( (int) ShapeScaleX, (int) ShapeScaleY );
425 }
426 
427 
429 {
430  D_PAD* pad1, * pad2;
431  MODULE* module;
432  wxString cmp_name;
433  int pad_count = 2;
434  EDGE_MODULE* edge;
435 
436  MWAVE_POLYGONAL_SHAPE_DLG dlg( this, wxDefaultPosition );
437 
438  int ret = dlg.ShowModal();
439 
440  if( ret != wxID_OK )
441  {
442  PolyEdges.clear();
443  return NULL;
444  }
445 
446  if( PolyShapeType == 2 ) // mirrored
448 
451 
452  if( ( ShapeSize.x ) == 0 || ( ShapeSize.y == 0 ) )
453  {
454  DisplayError( this, _( "Shape has a null size!" ) );
455  return NULL;
456  }
457 
458  if( PolyEdges.size() == 0 )
459  {
460  DisplayError( this, _( "Shape has no points!" ) );
461  return NULL;
462  }
463 
464  cmp_name = wxT( "muwave_polygon" );
465 
466  // Create a footprint with 2 pads, orientation = 0, pos 0
467  module = CreateMuWaveBaseFootprint( cmp_name, 0, pad_count );
468 
469  // We try to place the footprint anchor to the middle of the shape len
470  wxPoint offset;
471  offset.x = -ShapeSize.x / 2;
472 
473  auto it = module->Pads().begin();
474 
475  pad1 = *it;
476  pad1->SetX0( offset.x );
477  pad1->SetX( pad1->GetPos0().x );
478 
479  pad2 = *( ++it );
480  pad2->SetX0( offset.x + ShapeSize.x );
481  pad2->SetX( pad2->GetPos0().x );
482 
483  // Add a polygonal edge (corners will be added later) on copper layer
484  edge = new EDGE_MODULE( module );
485  edge->SetShape( S_POLYGON );
486  edge->SetLayer( F_Cu );
487 
488  module->Add( edge, ADD_MODE::INSERT );
489 
490  // Get the corner buffer of the polygonal edge
491  std::vector<wxPoint> polyPoints;
492  polyPoints.reserve( PolyEdges.size() + 2 );
493 
494  // Init start point coord:
495  polyPoints.emplace_back( wxPoint( offset.x, 0 ) );
496 
497  wxPoint last_coordinate;
498 
499  for( wxRealPoint& pt: PolyEdges ) // Copy points
500  {
501  last_coordinate.x = KiROUND( pt.x * ShapeScaleX );
502  last_coordinate.y = -KiROUND( pt.y * ShapeScaleY );
503  last_coordinate += offset;
504  polyPoints.push_back( last_coordinate );
505  }
506 
507  // finish the polygonal shape
508  if( last_coordinate.y != 0 )
509  polyPoints.emplace_back( wxPoint( last_coordinate.x, 0 ) );
510 
511  switch( PolyShapeType )
512  {
513  case 0: // shape from file
514  case 2: // shape from file, mirrored (the mirror is already done)
515  break;
516 
517  case 1: // Symmetric shape: add the symmetric (mirrored) shape
518  for( int ndx = (int) polyPoints.size() - 1; ndx >= 0; --ndx )
519  {
520  wxPoint pt = polyPoints[ndx];
521  pt.y = -pt.y; // mirror about X axis
522  polyPoints.push_back( pt );
523  }
524  break;
525  }
526 
527  edge->SetPolyPoints( polyPoints );
528  // Set the polygon outline thickness to 0, only the polygonal shape is filled
529  // without extra thickness
530  edge->SetWidth( 0 );
531  PolyEdges.clear();
532  module->CalculateBoundingBox();
533  OnModify();
534  return module;
535 }
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)
Definition: microwave.cpp:293
static wxSize ShapeSize
Definition: microwave.cpp:48
void OnModify() override
Function OnModify must be called after a board change to set the modified flag.
TEXTE_MODULE & Reference()
Definition: class_module.h:477
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
virtual BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings returns the BOARD_DESIGN_SETTINGS for the BOARD owned by this frame.
const wxPoint & GetPos0() const
Definition: class_pad.h:294
wxRadioBox * m_ShapeOptionCtrl
Definition: microwave.cpp:253
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:202
int GetCurrentTrackWidth() const
Function GetCurrentTrackWidth.
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.
PCB_EDIT_FRAME * m_Parent
Definition: microwave.cpp:252
id_mw_cmd
Definition: microwave.cpp:242
void CalculateBoundingBox()
Function CalculateBoundingBox calculates the bounding box in board coordinates.
polygon (not yet used for tracks, but could be in microwave apps)
Smd pad, appears on the solder paste layer (default)
Definition: pad_shapes.h:62
PADS & Pads()
Definition: class_module.h:173
wxString StringFromValue(EDA_UNITS aUnits, double aValue, bool aAddUnitSymbol, bool aUseMils)
Function StringFromValue returns the string from aValue according to units (inch, mm ....
Definition: base_units.cpp:234
void SetPosition(const wxPoint &aPos) override
Definition: class_pad.h:240
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:222
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:208
static int PolyShapeType
Definition: microwave.cpp:49
EDA_SIZE_CTRL * m_SizeCtrl
Definition: microwave.cpp:254
MODULE * CreateNewModule(const wxString &aModuleName)
Function CreateNewModule Creates a new module or footprint, at position 0,0 The new module contains o...
void SetY0(int y)
Definition: class_pad.h:296
void AddPrimitivePoly(const SHAPE_POLY_SET &aPoly, int aThickness, bool aMergePrimitives=true)
Has meaning only for free shape pads.
char * ReadLine() override
Function ReadLine reads a line of text into the buffer and increments the line number counter.
void SetAnchorPadShape(PAD_SHAPE_T aShape)
Function SetAnchorPadShape Set the shape of the anchor pad for custm shped pads.
Definition: class_pad.h:274
FILE_LINE_READER is a LINE_READER that reads from an open file.
Definition: richio.h:180
MODULE * Create_MuWavePolygonShape()
Definition: microwave.cpp:428
#define NULL
MODULE * Create_MuWaveComponent(int shape_type)
Create_MuWaveComponent creates a module "GAP" or "STUB" used in micro wave designs.
Definition: microwave.cpp:93
void SetName(const wxString &aName)
Set the pad name (sometimes called pad number, although it can be an array reference like AA12).
Definition: class_pad.h:187
static double ShapeScaleX
Definition: microwave.cpp:47
void OnOkClick(wxCommandEvent &event)
Definition: microwave.cpp:341
TEXTE_MODULE & Value()
read/write accessors:
Definition: class_module.h:476
void ReadDataShapeDescr(wxCommandEvent &event)
Function ReadDataShapeDescr read a description shape file File format is Unit=MM XScale=271....
Definition: microwave.cpp:349
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)
Definition: microwave.cpp:334
Helper dialog and control classes.
void SetSize(const wxSize &aSize)
Definition: class_pad.h:299
void SetAttribute(PAD_ATTR_T aAttribute)
Definition: class_pad.cpp:423
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT) override
void SetPolyPoints(const std::vector< wxPoint > &aPoints)
wxSize GetValue()
void SetLayerSet(LSET aLayerMask)
Definition: class_pad.h:445
wxString GetValue()
void SetY(int y)
Definition: class_pad.h:290
MODULE * CreateMuWaveBaseFootprint(const wxString &aValue, int aTextSize, int aPadCount)
Function CreateMuWaveBaseFootprint create a basic footprint for micro wave applications.
Definition: microwave.cpp:52
#define _(s)
Definition: 3d_actions.cpp:33
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
PCB_EDIT_FRAME is the main frame for Pcbnew.
#define IU_PER_MILS
Definition: plotter.cpp:137
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:61
void SetShape(PAD_SHAPE_T aShape)
Definition: class_pad.h:238
void SetX0(int x)
Definition: class_pad.h:297
long long int ValueFromString(EDA_UNITS aUnits, const wxString &aTextValue, bool aUseMils)
Function ValueFromString converts aTextValue in aUnits to internal units used by the application.
Definition: base_units.cpp:444
Module description (excepted pads)
static double ShapeScaleY
Definition: microwave.cpp:47
const wxSize & GetSize() const
Definition: class_pad.h:300
const wxPoint GetPosition() const override
Definition: class_pad.h:241
EDGE_MODULE class definition.
void SetX(int x)
Definition: class_pad.h:291
FILTER_READER reads lines of text from another LINE_READER, but only returns non-comment lines and no...
Definition: filter_reader.h:37
const wxPoint GetPosition() const override
Definition: class_module.h:210
void SetValue(int x_value, int y_value)
Custom text control validator definitions.
EDA_UNITS GetUserUnits() const
Return the user units currently in use.
static std::vector< wxRealPoint > PolyEdges
Definition: microwave.cpp:46
void SetThickness(int aNewThickness)
Set the pen width.
Definition: eda_text.h:143
void SetWidth(int aWidth)