KiCad PCB EDA Suite
gpcb_plugin.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) 2012 Wayne Stambaugh <stambaughw@gmail.com>
5  * Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
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 
31 #include <trace_helpers.h>
32 #include <math/util.h> // for KiROUND
33 
34 #include <board.h>
35 #include <footprint.h>
36 #include <locale_io.h>
37 #include <pcb_text.h>
38 #include <pcb_shape.h>
39 #include <fp_shape.h>
41 #include <wx_filename.h>
42 
43 #include <wx/dir.h>
44 #include <wx/filename.h>
45 #include <wx/wfstream.h>
46 #include <boost/ptr_container/ptr_map.hpp>
47 #include <memory.h>
48 
49 
50 static inline long parseInt( const wxString& aValue, double aScalar )
51 {
52  double value = std::numeric_limits<double>::max();
53 
54  /*
55  * In 2011 gEDA/pcb introduced values with units, like "10mm" or "200mil".
56  * Unit-less values are still centimils (100000 units per inch), like with
57  * the previous format.
58  *
59  * Distinction between the even older format (mils, 1000 units per inch)
60  * and the pre-2011 format is done in ::parseFOOTPRINT already; the
61  * distinction is by wether an object definition opens with '(' or '['.
62  * All values with explicite unit open with a '[' so there's no need to
63  * consider this distinction when parsing them.
64  *
65  * The solution here is to watch for a unit and, if present, convert the
66  * value to centimils. All unit-less values are read unaltered. This way
67  * the code below can contine to consider all read values to be in mils or
68  * centimils. It also matches the strategy gEDA/pcb uses for backwards
69  * compatibility with its own layouts.
70  *
71  * Fortunately gEDA/pcb allows only units 'mil' and 'mm' in files, see
72  * definition of ALLOW_READABLE in gEDA/pcb's pcb_printf.h. So we don't
73  * have to test for all 11 units gEDA/pcb allows in user dialogs.
74  */
75  if( aValue.EndsWith( wxT( "mm" ) ) )
76  {
77  aScalar *= 100000.0 / 25.4;
78  }
79  else if( aValue.EndsWith( wxT( "mil" ) ) )
80  {
81  aScalar *= 100.;
82  }
83 
84  // This conversion reports failure on strings as simple as "1000", still
85  // it returns the right result in &value. Thus, ignore the return value.
86  aValue.ToCDouble(&value);
87  if( value == std::numeric_limits<double>::max() ) // conversion really failed
88  {
89  THROW_IO_ERROR( wxString::Format( _( "Cannot convert \"%s\" to an integer" ),
90  aValue.GetData() ) );
91  return 0;
92  }
93 
94  return KiROUND( value * aScalar );
95 }
96 
97 
108 {
110  std::unique_ptr<FOOTPRINT> m_footprint;
111 
112 public:
113  GPCB_FPL_CACHE_ITEM( FOOTPRINT* aFootprint, const WX_FILENAME& aFileName );
114 
115  WX_FILENAME GetFileName() const { return m_filename; }
116  FOOTPRINT* GetFootprint() const { return m_footprint.get(); }
117 };
118 
119 
121  m_filename( aFileName ),
122  m_footprint( aFootprint )
123 {
124 }
125 
126 
127 typedef boost::ptr_map< std::string, GPCB_FPL_CACHE_ITEM > FOOTPRINT_MAP;
128 
129 
131 {
133  wxFileName m_lib_path;
135 
137  long long m_cache_timestamp;
139 
141  FOOTPRINT* parseFOOTPRINT( LINE_READER* aLineReader );
142 
153  bool testFlags( const wxString& aFlag, long aMask, const wxChar* aName );
154 
171  void parseParameters( wxArrayString& aParameterList, LINE_READER* aLineReader );
172 
173 public:
174  GPCB_FPL_CACHE( GPCB_PLUGIN* aOwner, const wxString& aLibraryPath );
175 
176  wxString GetPath() const { return m_lib_path.GetPath(); }
177  bool IsWritable() const { return m_lib_path.IsOk() && m_lib_path.IsDirWritable(); }
179 
180  // Most all functions in this class throw IO_ERROR exceptions. There are no
181  // error codes nor user interface calls from here, nor in any PLUGIN.
182  // Catch these exceptions higher up please.
183 
185 
186  void Load();
187 
188  void Remove( const wxString& aFootprintName );
189 
196  static long long GetTimestamp( const wxString& aLibPath );
197 
202  bool IsModified();
203 };
204 
205 
206 GPCB_FPL_CACHE::GPCB_FPL_CACHE( GPCB_PLUGIN* aOwner, const wxString& aLibraryPath )
207 {
208  m_owner = aOwner;
209  m_lib_path.SetPath( aLibraryPath );
210  m_cache_timestamp = 0;
211  m_cache_dirty = true;
212 }
213 
214 
216 {
217  m_cache_dirty = false;
218  m_cache_timestamp = 0;
219 
220  // Note: like our .pretty footprint libraries, the gpcb footprint libraries are folders,
221  // and the footprints are the .fp files inside this folder.
222 
223  wxDir dir( m_lib_path.GetPath() );
224 
225  if( !dir.IsOpened() )
226  {
227  THROW_IO_ERROR( wxString::Format( _( "footprint library path \"%s\" does not exist" ),
228  m_lib_path.GetPath().GetData() ) );
229  }
230 
231  wxString fullName;
232  wxString fileSpec = wxT( "*." ) + GedaPcbFootprintLibFileExtension;
233 
234  // wxFileName construction is egregiously slow. Construct it once and just swap out
235  // the filename thereafter.
236  WX_FILENAME fn( m_lib_path.GetPath(), wxT( "dummyName" ) );
237 
238  if( !dir.GetFirst( &fullName, fileSpec ) )
239  return;
240 
241  wxString cacheErrorMsg;
242 
243  do
244  {
245  fn.SetFullName( fullName );
246 
247  // Queue I/O errors so only files that fail to parse don't get loaded.
248  try
249  {
250  // reader now owns fp, will close on exception or return
251  FILE_LINE_READER reader( fn.GetFullPath() );
252  std::string name = TO_UTF8( fn.GetName() );
253  FOOTPRINT* footprint = parseFOOTPRINT( &reader );
254 
255  // The footprint name is the file name without the extension.
256  footprint->SetFPID( LIB_ID( wxEmptyString, fn.GetName() ) );
257  m_footprints.insert( name, new GPCB_FPL_CACHE_ITEM( footprint, fn ) );
258  }
259  catch( const IO_ERROR& ioe )
260  {
261  if( !cacheErrorMsg.IsEmpty() )
262  cacheErrorMsg += "\n\n";
263 
264  cacheErrorMsg += ioe.What();
265  }
266  } while( dir.GetNext( &fullName ) );
267 
268  if( !cacheErrorMsg.IsEmpty() )
269  THROW_IO_ERROR( cacheErrorMsg );
270 }
271 
272 
273 void GPCB_FPL_CACHE::Remove( const wxString& aFootprintName )
274 {
275  std::string footprintName = TO_UTF8( aFootprintName );
276 
277  FOOTPRINT_MAP::const_iterator it = m_footprints.find( footprintName );
278 
279  if( it == m_footprints.end() )
280  {
281  THROW_IO_ERROR( wxString::Format( _( "library \"%s\" has no footprint \"%s\" to delete" ),
282  m_lib_path.GetPath().GetData(),
283  aFootprintName.GetData() ) );
284  }
285 
286  // Remove the footprint from the cache and delete the footprint file from the library.
287  wxString fullPath = it->second->GetFileName().GetFullPath();
288  m_footprints.erase( footprintName );
289  wxRemoveFile( fullPath );
290 }
291 
292 
294 {
296 
297  return m_cache_dirty;
298 }
299 
300 
301 long long GPCB_FPL_CACHE::GetTimestamp( const wxString& aLibPath )
302 {
303  wxString fileSpec = wxT( "*." ) + GedaPcbFootprintLibFileExtension;
304 
305  return TimestampDir( aLibPath, fileSpec );
306 }
307 
308 
310 {
311  #define TEXT_DEFAULT_SIZE ( 40*IU_PER_MILS )
312  #define OLD_GPCB_UNIT_CONV IU_PER_MILS
313 
314  // Old version unit = 1 mil, so conv_unit is 10 or 0.1
315  #define NEW_GPCB_UNIT_CONV ( 0.01*IU_PER_MILS )
316 
317  int paramCnt;
318  double conv_unit = NEW_GPCB_UNIT_CONV; // GPCB unit = 0.01 mils and Pcbnew 0.1
319  wxPoint textPos;
320  wxString msg;
321  wxArrayString parameters;
322  std::unique_ptr<FOOTPRINT> footprint = std::make_unique<FOOTPRINT>( nullptr );
323 
324 
325  if( aLineReader->ReadLine() == NULL )
326  {
327  msg = aLineReader->GetSource() + ": empty file";
328  THROW_IO_ERROR( msg );
329  }
330 
331  parameters.Clear();
332  parseParameters( parameters, aLineReader );
333  paramCnt = parameters.GetCount();
334 
335  /* From the Geda PCB documentation, valid Element definitions:
336  * Element [SFlags "Desc" "Name" "Value" MX MY TX TY TDir TScale TSFlags]
337  * Element (NFlags "Desc" "Name" "Value" MX MY TX TY TDir TScale TNFlags)
338  * Element (NFlags "Desc" "Name" "Value" TX TY TDir TScale TNFlags)
339  * Element (NFlags "Desc" "Name" TX TY TDir TScale TNFlags)
340  * Element ("Desc" "Name" TX TY TDir TScale TNFlags)
341  */
342 
343  if( parameters[0].CmpNoCase( wxT( "Element" ) ) != 0 )
344  {
345  msg.Printf( _( "unknown token \"%s\"" ), parameters[0] );
346  THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader,
347  aLineReader->LineNumber(), 0 );
348  }
349 
350  if( paramCnt < 10 || paramCnt > 14 )
351  {
352  msg.Printf( _( "Element token contains %d parameters." ), paramCnt );
353  THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader,
354  aLineReader->LineNumber(), 0 );
355  }
356 
357  // Test symbol after "Element": if [ units = 0.01 mils, and if ( units = 1 mil
358  if( parameters[1] == wxT( "(" ) )
359  conv_unit = OLD_GPCB_UNIT_CONV;
360 
361  if( paramCnt > 10 )
362  {
363  footprint->SetDescription( parameters[3] );
364  footprint->SetReference( parameters[4] );
365  }
366  else
367  {
368  footprint->SetDescription( parameters[2] );
369  footprint->SetReference( parameters[3] );
370  }
371 
372  // Read value
373  if( paramCnt > 10 )
374  footprint->SetValue( parameters[5] );
375  // With gEDA/pcb, value is meaningful after instantiation, only, so it's
376  // often empty in bare footprints.
377  if( footprint->Value().GetText().IsEmpty() )
378  footprint->Value().SetText( wxT( "Val**" ) );
379 
380 
381  if( paramCnt == 14 )
382  {
383  textPos = wxPoint( parseInt( parameters[8], conv_unit ),
384  parseInt( parameters[9], conv_unit ) );
385  }
386  else
387  {
388  textPos = wxPoint( parseInt( parameters[6], conv_unit ),
389  parseInt( parameters[7], conv_unit ) );
390  }
391 
392  int orientation = parseInt( parameters[paramCnt-4], 1.0 );
393  footprint->Reference().SetTextAngle(( orientation % 2) ? 900 : 0 );
394 
395  // Calculate size: default height is 40 mils, width 30 mil.
396  // real size is: default * ibuf[idx+3] / 100 (size in gpcb is given in percent of default size
397  int thsize = parseInt( parameters[paramCnt-3], TEXT_DEFAULT_SIZE ) / 100;
398  thsize = std::max( (int)( 5 * IU_PER_MILS ), thsize ); // Ensure a minimal size = 5 mils
399  int twsize = thsize * 30 / 40;
400  int thickness = thsize / 8;
401 
402  // gEDA/pcb aligns top/left, not pcbnew's default, center/center.
403  // Compensate for this by shifting the insertion point instead of the
404  // alignment, because alignment isn't changeable in the GUI.
405  textPos.x = textPos.x + twsize * footprint->GetReference().Len() / 2;
406  textPos.y += thsize / 2;
407 
408  // gEDA/pcb draws a bit too low/left, while pcbnew draws a bit too
409  // high/right. Compensate for similar appearance.
410  textPos.x -= thsize / 10;
411  textPos.y += thsize / 2;
412 
413  footprint->Reference().SetTextPos( textPos );
414  footprint->Reference().SetPos0( textPos );
415  footprint->Reference().SetTextSize( wxSize( twsize, thsize ) );
416  footprint->Reference().SetTextThickness( thickness );
417 
418  // gEDA/pcb shows only one of value/reference/description at a time. Which
419  // one is selectable by a global menu setting. pcbnew needs reference as
420  // well as value visible, so place the value right below the reference.
421  footprint->Value().SetTextAngle( footprint->Reference().GetTextAngle() );
422  footprint->Value().SetTextSize( footprint->Reference().GetTextSize() );
423  footprint->Value().SetTextThickness( footprint->Reference().GetTextThickness() );
424  textPos.y += thsize * 13 / 10; // 130% line height
425  footprint->Value().SetTextPos( textPos );
426  footprint->Value().SetPos0( textPos );
427 
428  while( aLineReader->ReadLine() )
429  {
430  parameters.Clear();
431  parseParameters( parameters, aLineReader );
432 
433  if( parameters.IsEmpty() || parameters[0] == wxT( "(" ) )
434  continue;
435 
436  if( parameters[0] == wxT( ")" ) )
437  break;
438 
439  paramCnt = parameters.GetCount();
440 
441  // Test units value for a string line param (more than 3 parameters : ident [ xx ] )
442  if( paramCnt > 3 )
443  {
444  if( parameters[1] == wxT( "(" ) )
445  conv_unit = OLD_GPCB_UNIT_CONV;
446  else
447  conv_unit = NEW_GPCB_UNIT_CONV;
448  }
449 
450  wxLogTrace(
451  traceGedaPcbPlugin, wxT( "%s parameter count = %d." ), parameters[0], paramCnt );
452 
453  // Parse a line with format: ElementLine [X1 Y1 X2 Y2 Thickness]
454  if( parameters[0].CmpNoCase( wxT( "ElementLine" ) ) == 0 )
455  {
456  if( paramCnt != 8 )
457  {
458  msg.Printf( wxT( "ElementLine token contains %d parameters." ), paramCnt );
459  THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader,
460  aLineReader->LineNumber(), 0 );
461  }
462 
463  FP_SHAPE* shape = new FP_SHAPE( footprint.get() );
464  shape->SetLayer( F_SilkS );
465  shape->SetShape( S_SEGMENT );
466  shape->SetStart0( wxPoint( parseInt( parameters[2], conv_unit ),
467  parseInt( parameters[3], conv_unit ) ) );
468  shape->SetEnd0( wxPoint( parseInt( parameters[4], conv_unit ),
469  parseInt( parameters[5], conv_unit ) ) );
470  shape->SetWidth( parseInt( parameters[6], conv_unit ) );
471  shape->SetDrawCoord();
472  footprint->Add( shape );
473  continue;
474  }
475 
476  // Parse an arc with format: ElementArc [X Y Width Height StartAngle DeltaAngle Thickness]
477  if( parameters[0].CmpNoCase( wxT( "ElementArc" ) ) == 0 )
478  {
479  if( paramCnt != 10 )
480  {
481  msg.Printf( wxT( "ElementArc token contains %d parameters." ), paramCnt );
482  THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader,
483  aLineReader->LineNumber(), 0 );
484  }
485 
486  // Pcbnew does know ellipse so we must have Width = Height
487  FP_SHAPE* shape = new FP_SHAPE( footprint.get() );
488  shape->SetLayer( F_SilkS );
489  shape->SetShape( S_ARC );
490  footprint->Add( shape );
491 
492  // for and arc: ibuf[3] = ibuf[4]. Pcbnew does not know ellipses
493  int radius = ( parseInt( parameters[4], conv_unit ) +
494  parseInt( parameters[5], conv_unit ) ) / 2;
495 
496  wxPoint centre( parseInt( parameters[2], conv_unit ),
497  parseInt( parameters[3], conv_unit ) );
498 
499  shape->SetStart0( centre );
500 
501  // Pcbnew start angles are inverted and 180 degrees from Geda PCB angles.
502  double start_angle = parseInt( parameters[6], -10.0 ) + 1800.0;
503 
504  // Pcbnew delta angle direction is the opposite of Geda PCB delta angles.
505  double sweep_angle = parseInt( parameters[7], -10.0 );
506 
507  // Geda PCB does not support circles.
508  if( sweep_angle == -3600.0 )
509  shape->SetShape( S_CIRCLE );
510 
511  // Angle value is clockwise in gpcb and Pcbnew.
512  shape->SetAngle( sweep_angle );
513  shape->SetEnd0( wxPoint( radius, 0 ) );
514 
515  // Calculate start point coordinate of arc
516  wxPoint arcStart( shape->GetEnd0() );
517  RotatePoint( &arcStart, -start_angle );
518  shape->SetEnd0( centre + arcStart );
519  shape->SetWidth( parseInt( parameters[8], conv_unit ) );
520  shape->SetDrawCoord();
521  continue;
522  }
523 
524  // Parse a Pad with no hole with format:
525  // Pad [rX1 rY1 rX2 rY2 Thickness Clearance Mask "Name" "Number" SFlags]
526  // Pad (rX1 rY1 rX2 rY2 Thickness Clearance Mask "Name" "Number" NFlags)
527  // Pad (aX1 aY1 aX2 aY2 Thickness "Name" "Number" NFlags)
528  // Pad (aX1 aY1 aX2 aY2 Thickness "Name" NFlags)
529  if( parameters[0].CmpNoCase( wxT( "Pad" ) ) == 0 )
530  {
531  if( paramCnt < 10 || paramCnt > 13 )
532  {
533  msg.Printf( wxT( "Pad token contains %d parameters." ), paramCnt );
534  THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader,
535  aLineReader->LineNumber(), 0 );
536  }
537 
538  PAD* pad = new PAD( footprint.get() );
539 
540  static const LSET pad_front( 3, F_Cu, F_Mask, F_Paste );
541  static const LSET pad_back( 3, B_Cu, B_Mask, B_Paste );
542 
543  pad->SetShape( PAD_SHAPE_RECT );
545  pad->SetLayerSet( pad_front );
546 
547  if( testFlags( parameters[paramCnt-2], 0x0080, wxT( "onsolder" ) ) )
548  pad->SetLayerSet( pad_back );
549 
550  // Set the pad name:
551  // Pcbnew pad name is used for electrical connection calculations.
552  // Accordingly it should be mapped to gEDA's pin/pad number,
553  // which is used for the same purpose.
554  // gEDA also features a pin/pad "name", which is an arbitrary string
555  // and set to the pin name of the netlist on instantiation. Many gEDA
556  // bare footprints use identical strings for name and number, so this
557  // can be a bit confusing.
558  pad->SetName( parameters[paramCnt-3] );
559 
560  int x1 = parseInt( parameters[2], conv_unit );
561  int x2 = parseInt( parameters[4], conv_unit );
562  int y1 = parseInt( parameters[3], conv_unit );
563  int y2 = parseInt( parameters[5], conv_unit );
564  int width = parseInt( parameters[6], conv_unit );
565  wxPoint delta( x2 - x1, y2 - y1 );
566  double angle = atan2( (double)delta.y, (double)delta.x );
567 
568  // Get the pad clearance and the solder mask clearance.
569  if( paramCnt == 13 )
570  {
571  int clearance = parseInt( parameters[7], conv_unit );
572  // One of gEDA's oddities is that clearance between pad and polygon
573  // is given as the gap on both sides of the pad together, so for
574  // KiCad it has to halfed.
575  pad->SetLocalClearance( clearance / 2 );
576 
577  // In GEDA, the mask value is the size of the hole in this
578  // solder mask. In Pcbnew, it is a margin, therefore the distance
579  // between the copper and the mask
580  int maskMargin = parseInt( parameters[8], conv_unit );
581  maskMargin = ( maskMargin - width ) / 2;
582  pad->SetLocalSolderMaskMargin( maskMargin );
583  }
584 
585  // Negate angle (due to Y reversed axis) and convert it to internal units
586  angle = - RAD2DECIDEG( angle );
587  pad->SetOrientation( KiROUND( angle ) );
588 
589  wxPoint padPos( (x1 + x2) / 2, (y1 + y2) / 2 );
590 
591  pad->SetSize( wxSize( KiROUND( EuclideanNorm( delta ) ) + width,
592  width ) );
593 
594  // Set the relative position before adjusting the absolute position
595  pad->SetPos0( padPos );
596  padPos += footprint->GetPosition();
597  pad->SetPosition( padPos );
598 
599  if( !testFlags( parameters[paramCnt-2], 0x0100, wxT( "square" ) ) )
600  {
601  if( pad->GetSize().x == pad->GetSize().y )
602  pad->SetShape( PAD_SHAPE_CIRCLE );
603  else
604  pad->SetShape( PAD_SHAPE_OVAL );
605  }
606 
607  footprint->Add( pad );
608  continue;
609  }
610 
611  // Parse a Pin with through hole with format:
612  // Pin [rX rY Thickness Clearance Mask Drill "Name" "Number" SFlags]
613  // Pin (rX rY Thickness Clearance Mask Drill "Name" "Number" NFlags)
614  // Pin (aX aY Thickness Drill "Name" "Number" NFlags)
615  // Pin (aX aY Thickness Drill "Name" NFlags)
616  // Pin (aX aY Thickness "Name" NFlags)
617  if( parameters[0].CmpNoCase( wxT( "Pin" ) ) == 0 )
618  {
619  if( paramCnt < 8 || paramCnt > 12 )
620  {
621  msg.Printf( wxT( "Pin token contains %d parameters." ), paramCnt );
622  THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader,
623  aLineReader->LineNumber(), 0 );
624  }
625 
626  PAD* pad = new PAD( footprint.get() );
627 
628  pad->SetShape( PAD_SHAPE_CIRCLE );
629 
630  static const LSET pad_set = LSET::AllCuMask() | LSET( 3, F_SilkS, F_Mask, B_Mask );
631 
632  pad->SetLayerSet( pad_set );
633 
634  if( testFlags( parameters[paramCnt-2], 0x0100, wxT( "square" ) ) )
635  pad->SetShape( PAD_SHAPE_RECT );
636 
637  // Set the pad name:
638  // Pcbnew pad name is used for electrical connection calculations.
639  // Accordingly it should be mapped to gEDA's pin/pad number,
640  // which is used for the same purpose.
641  pad->SetName( parameters[paramCnt-3] );
642 
643  wxPoint padPos( parseInt( parameters[2], conv_unit ),
644  parseInt( parameters[3], conv_unit ) );
645 
646  int padSize = parseInt( parameters[4], conv_unit );
647 
648  pad->SetSize( wxSize( padSize, padSize ) );
649 
650  int drillSize = 0;
651 
652  // Get the pad clearance, solder mask clearance, and drill size.
653  if( paramCnt == 12 )
654  {
655  int clearance = parseInt( parameters[5], conv_unit );
656  // One of gEDA's oddities is that clearance between pad and polygon
657  // is given as the gap on both sides of the pad together, so for
658  // KiCad it has to halfed.
659  pad->SetLocalClearance( clearance / 2 );
660 
661  // In GEDA, the mask value is the size of the hole in this
662  // solder mask. In Pcbnew, it is a margin, therefore the distance
663  // between the copper and the mask
664  int maskMargin = parseInt( parameters[6], conv_unit );
665  maskMargin = ( maskMargin - padSize ) / 2;
666  pad->SetLocalSolderMaskMargin( maskMargin );
667 
668  drillSize = parseInt( parameters[7], conv_unit );
669  }
670  else
671  {
672  drillSize = parseInt( parameters[5], conv_unit );
673  }
674 
675  pad->SetDrillSize( wxSize( drillSize, drillSize ) );
676 
677  // Set the relative position before adjusting the absolute position
678  pad->SetPos0( padPos );
679  padPos += footprint->GetPosition();
680  pad->SetPosition( padPos );
681 
682  if( pad->GetShape() == PAD_SHAPE_CIRCLE && pad->GetSize().x != pad->GetSize().y )
683  pad->SetShape( PAD_SHAPE_OVAL );
684 
685  footprint->Add( pad );
686  continue;
687  }
688  }
689 
690  // Recalculate the bounding box
691  footprint->CalculateBoundingBox();
692  return footprint.release();
693 }
694 
695 
696 void GPCB_FPL_CACHE::parseParameters( wxArrayString& aParameterList, LINE_READER* aLineReader )
697 {
698  char key;
699  wxString tmp;
700  char* line = aLineReader->Line();
701 
702  // Last line already ready in main parser loop.
703  while( *line != 0 )
704  {
705  key = *line;
706  line++;
707 
708  switch( key )
709  {
710  case '[':
711  case '(':
712  if( !tmp.IsEmpty() )
713  {
714  aParameterList.Add( tmp );
715  tmp.Clear();
716  }
717 
718  tmp.Append( key );
719  aParameterList.Add( tmp );
720  tmp.Clear();
721 
722  // Opening delimiter "(" after Element statement. Any other occurrence is part
723  // of a keyword definition.
724  if( aParameterList.GetCount() == 1 )
725  {
726  wxLogTrace( traceGedaPcbPlugin, dump( aParameterList ) );
727  return;
728  }
729 
730  break;
731 
732  case ']':
733  case ')':
734  if( !tmp.IsEmpty() )
735  {
736  aParameterList.Add( tmp );
737  tmp.Clear();
738  }
739 
740  tmp.Append( key );
741  aParameterList.Add( tmp );
742  wxLogTrace( traceGedaPcbPlugin, dump( aParameterList ) );
743  return;
744 
745  case '\n':
746  case '\r':
747  // Element descriptions can span multiple lines.
748  line = aLineReader->ReadLine();
750 
751  case '\t':
752  case ' ':
753  if( !tmp.IsEmpty() )
754  {
755  aParameterList.Add( tmp );
756  tmp.Clear();
757  }
758 
759  break;
760 
761  case '"':
762  // Handle empty quotes.
763  if( *line == '"' )
764  {
765  line++;
766  tmp.Clear();
767  aParameterList.Add( wxEmptyString );
768  break;
769  }
770 
771  while( *line != 0 )
772  {
773  key = *line;
774  line++;
775 
776  if( key == '"' )
777  {
778  aParameterList.Add( tmp );
779  tmp.Clear();
780  break;
781  }
782  else
783  {
784  tmp.Append( key );
785  }
786  }
787 
788  break;
789 
790  case '#':
791  line = aLineReader->ReadLine();
792  break;
793 
794  default:
795  tmp.Append( key );
796  break;
797  }
798  }
799 }
800 
801 
802 bool GPCB_FPL_CACHE::testFlags( const wxString& aFlag, long aMask, const wxChar* aName )
803 {
804  wxString number;
805 
806  if( aFlag.StartsWith( wxT( "0x" ), &number ) || aFlag.StartsWith( wxT( "0X" ), &number ) )
807  {
808  long lflags;
809 
810  if( number.ToLong( &lflags, 16 ) && ( lflags & aMask ) )
811  return true;
812  }
813  else if( aFlag.Contains( aName ) )
814  {
815  return true;
816  }
817 
818  return false;
819 }
820 
821 
823  m_cache( 0 ),
824  m_ctl( 0 )
825 {
826  m_reader = NULL;
827  init( 0 );
828 }
829 
830 
831 GPCB_PLUGIN::GPCB_PLUGIN( int aControlFlags ) :
832  m_cache( 0 ),
833  m_ctl( aControlFlags )
834 {
835  m_reader = NULL;
836  init( 0 );
837 }
838 
839 
841 {
842  delete m_cache;
843 }
844 
845 
846 void GPCB_PLUGIN::init( const PROPERTIES* aProperties )
847 {
848  m_props = aProperties;
849 }
850 
851 
852 void GPCB_PLUGIN::validateCache( const wxString& aLibraryPath, bool checkModified )
853 {
854  if( !m_cache || ( checkModified && m_cache->IsModified() ) )
855  {
856  // a spectacular episode in memory management:
857  delete m_cache;
858  m_cache = new GPCB_FPL_CACHE( this, aLibraryPath );
859  m_cache->Load();
860  }
861 }
862 
863 
864 void GPCB_PLUGIN::FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aLibraryPath,
865  bool aBestEfforts, const PROPERTIES* aProperties )
866 {
867  LOCALE_IO toggle; // toggles on, then off, the C locale.
868  wxDir dir( aLibraryPath );
869  wxString errorMsg;
870 
871  if( !dir.IsOpened() )
872  {
873  if( aBestEfforts )
874  return;
875  else
876  {
877  THROW_IO_ERROR( wxString::Format( _( "footprint library path \"%s\" does not exist" ),
878  aLibraryPath ) );
879  }
880  }
881 
882  init( aProperties );
883 
884  try
885  {
886  validateCache( aLibraryPath );
887  }
888  catch( const IO_ERROR& ioe )
889  {
890  errorMsg = ioe.What();
891  }
892 
893  // Some of the files may have been parsed correctly so we want to add the valid files to
894  // the library.
895 
896  for( const auto& footprint : m_cache->GetFootprints() )
897  aFootprintNames.Add( FROM_UTF8( footprint.first.c_str() ) );
898 
899  if( !errorMsg.IsEmpty() && !aBestEfforts )
900  THROW_IO_ERROR( errorMsg );
901 }
902 
903 
904 const FOOTPRINT* GPCB_PLUGIN::getFootprint( const wxString& aLibraryPath,
905  const wxString& aFootprintName,
906  const PROPERTIES* aProperties,
907  bool checkModified )
908 {
909  LOCALE_IO toggle; // toggles on, then off, the C locale.
910 
911  init( aProperties );
912 
913  validateCache( aLibraryPath, checkModified );
914 
915  const FOOTPRINT_MAP& mods = m_cache->GetFootprints();
916 
917  FOOTPRINT_MAP::const_iterator it = mods.find( TO_UTF8( aFootprintName ) );
918 
919  if( it == mods.end() )
920  return NULL;
921 
922  return it->second->GetFootprint();
923 }
924 
925 
926 const FOOTPRINT* GPCB_PLUGIN::GetEnumeratedFootprint( const wxString& aLibraryPath,
927  const wxString& aFootprintName,
928  const PROPERTIES* aProperties )
929 {
930  return getFootprint( aLibraryPath, aFootprintName, aProperties, false );
931 }
932 
933 
934 FOOTPRINT* GPCB_PLUGIN::FootprintLoad( const wxString& aLibraryPath,
935  const wxString& aFootprintName,
936  const PROPERTIES* aProperties )
937 {
938  const FOOTPRINT* footprint = getFootprint( aLibraryPath, aFootprintName, aProperties, true );
939  return footprint ? (FOOTPRINT*) footprint->Duplicate() : nullptr;
940 }
941 
942 
943 void GPCB_PLUGIN::FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName,
944  const PROPERTIES* aProperties )
945 {
946  LOCALE_IO toggle; // toggles on, then off, the C locale.
947 
948  init( aProperties );
949 
950  validateCache( aLibraryPath );
951 
952  if( !m_cache->IsWritable() )
953  {
954  THROW_IO_ERROR( wxString::Format( _( "Library \"%s\" is read only" ),
955  aLibraryPath.GetData() ) );
956  }
957 
958  m_cache->Remove( aFootprintName );
959 }
960 
961 
962 bool GPCB_PLUGIN::FootprintLibDelete( const wxString& aLibraryPath, const PROPERTIES* aProperties )
963 {
964  wxFileName fn;
965  fn.SetPath( aLibraryPath );
966 
967  // Return if there is no library path to delete.
968  if( !fn.DirExists() )
969  return false;
970 
971  if( !fn.IsDirWritable() )
972  {
973  THROW_IO_ERROR( wxString::Format( _( "user does not have permission to delete directory \"%s\"" ),
974  aLibraryPath.GetData() ) );
975  }
976 
977  wxDir dir( aLibraryPath );
978 
979  if( dir.HasSubDirs() )
980  {
981  THROW_IO_ERROR( wxString::Format( _( "library directory \"%s\" has unexpected sub-directories" ),
982  aLibraryPath.GetData() ) );
983  }
984 
985  // All the footprint files must be deleted before the directory can be deleted.
986  if( dir.HasFiles() )
987  {
988  unsigned i;
989  wxFileName tmp;
990  wxArrayString files;
991 
992  wxDir::GetAllFiles( aLibraryPath, &files );
993 
994  for( i = 0; i < files.GetCount(); i++ )
995  {
996  tmp = files[i];
997 
998  if( tmp.GetExt() != KiCadFootprintFileExtension )
999  {
1000  THROW_IO_ERROR( wxString::Format( _( "unexpected file \"%s\" was found in library path \"%s\"" ),
1001  files[i].GetData(), aLibraryPath.GetData() ) );
1002  }
1003  }
1004 
1005  for( i = 0; i < files.GetCount(); i++ )
1006  {
1007  wxRemoveFile( files[i] );
1008  }
1009  }
1010 
1011  wxLogTrace( traceGedaPcbPlugin, wxT( "Removing footprint library '%s'" ),
1012  aLibraryPath.GetData() );
1013 
1014  // Some of the more elaborate wxRemoveFile() crap puts up its own wxLog dialog
1015  // we don't want that. we want bare metal portability with no UI here.
1016  if( !wxRmdir( aLibraryPath ) )
1017  {
1018  THROW_IO_ERROR( wxString::Format( _( "footprint library \"%s\" cannot be deleted" ),
1019  aLibraryPath.GetData() ) );
1020  }
1021 
1022  // For some reason removing a directory in Windows is not immediately updated. This delay
1023  // prevents an error when attempting to immediately recreate the same directory when over
1024  // writing an existing library.
1025 #ifdef __WINDOWS__
1026  wxMilliSleep( 250L );
1027 #endif
1028 
1029  if( m_cache && m_cache->GetPath() == aLibraryPath )
1030  {
1031  delete m_cache;
1032  m_cache = NULL;
1033  }
1034 
1035  return true;
1036 }
1037 
1038 
1039 long long GPCB_PLUGIN::GetLibraryTimestamp( const wxString& aLibraryPath ) const
1040 {
1041  return GPCB_FPL_CACHE::GetTimestamp( aLibraryPath );
1042 }
1043 
1044 
1045 bool GPCB_PLUGIN::IsFootprintLibWritable( const wxString& aLibraryPath )
1046 {
1047  LOCALE_IO toggle;
1048 
1049  init( NULL );
1050 
1051  validateCache( aLibraryPath );
1052 
1053  return m_cache->IsWritable();
1054 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:134
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:750
bool IsWritable() const
FOOTPRINT * GetFootprint() const
LINE_READER is an abstract class from which implementation specific LINE_READERs may be derived to re...
Definition: richio.h:82
char * Line() const
Function Line returns a pointer to the last line that was read in.
Definition: richio.h:140
void SetEnd0(const wxPoint &aPoint)
Definition: fp_shape.h:108
GPCB_PLUGIN * m_owner
Plugin object that owns the cache.
FOOTPRINT_MAP m_footprints
Map of footprint file name to FOOTPRINT*.
static wxString FROM_UTF8(const char *cstring)
function FROM_UTF8 converts a UTF8 encoded C string to a wxString for all wxWidgets build modes.
Definition: macros.h:109
GPCB_PLUGIN is a PLUGIN derivation for saving and loading Geda PCB files.
Definition: gpcb_plugin.h:47
virtual const wxString & GetSource() const
Function GetSource returns the name of the source of the lines in an abstract sense.
Definition: richio.h:131
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:40
#define OLD_GPCB_UNIT_CONV
static long long GetTimestamp(const wxString &aLibPath)
Function GetTimestamp Generate a timestamp representing all source files in the cache (including the ...
wxString GetPath() const
void SetLocalClearance(int aClearance)
Definition: pad.h:365
virtual void SetLayer(PCB_LAYER_ID aLayer)
Function SetLayer sets the layer this item is on.
Definition: board_item.h:206
const wxChar *const traceGedaPcbPlugin
Flag to enable GEDA PCB plugin debug output.
const std::string KiCadFootprintFileExtension
const FOOTPRINT * GetEnumeratedFootprint(const wxString &aLibraryPath, const wxString &aFootprintName, const PROPERTIES *aProperties=NULL) override
Function GetEnumeratedFootprint a version of FootprintLoad() for use after FootprintEnumerate() for m...
bool IsFootprintLibWritable(const wxString &aLibraryPath) override
Function IsFootprintLibWritable returns true iff the library at aLibraryPath is writable.
WX_FILENAME m_filename
The the full file name and path of the footprint to cache.
WX_FILENAME GetFileName() const
Smd pad, appears on the solder paste layer (default)
Definition: pad_shapes.h:81
void SetName(const wxString &aName)
Set the pad name (sometimes called pad number, although it can be an array reference like AA12).
Definition: pad.h:126
double RAD2DECIDEG(double rad)
Definition: trigo.h:222
usual segment : line with rounded ends
Definition: board_item.h:52
FOOTPRINT_MAP & GetFootprints()
GPCB_FPL_CACHE_ITEM is helper class for creating a footprint library cache.
void parseParameters(wxArrayString &aParameterList, LINE_READER *aLineReader)
Function parseParameters extracts parameters and tokens from aLineReader and adds them to aParameterL...
Arcs (with rounded ends)
Definition: board_item.h:54
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
PAD_SHAPE_T GetShape() const
Definition: pad.h:159
void SetSize(const wxSize &aSize)
Definition: pad.h:225
void Remove(const wxString &aFootprintName)
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:208
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
void SetFullName(const wxString &aFileNameAndExtension)
Definition: wx_filename.cpp:33
PROPERTIES is a name/value tuple with unique names and optional values.
Definition: properties.h:34
void init(const PROPERTIES *aProperties)
GPCB_FPL_CACHE_ITEM(FOOTPRINT *aFootprint, const WX_FILENAME &aFileName)
FOOTPRINT * FootprintLoad(const wxString &aLibraryPath, const wxString &aFootprintName, const PROPERTIES *aProperties=NULL) override
Function FootprintLoad loads a footprint having aFootprintName from the aLibraryPath containing a lib...
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:95
GPCB_FPL_CACHE * m_cache
Footprint library cache.
Definition: gpcb_plugin.h:97
void SetLocalSolderMaskMargin(int aMargin)
Definition: pad.h:361
FILE_LINE_READER is a LINE_READER that reads from an open file.
Definition: richio.h:181
LSET is a set of PCB_LAYER_IDs.
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:171
#define NULL
void SetPos0(const wxPoint &aPos)
Definition: pad.h:219
wxString dump(const wxArrayString &aArray)
Debug helper for printing wxArrayString contents.
void SetShape(PCB_SHAPE_TYPE_T aShape)
Definition: pcb_shape.h:128
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:29
const FOOTPRINT * getFootprint(const wxString &aLibraryPath, const wxString &aFootprintName, const PROPERTIES *aProperties, bool checkModified)
virtual unsigned LineNumber() const
Function Line Number returns the line number of the last line read from this LINE_READER.
Definition: richio.h:160
#define NEW_GPCB_UNIT_CONV
void SetDrillSize(const wxSize &aSize)
Definition: pad.h:235
void SetAngle(double aAngle, bool aUpdateEnd=true) override
Function SetAngle sets the angle for arcs, and normalizes it within the range 0 - 360 degrees.
Definition: fp_shape.cpp:151
const wxSize & GetSize() const
Definition: pad.h:226
Definition of file extensions used in Kicad.
FOOTPRINT * parseFOOTPRINT(LINE_READER *aLineReader)
const PROPERTIES * m_props
passed via Save() or Load(), no ownership, may be NULL.
Definition: gpcb_plugin.h:96
long long TimestampDir(const wxString &aDirPath, const wxString &aFilespec)
A copy of ConvertFileTimeToWx() because wxWidgets left it as a static function private to src/common/...
Definition: common.cpp:582
wxFileName m_lib_path
The path of the library.
wxLogTrace helper definitions.
BOARD_ITEM * Duplicate() const override
Function Duplicate creates a copy of a BOARD_ITEM.
Definition: footprint.cpp:1484
void SetShape(PAD_SHAPE_T aShape)
Set the new shape of this pad.
Definition: pad.h:150
void SetDrawCoord()
Set draw coordinates (absolute values ) from relative coordinates.
Definition: fp_shape.cpp:81
void Load()
Save not implemented for the Geda PCB footprint library format.
void SetStart0(const wxPoint &aPoint)
Definition: fp_shape.h:105
long long m_cache_timestamp
A hash of the timestamps for all the footprint files.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
void FootprintEnumerate(wxArrayString &aFootprintNames, const wxString &aLibraryPath, bool aBestEfforts, const PROPERTIES *aProperties=NULL) override
Return a list of footprint names contained within the library at aLibraryPath.
void SetLayerSet(LSET aLayers) override
Definition: pad.h:344
virtual char * ReadLine()=0
Function ReadLine reads a line of text into the buffer and increments the line number counter.
WX_FILENAME - A wrapper around a wxFileName which is much more performant with a subset of the API.
Definition: wx_filename.h:36
const char * name
Definition: DXF_plotter.cpp:59
#define TEXT_DEFAULT_SIZE
GPCB_FPL_CACHE(GPCB_PLUGIN *aOwner, const wxString &aLibraryPath)
#define _(s)
Definition: 3d_actions.cpp:33
void validateCache(const wxString &aLibraryPath, bool checkModified=true)
bool FootprintLibDelete(const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL) override
Function FootprintLibDelete deletes an existing footprint library and returns true,...
std::map< wxString, FOOTPRINT * > FOOTPRINT_MAP
Definition: eagle_parser.h:51
std::unique_ptr< FOOTPRINT > m_footprint
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
void SetPosition(const wxPoint &aPos) override
Definition: pad.h:161
long long GetLibraryTimestamp(const wxString &aLibraryPath) const override
Generate a timestamp representing all the files in the library (including the library directory).
const wxPoint & GetEnd0() const
Definition: fp_shape.h:109
void SetWidth(int aWidth)
Definition: pcb_shape.h:117
#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:68
const std::string GedaPcbFootprintLibFileExtension
ring
Definition: board_item.h:55
bool IsModified()
Function IsModified Return true if the cache is not up-to-date.
friend class GPCB_FPL_CACHE
Definition: gpcb_plugin.h:49
LINE_READER * m_reader
no ownership here.
Definition: gpcb_plugin.h:99
bool testFlags(const wxString &aFlag, long aMask, const wxChar *aName)
Function testFlags tests aFlag for aMask or aName.
void FootprintDelete(const wxString &aLibraryPath, const wxString &aFootprintName, const PROPERTIES *aProperties=NULL) override
Function FootprintDelete deletes aFootprintName from the library at aLibraryPath.
Definition: pad.h:59
bool m_cache_dirty
Stored separately because it's expensive to check m_cache_timestamp against all the files.
boost::ptr_map< std::string, GPCB_FPL_CACHE_ITEM > FOOTPRINT_MAP
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:76
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
static long parseInt(const wxString &aValue, double aScalar)
Definition: gpcb_plugin.cpp:50
void SetOrientation(double aAngle)
Function SetOrientation sets the rotation angle of the pad.
Definition: pcbnew/pad.cpp:531
void SetAttribute(PAD_ATTR_T aAttribute)
Definition: pcbnew/pad.cpp:512