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