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-2016 Wayne Stambaugh <stambaughw@verizon.net>
5  * Copyright (C) 1992-2016 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 
37 #include <class_board.h>
38 #include <class_module.h>
39 #include <class_pcb_text.h>
40 #include <class_drawsegment.h>
41 #include <class_edge_mod.h>
42 #include <gpcb_plugin.h>
43 
44 #include <wx/dir.h>
45 #include <wx/filename.h>
46 #include <wx/wfstream.h>
47 #include <boost/ptr_container/ptr_map.hpp>
48 #include <memory.h>
49 
54 static const wxString traceFootprintLibrary( wxT( "GedaPcbFootprintLib" ) );
55 
56 #ifdef DEBUG
57 static void inline traceParams( wxArrayString& aParams )
58 {
59  wxString tmp;
60 
61  for( unsigned i = 0; i < aParams.GetCount(); i++ )
62  {
63  if( aParams[i].IsEmpty() )
64  tmp << wxT( "\"\" " );
65  else
66  tmp << aParams[i] << wxT( " " );
67  }
68 
69  wxLogTrace( traceFootprintLibrary, tmp );
70 }
71 #endif
72 
73 static inline long parseInt( const wxString& aValue, double aScalar )
74 {
75  double value = LONG_MAX;
76 
77  /*
78  * In 2011 gEDA/pcb introduced values with units, like "10mm" or "200mil".
79  * Unit-less values are still centimils (100000 units per inch), like with
80  * the previous format.
81  *
82  * Distinction between the even older format (mils, 1000 units per inch)
83  * and the pre-2011 format is done in ::parseMODULE already; the
84  * distinction is by wether an object definition opens with '(' or '['.
85  * All values with explicite unit open with a '[' so there's no need to
86  * consider this distinction when parsing them.
87  *
88  * The solution here is to watch for a unit and, if present, convert the
89  * value to centimils. All unit-less values are read unaltered. This way
90  * the code below can contine to consider all read values to be in mils or
91  * centimils. It also matches the strategy gEDA/pcb uses for backwards
92  * compatibility with its own layouts.
93  *
94  * Fortunately gEDA/pcb allows only units 'mil' and 'mm' in files, see
95  * definition of ALLOW_READABLE in gEDA/pcb's pcb_printf.h. So we don't
96  * have to test for all 11 units gEDA/pcb allows in user dialogs.
97  */
98  if( aValue.EndsWith( wxT( "mm" ) ) )
99  {
100  aScalar *= 100000.0 / 25.4;
101  }
102  else if( aValue.EndsWith( wxT( "mil" ) ) )
103  {
104  aScalar *= 100.;
105  }
106 
107  // This conversion reports failure on strings as simple as "1000", still
108  // it returns the right result in &value. Thus, ignore the return value.
109  aValue.ToCDouble(&value);
110  if( value == LONG_MAX ) // conversion really failed
111  {
112  THROW_IO_ERROR( wxString::Format( _( "Cannot convert \"%s\" to an integer" ),
113  aValue.GetData() ) );
114  return 0;
115  }
116 
117  return KiROUND( value * aScalar );
118 }
119 
120 
121 // Tracing for token parameter arrays.
122 #ifdef DEBUG
123 #define TRACE_PARAMS( arr ) traceParams( arr );
124 #else
125 #define TRACE_PARAMS( arr ) // Expands to nothing on non-debug builds.
126 #endif
127 
128 
139 {
140  wxFileName m_file_name;
141  bool m_writable;
142  wxDateTime m_mod_time;
143  std::unique_ptr<MODULE> m_module;
144 
145 public:
146  GPCB_FPL_CACHE_ITEM( MODULE* aModule, const wxFileName& aFileName );
147 
148  wxString GetName() const { return m_file_name.GetDirs().Last(); }
149  wxFileName GetFileName() const { return m_file_name; }
150  bool IsModified() const;
151  MODULE* GetModule() const { return m_module.get(); }
152  void UpdateModificationTime() { m_mod_time = m_file_name.GetModificationTime(); }
153 };
154 
155 
156 GPCB_FPL_CACHE_ITEM::GPCB_FPL_CACHE_ITEM( MODULE* aModule, const wxFileName& aFileName ) :
157  m_module( aModule )
158 {
159  m_file_name = aFileName;
160  m_writable = true; // temporary init
161 
162  if( m_file_name.FileExists() )
163  m_mod_time = m_file_name.GetModificationTime();
164  else
165  m_mod_time.Now();
166 }
167 
168 
170 {
171  if( !m_file_name.FileExists() )
172  return false;
173 
174  return m_file_name.GetModificationTime() != m_mod_time;
175 }
176 
177 
178 typedef boost::ptr_map< std::string, GPCB_FPL_CACHE_ITEM > MODULE_MAP;
179 typedef MODULE_MAP::iterator MODULE_ITER;
180 typedef MODULE_MAP::const_iterator MODULE_CITER;
181 
182 
184 {
186  wxFileName m_lib_path;
187  wxDateTime m_mod_time;
188  MODULE_MAP m_modules;
189 
190  MODULE* parseMODULE( LINE_READER* aLineReader ) throw( IO_ERROR, PARSE_ERROR );
191 
202  bool testFlags( const wxString& aFlag, long aMask, const wxChar* aName );
203 
220  void parseParameters( wxArrayString& aParameterList, LINE_READER* aLineReader );
221 
222 public:
223  GPCB_FPL_CACHE( GPCB_PLUGIN* aOwner, const wxString& aLibraryPath );
224 
225  wxString GetPath() const { return m_lib_path.GetPath(); }
226  wxDateTime GetLastModificationTime() const { return m_mod_time; }
227  bool IsWritable() const { return m_lib_path.IsOk() && m_lib_path.IsDirWritable(); }
228  MODULE_MAP& GetModules() { return m_modules; }
229 
230  // Most all functions in this class throw IO_ERROR exceptions. There are no
231  // error codes nor user interface calls from here, nor in any PLUGIN.
232  // Catch these exceptions higher up please.
233 
235 
236  void Load();
237 
238  void Remove( const wxString& aFootprintName );
239 
240  wxDateTime GetLibModificationTime() const;
241 
253  bool IsModified( const wxString& aLibPath,
254  const wxString& aFootprintName = wxEmptyString ) const;
255 
268  bool IsPath( const wxString& aPath ) const;
269 };
270 
271 
272 GPCB_FPL_CACHE::GPCB_FPL_CACHE( GPCB_PLUGIN* aOwner, const wxString& aLibraryPath )
273 {
274  m_owner = aOwner;
275  m_lib_path.SetPath( aLibraryPath );
276 }
277 
278 
280 {
281  if( !m_lib_path.DirExists() )
282  return wxDateTime::Now();
283 
284  return m_lib_path.GetModificationTime();
285 }
286 
287 
289 {
290  wxDir dir( m_lib_path.GetPath() );
291 
292  if( !dir.IsOpened() )
293  {
294  THROW_IO_ERROR( wxString::Format( _( "footprint library path '%s' does not exist" ),
295  m_lib_path.GetPath().GetData() ) );
296  }
297 
298  wxString fpFileName;
299  wxString wildcard = wxT( "*." ) + GedaPcbFootprintLibFileExtension;
300 
301  if( !dir.GetFirst( &fpFileName, wildcard, wxDIR_FILES ) )
302  return;
303 
304  do
305  {
306  wxFileName fn( m_lib_path.GetPath(), fpFileName );
307 
308  // reader now owns fp, will close on exception or return
309  FILE_LINE_READER reader( fn.GetFullPath() );
310  std::string name = TO_UTF8( fn.GetName() );
311  MODULE* footprint = parseMODULE( &reader );
312 
313  // The footprint name is the file name without the extension.
314  footprint->SetFPID( LIB_ID( fn.GetName() ) );
315  m_modules.insert( name, new GPCB_FPL_CACHE_ITEM( footprint, fn.GetName() ) );
316 
317  } while( dir.GetNext( &fpFileName ) );
318 
319  // Remember the file modification time of library file when the
320  // cache snapshot was made, so that in a networked environment we will
321  // reload the cache as needed.
322  m_mod_time = GetLibModificationTime();
323 }
324 
325 
326 void GPCB_FPL_CACHE::Remove( const wxString& aFootprintName )
327 {
328  std::string footprintName = TO_UTF8( aFootprintName );
329 
330  MODULE_CITER it = m_modules.find( footprintName );
331 
332  if( it == m_modules.end() )
333  {
334  THROW_IO_ERROR( wxString::Format( _( "library <%s> has no footprint '%s' to delete" ),
335  m_lib_path.GetPath().GetData(),
336  aFootprintName.GetData() ) );
337  }
338 
339  // Remove the module from the cache and delete the module file from the library.
340  wxString fullPath = it->second->GetFileName().GetFullPath();
341  m_modules.erase( footprintName );
342  wxRemoveFile( fullPath );
343 }
344 
345 
346 bool GPCB_FPL_CACHE::IsPath( const wxString& aPath ) const
347 {
348  // Converts path separators to native path separators
349  wxFileName newPath;
350  newPath.AssignDir( aPath );
351 
352  return m_lib_path == newPath;
353 }
354 
355 
356 bool GPCB_FPL_CACHE::IsModified( const wxString& aLibPath, const wxString& aFootprintName ) const
357 {
358  // The library is modified if the library path got deleted or changed.
359  if( !m_lib_path.DirExists() || !IsPath( aLibPath ) )
360  return true;
361 
362  // If no footprint was specified, check every file modification time against the time
363  // it was loaded.
364  if( aFootprintName.IsEmpty() )
365  {
366  for( MODULE_CITER it = m_modules.begin(); it != m_modules.end(); ++it )
367  {
368  wxFileName fn = m_lib_path;
369 
370  fn.SetName( it->second->GetFileName().GetName() );
371  fn.SetExt( KiCadFootprintFileExtension );
372 
373  if( !fn.FileExists() )
374  {
375  wxLogTrace( traceFootprintLibrary,
376  wxT( "Footprint cache file '%s' does not exist." ),
377  fn.GetFullPath().GetData() );
378  return true;
379  }
380 
381  if( it->second->IsModified() )
382  {
383  wxLogTrace( traceFootprintLibrary,
384  wxT( "Footprint cache file '%s' has been modified." ),
385  fn.GetFullPath().GetData() );
386  return true;
387  }
388  }
389  }
390  else
391  {
392  MODULE_CITER it = m_modules.find( TO_UTF8( aFootprintName ) );
393 
394  if( it == m_modules.end() || it->second->IsModified() )
395  return true;
396  }
397 
398  return false;
399 }
400 
401 
403 {
404  #define TEXT_DEFAULT_SIZE ( 40*IU_PER_MILS )
405  #define OLD_GPCB_UNIT_CONV IU_PER_MILS
406 
407  // Old version unit = 1 mil, so conv_unit is 10 or 0.1
408  #define NEW_GPCB_UNIT_CONV ( 0.01*IU_PER_MILS )
409 
410  int paramCnt;
411  double conv_unit = NEW_GPCB_UNIT_CONV; // GPCB unit = 0.01 mils and Pcbnew 0.1
412  wxPoint textPos;
413  wxString msg;
414  wxArrayString parameters;
415  std::unique_ptr<MODULE> module( new MODULE( NULL ) );
416 
417 
418  if( aLineReader->ReadLine() == NULL )
419  THROW_IO_ERROR( "unexpected end of file" );
420 
421  parameters.Clear();
422  parseParameters( parameters, aLineReader );
423  paramCnt = parameters.GetCount();
424 
425  /* From the Geda PCB documentation, valid Element definitions:
426  * Element [SFlags "Desc" "Name" "Value" MX MY TX TY TDir TScale TSFlags]
427  * Element (NFlags "Desc" "Name" "Value" MX MY TX TY TDir TScale TNFlags)
428  * Element (NFlags "Desc" "Name" "Value" TX TY TDir TScale TNFlags)
429  * Element (NFlags "Desc" "Name" TX TY TDir TScale TNFlags)
430  * Element ("Desc" "Name" TX TY TDir TScale TNFlags)
431  */
432 
433  if( parameters[0].CmpNoCase( wxT( "Element" ) ) != 0 )
434  {
435  msg.Printf( _( "unknown token \"%s\"" ), GetChars( parameters[0] ) );
436  THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader,
437  aLineReader->LineNumber(), 0 );
438  }
439 
440  if( paramCnt < 10 || paramCnt > 14 )
441  {
442  msg.Printf( _( "Element token contains %d parameters." ), paramCnt );
443  THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader,
444  aLineReader->LineNumber(), 0 );
445  }
446 
447  // Test symbol after "Element": if [ units = 0.01 mils, and if ( units = 1 mil
448  if( parameters[1] == wxT( "(" ) )
449  conv_unit = OLD_GPCB_UNIT_CONV;
450 
451  if( paramCnt > 10 )
452  {
453  module->SetDescription( parameters[3] );
454  module->SetReference( parameters[4] );
455  }
456  else
457  {
458  module->SetDescription( parameters[2] );
459  module->SetReference( parameters[3] );
460  }
461 
462  // Read value
463  if( paramCnt > 10 )
464  module->SetValue( parameters[5] );
465  // With gEDA/pcb, value is meaningful after instantiation, only, so it's
466  // often empty in bare footprints.
467  if( module->Value().GetText().IsEmpty() )
468  module->Value().SetText( wxT( "Val**" ) );
469 
470 
471  if( paramCnt == 14 )
472  {
473  textPos = wxPoint( parseInt( parameters[8], conv_unit ),
474  parseInt( parameters[9], conv_unit ) );
475  }
476  else
477  {
478  textPos = wxPoint( parseInt( parameters[6], conv_unit ),
479  parseInt( parameters[7], conv_unit ) );
480  }
481 
482  int orientation = parseInt( parameters[paramCnt-4], 1.0 );
483  module->Reference().SetTextAngle( (orientation % 2) ? 900 : 0 );
484 
485  // Calculate size: default height is 40 mils, width 30 mil.
486  // real size is: default * ibuf[idx+3] / 100 (size in gpcb is given in percent of default size
487  int thsize = parseInt( parameters[paramCnt-3], TEXT_DEFAULT_SIZE ) / 100;
488  thsize = std::max( (int)( 5 * IU_PER_MILS ), thsize ); // Ensure a minimal size = 5 mils
489  int twsize = thsize * 30 / 40;
490  int thickness = thsize / 8;
491 
492  // gEDA/pcb aligns top/left, not pcbnew's default, center/center.
493  // Compensate for this by shifting the insertion point instead of the
494  // aligment, because alignment isn't changeable in the GUI.
495  textPos.x = textPos.x + twsize * module->GetReference().Len() / 2;
496  textPos.y += thsize / 2;
497 
498  // gEDA/pcb draws a bit too low/left, while pcbnew draws a bit too
499  // high/right. Compensate for similar appearance.
500  textPos.x -= thsize / 10;
501  textPos.y += thsize / 2;
502 
503  module->Reference().SetTextPos( textPos );
504  module->Reference().SetPos0( textPos );
505  module->Reference().SetTextSize( wxSize( twsize, thsize ) );
506  module->Reference().SetThickness( thickness );
507 
508  // gEDA/pcb shows only one of value/reference/description at a time. Which
509  // one is selectable by a global menu setting. pcbnew needs reference as
510  // well as value visible, so place the value right below the reference.
511  module->Value().SetTextAngle( module->Reference().GetTextAngle() );
512  module->Value().SetTextSize( module->Reference().GetTextSize() );
513  module->Value().SetThickness( module->Reference().GetThickness() );
514  textPos.y += thsize * 13 / 10; // 130% line height
515  module->Value().SetTextPos( textPos );
516  module->Value().SetPos0( textPos );
517 
518  while( aLineReader->ReadLine() )
519  {
520  parameters.Clear();
521  parseParameters( parameters, aLineReader );
522 
523  if( parameters.IsEmpty() || parameters[0] == wxT( "(" ) )
524  continue;
525 
526  if( parameters[0] == wxT( ")" ) )
527  break;
528 
529  paramCnt = parameters.GetCount();
530 
531  // Test units value for a string line param (more than 3 parameters : ident [ xx ] )
532  if( paramCnt > 3 )
533  {
534  if( parameters[1] == wxT( "(" ) )
535  conv_unit = OLD_GPCB_UNIT_CONV;
536  else
537  conv_unit = NEW_GPCB_UNIT_CONV;
538  }
539 
540  wxLogTrace( traceFootprintLibrary, wxT( "%s parameter count = %d." ),
541  GetChars( parameters[0] ), paramCnt );
542 
543  // Parse a line with format: ElementLine [X1 Y1 X2 Y2 Thickness]
544  if( parameters[0].CmpNoCase( wxT( "ElementLine" ) ) == 0 )
545  {
546  if( paramCnt != 8 )
547  {
548  msg.Printf( wxT( "ElementLine token contains %d parameters." ), paramCnt );
549  THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader,
550  aLineReader->LineNumber(), 0 );
551  }
552 
553  EDGE_MODULE* drawSeg = new EDGE_MODULE( module.get() );
554  drawSeg->SetLayer( F_SilkS );
555  drawSeg->SetShape( S_SEGMENT );
556  drawSeg->SetStart0( wxPoint( parseInt( parameters[2], conv_unit ),
557  parseInt( parameters[3], conv_unit ) ) );
558  drawSeg->SetEnd0( wxPoint( parseInt( parameters[4], conv_unit ),
559  parseInt( parameters[5], conv_unit ) ) );
560  drawSeg->SetWidth( parseInt( parameters[6], conv_unit ) );
561  drawSeg->SetDrawCoord();
562  module->GraphicalItems().PushBack( drawSeg );
563  continue;
564  }
565 
566  // Parse an arc with format: ElementArc [X Y Width Height StartAngle DeltaAngle Thickness]
567  if( parameters[0].CmpNoCase( wxT( "ElementArc" ) ) == 0 )
568  {
569  if( paramCnt != 10 )
570  {
571  msg.Printf( wxT( "ElementArc token contains %d parameters." ), paramCnt );
572  THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader,
573  aLineReader->LineNumber(), 0 );
574  }
575 
576  // Pcbnew does know ellipse so we must have Width = Height
577  EDGE_MODULE* drawSeg = new EDGE_MODULE( module.get() );
578  drawSeg->SetLayer( F_SilkS );
579  drawSeg->SetShape( S_ARC );
580  module->GraphicalItems().PushBack( drawSeg );
581 
582  // for and arc: ibuf[3] = ibuf[4]. Pcbnew does not know ellipses
583  int radius = ( parseInt( parameters[4], conv_unit ) +
584  parseInt( parameters[5], conv_unit ) ) / 2;
585 
586  wxPoint centre( parseInt( parameters[2], conv_unit ),
587  parseInt( parameters[3], conv_unit ) );
588 
589  drawSeg->SetStart0( centre );
590 
591  // Pcbnew start angles are inverted and 180 degrees from Geda PCB angles.
592  double start_angle = parseInt( parameters[6], -10.0 ) + 1800.0;
593 
594  // Pcbnew delta angle direction is the opposite of Geda PCB delta angles.
595  double sweep_angle = parseInt( parameters[7], -10.0 );
596 
597  // Geda PCB does not support circles.
598  if( sweep_angle == -3600.0 )
599  drawSeg->SetShape( S_CIRCLE );
600 
601  // Angle value is clockwise in gpcb and Pcbnew.
602  drawSeg->SetAngle( sweep_angle );
603  drawSeg->SetEnd0( wxPoint( radius, 0 ) );
604 
605  // Calculate start point coordinate of arc
606  wxPoint arcStart( drawSeg->GetEnd0() );
607  RotatePoint( &arcStart, -start_angle );
608  drawSeg->SetEnd0( centre + arcStart );
609  drawSeg->SetWidth( parseInt( parameters[8], conv_unit ) );
610  drawSeg->SetDrawCoord();
611  continue;
612  }
613 
614  // Parse a Pad with no hole with format:
615  // Pad [rX1 rY1 rX2 rY2 Thickness Clearance Mask "Name" "Number" SFlags]
616  // Pad (rX1 rY1 rX2 rY2 Thickness Clearance Mask "Name" "Number" NFlags)
617  // Pad (aX1 aY1 aX2 aY2 Thickness "Name" "Number" NFlags)
618  // Pad (aX1 aY1 aX2 aY2 Thickness "Name" NFlags)
619  if( parameters[0].CmpNoCase( wxT( "Pad" ) ) == 0 )
620  {
621  if( paramCnt < 10 || paramCnt > 13 )
622  {
623  msg.Printf( wxT( "Pad token contains %d parameters." ), paramCnt );
624  THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader,
625  aLineReader->LineNumber(), 0 );
626  }
627 
628  D_PAD* pad = new D_PAD( module.get() );
629 
630  static const LSET pad_front( 3, F_Cu, F_Mask, F_Paste );
631  static const LSET pad_back( 3, B_Cu, B_Mask, B_Paste );
632 
633  pad->SetShape( PAD_SHAPE_RECT );
635  pad->SetLayerSet( pad_front );
636 
637  if( testFlags( parameters[paramCnt-2], 0x0080, wxT( "onsolder" ) ) )
638  pad->SetLayerSet( pad_back );
639 
640  // Set the pad name:
641  // Pcbnew pad name is used for electrical connection calculations.
642  // Accordingly it should be mapped to gEDA's pin/pad number,
643  // which is used for the same purpose.
644  // gEDA also features a pin/pad "name", which is an arbitrary string
645  // and set to the pin name of the netlist on instantiation. Many gEDA
646  // bare footprints use identical strings for name and number, so this
647  // can be a bit confusing.
648  pad->SetPadName( parameters[paramCnt-3] );
649 
650  int x1 = parseInt( parameters[2], conv_unit );
651  int x2 = parseInt( parameters[4], conv_unit );
652  int y1 = parseInt( parameters[3], conv_unit );
653  int y2 = parseInt( parameters[5], conv_unit );
654  int width = parseInt( parameters[6], conv_unit );
655  wxPoint delta( x2 - x1, y2 - y1 );
656  double angle = atan2( (double)delta.y, (double)delta.x );
657 
658  // Get the pad clearance and the solder mask clearance.
659  if( paramCnt == 13 )
660  {
661  int clearance = parseInt( parameters[7], conv_unit );
662  // One of gEDA's oddities is that clearance between pad and polygon
663  // is given as the gap on both sides of the pad together, so for
664  // KiCad it has to halfed.
665  pad->SetLocalClearance( clearance / 2 );
666 
667  // In GEDA, the mask value is the size of the hole in this
668  // solder mask. In Pcbnew, it is a margin, therefore the distance
669  // between the copper and the mask
670  int maskMargin = parseInt( parameters[8], conv_unit );
671  maskMargin = ( maskMargin - width ) / 2;
672  pad->SetLocalSolderMaskMargin( maskMargin );
673  }
674 
675  // Negate angle (due to Y reversed axis) and convert it to internal units
676  angle = - RAD2DECIDEG( angle );
677  pad->SetOrientation( KiROUND( angle ) );
678 
679  wxPoint padPos( (x1 + x2) / 2, (y1 + y2) / 2 );
680 
681  pad->SetSize( wxSize( KiROUND( EuclideanNorm( delta ) ) + width,
682  width ) );
683 
684  padPos += module->GetPosition();
685  pad->SetPos0( padPos );
686  pad->SetPosition( padPos );
687 
688  if( !testFlags( parameters[paramCnt-2], 0x0100, wxT( "square" ) ) )
689  {
690  if( pad->GetSize().x == pad->GetSize().y )
691  pad->SetShape( PAD_SHAPE_CIRCLE );
692  else
693  pad->SetShape( PAD_SHAPE_OVAL );
694  }
695 
696  module->Add( pad );
697  continue;
698  }
699 
700  // Parse a Pin with through hole with format:
701  // Pin [rX rY Thickness Clearance Mask Drill "Name" "Number" SFlags]
702  // Pin (rX rY Thickness Clearance Mask Drill "Name" "Number" NFlags)
703  // Pin (aX aY Thickness Drill "Name" "Number" NFlags)
704  // Pin (aX aY Thickness Drill "Name" NFlags)
705  // Pin (aX aY Thickness "Name" NFlags)
706  if( parameters[0].CmpNoCase( wxT( "Pin" ) ) == 0 )
707  {
708  if( paramCnt < 8 || paramCnt > 12 )
709  {
710  msg.Printf( wxT( "Pin token contains %d parameters." ), paramCnt );
711  THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader,
712  aLineReader->LineNumber(), 0 );
713  }
714 
715  D_PAD* pad = new D_PAD( module.get() );
716 
717  pad->SetShape( PAD_SHAPE_CIRCLE );
718 
719  static const LSET pad_set = LSET::AllCuMask() | LSET( 3, F_SilkS, F_Mask, B_Mask );
720 
721  pad->SetLayerSet( pad_set );
722 
723  if( testFlags( parameters[paramCnt-2], 0x0100, wxT( "square" ) ) )
724  pad->SetShape( PAD_SHAPE_RECT );
725 
726  // Set the pad name:
727  // Pcbnew pad name is used for electrical connection calculations.
728  // Accordingly it should be mapped to gEDA's pin/pad number,
729  // which is used for the same purpose.
730  pad->SetPadName( parameters[paramCnt-3] );
731 
732  wxPoint padPos( parseInt( parameters[2], conv_unit ),
733  parseInt( parameters[3], conv_unit ) );
734 
735  int padSize = parseInt( parameters[4], conv_unit );
736 
737  pad->SetSize( wxSize( padSize, padSize ) );
738 
739  int drillSize = 0;
740 
741  // Get the pad clearance, solder mask clearance, and drill size.
742  if( paramCnt == 12 )
743  {
744  int clearance = parseInt( parameters[5], conv_unit );
745  // One of gEDA's oddities is that clearance between pad and polygon
746  // is given as the gap on both sides of the pad together, so for
747  // KiCad it has to halfed.
748  pad->SetLocalClearance( clearance / 2 );
749 
750  // In GEDA, the mask value is the size of the hole in this
751  // solder mask. In Pcbnew, it is a margin, therefore the distance
752  // between the copper and the mask
753  int maskMargin = parseInt( parameters[6], conv_unit );
754  maskMargin = ( maskMargin - padSize ) / 2;
755  pad->SetLocalSolderMaskMargin( maskMargin );
756 
757  drillSize = parseInt( parameters[7], conv_unit );
758  }
759  else
760  {
761  drillSize = parseInt( parameters[5], conv_unit );
762  }
763 
764  pad->SetDrillSize( wxSize( drillSize, drillSize ) );
765  padPos += module->GetPosition();
766  pad->SetPos0( padPos );
767  pad->SetPosition( padPos );
768 
769  if( pad->GetShape() == PAD_SHAPE_CIRCLE && pad->GetSize().x != pad->GetSize().y )
770  pad->SetShape( PAD_SHAPE_OVAL );
771 
772  module->Add( pad );
773  continue;
774  }
775  }
776 
777  // Recalculate the bounding box
778  module->CalculateBoundingBox();
779  return module.release();
780 }
781 
782 
783 void GPCB_FPL_CACHE::parseParameters( wxArrayString& aParameterList, LINE_READER* aLineReader )
784 {
785  char key;
786  wxString tmp;
787  char* line = aLineReader->Line();
788 
789  // Last line already ready in main parser loop.
790  while( *line != 0 )
791  {
792  key = *line;
793  line++;
794 
795  switch( key )
796  {
797  case '[':
798  case '(':
799  if( !tmp.IsEmpty() )
800  {
801  aParameterList.Add( tmp );
802  tmp.Clear();
803  }
804 
805  tmp.Append( key );
806  aParameterList.Add( tmp );
807  tmp.Clear();
808 
809  // Opening delimiter "(" after Element statement. Any other occurrence is part
810  // of a keyword definition.
811  if( aParameterList.GetCount() == 1 )
812  {
813  TRACE_PARAMS( aParameterList );
814  return;
815  }
816 
817  break;
818 
819  case ']':
820  case ')':
821  if( !tmp.IsEmpty() )
822  {
823  aParameterList.Add( tmp );
824  tmp.Clear();
825  }
826 
827  tmp.Append( key );
828  aParameterList.Add( tmp );
829  TRACE_PARAMS( aParameterList );
830  return;
831 
832  case '\n':
833  case '\r':
834  // Element descriptions can span multiple lines.
835  line = aLineReader->ReadLine();
836 
837  // Fall through is intentional.
838 
839  case '\t':
840  case ' ':
841  if( !tmp.IsEmpty() )
842  {
843  aParameterList.Add( tmp );
844  tmp.Clear();
845  }
846 
847  break;
848 
849  case '"':
850  // Handle empty quotes.
851  if( *line == '"' )
852  {
853  line++;
854  tmp.Clear();
855  aParameterList.Add( wxEmptyString );
856  break;
857  }
858 
859  while( *line != 0 )
860  {
861  key = *line;
862  line++;
863 
864  if( key == '"' )
865  {
866  aParameterList.Add( tmp );
867  tmp.Clear();
868  break;
869  }
870  else
871  {
872  tmp.Append( key );
873  }
874  }
875 
876  break;
877 
878  case '#':
879  line = aLineReader->ReadLine();
880  break;
881 
882  default:
883  tmp.Append( key );
884  break;
885  }
886  }
887 }
888 
889 
890 bool GPCB_FPL_CACHE::testFlags( const wxString& aFlag, long aMask, const wxChar* aName )
891 {
892  wxString number;
893 
894  if( aFlag.StartsWith( wxT( "0x" ), &number ) || aFlag.StartsWith( wxT( "0X" ), &number ) )
895  {
896  long lflags;
897 
898  if( number.ToLong( &lflags, 16 ) && ( lflags & aMask ) )
899  return true;
900  }
901  else if( aFlag.Contains( aName ) )
902  {
903  return true;
904  }
905 
906  return false;
907 }
908 
909 
911  m_cache( 0 ),
912  m_ctl( 0 )
913 {
914  m_reader = NULL;
915  init( 0 );
916 }
917 
918 
919 GPCB_PLUGIN::GPCB_PLUGIN( int aControlFlags ) :
920  m_cache( 0 ),
921  m_ctl( aControlFlags )
922 {
923  m_reader = NULL;
924  init( 0 );
925 }
926 
927 
929 {
930  delete m_cache;
931 }
932 
933 
934 void GPCB_PLUGIN::init( const PROPERTIES* aProperties )
935 {
936  m_props = aProperties;
937 }
938 
939 
940 void GPCB_PLUGIN::cacheLib( const wxString& aLibraryPath, const wxString& aFootprintName )
941 {
942  if( !m_cache || m_cache->IsModified( aLibraryPath, aFootprintName ) )
943  {
944  // a spectacular episode in memory management:
945  delete m_cache;
946  m_cache = new GPCB_FPL_CACHE( this, aLibraryPath );
947  m_cache->Load();
948  }
949 }
950 
951 
952 wxArrayString GPCB_PLUGIN::FootprintEnumerate( const wxString& aLibraryPath,
953  const PROPERTIES* aProperties )
954 {
955  LOCALE_IO toggle; // toggles on, then off, the C locale.
956  wxArrayString ret;
957  wxDir dir( aLibraryPath );
958 
959  if( !dir.IsOpened() )
960  {
961  THROW_IO_ERROR( wxString::Format( _( "footprint library path '%s' does not exist" ),
962  GetChars( aLibraryPath ) ) );
963  }
964 
965  init( aProperties );
966 
967 #if 1 // Set to 0 to only read directory contents, not load cache.
968  cacheLib( aLibraryPath );
969 
970  const MODULE_MAP& mods = m_cache->GetModules();
971 
972 
973  for( MODULE_CITER it = mods.begin(); it != mods.end(); ++it )
974  {
975  ret.Add( FROM_UTF8( it->first.c_str() ) );
976  }
977 #else
978  wxString fpFileName;
979  wxString wildcard = wxT( "*." ) + GedaPcbFootprintLibFileExtension;
980 
981  if( dir.GetFirst( &fpFileName, wildcard, wxDIR_FILES ) )
982  {
983  do
984  {
985  wxFileName fn( aLibraryPath, fpFileName );
986  ret.Add( fn.GetName() );
987  } while( dir.GetNext( &fpFileName ) );
988  }
989 #endif
990 
991  return ret;
992 }
993 
994 
995 MODULE* GPCB_PLUGIN::FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName,
996  const PROPERTIES* aProperties )
997 {
998  LOCALE_IO toggle; // toggles on, then off, the C locale.
999 
1000  init( aProperties );
1001 
1002  cacheLib( aLibraryPath, aFootprintName );
1003 
1004  const MODULE_MAP& mods = m_cache->GetModules();
1005 
1006  MODULE_CITER it = mods.find( TO_UTF8( aFootprintName ) );
1007 
1008  if( it == mods.end() )
1009  {
1010  return NULL;
1011  }
1012 
1013  // copy constructor to clone the already loaded MODULE
1014  return new MODULE( *it->second->GetModule() );
1015 }
1016 
1017 
1018 void GPCB_PLUGIN::FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName,
1019  const PROPERTIES* aProperties )
1020 {
1021  LOCALE_IO toggle; // toggles on, then off, the C locale.
1022 
1023  init( aProperties );
1024 
1025  cacheLib( aLibraryPath );
1026 
1027  if( !m_cache->IsWritable() )
1028  {
1029  THROW_IO_ERROR( wxString::Format( _( "Library '%s' is read only" ),
1030  aLibraryPath.GetData() ) );
1031  }
1032 
1033  m_cache->Remove( aFootprintName );
1034 }
1035 
1036 
1037 bool GPCB_PLUGIN::FootprintLibDelete( const wxString& aLibraryPath, const PROPERTIES* aProperties )
1038 {
1039  wxFileName fn;
1040  fn.SetPath( aLibraryPath );
1041 
1042  // Return if there is no library path to delete.
1043  if( !fn.DirExists() )
1044  return false;
1045 
1046  if( !fn.IsDirWritable() )
1047  {
1048  THROW_IO_ERROR( wxString::Format( _( "user does not have permission to delete directory '%s'" ),
1049  aLibraryPath.GetData() ) );
1050  }
1051 
1052  wxDir dir( aLibraryPath );
1053 
1054  if( dir.HasSubDirs() )
1055  {
1056  THROW_IO_ERROR( wxString::Format( _( "library directory '%s' has unexpected sub-directories" ),
1057  aLibraryPath.GetData() ) );
1058  }
1059 
1060  // All the footprint files must be deleted before the directory can be deleted.
1061  if( dir.HasFiles() )
1062  {
1063  unsigned i;
1064  wxFileName tmp;
1065  wxArrayString files;
1066 
1067  wxDir::GetAllFiles( aLibraryPath, &files );
1068 
1069  for( i = 0; i < files.GetCount(); i++ )
1070  {
1071  tmp = files[i];
1072 
1073  if( tmp.GetExt() != KiCadFootprintFileExtension )
1074  {
1075  THROW_IO_ERROR( wxString::Format( _( "unexpected file '%s' was found in library path '%s'" ),
1076  files[i].GetData(), aLibraryPath.GetData() ) );
1077  }
1078  }
1079 
1080  for( i = 0; i < files.GetCount(); i++ )
1081  {
1082  wxRemoveFile( files[i] );
1083  }
1084  }
1085 
1086  wxLogTrace( traceFootprintLibrary, wxT( "Removing footprint library '%s'" ),
1087  aLibraryPath.GetData() );
1088 
1089  // Some of the more elaborate wxRemoveFile() crap puts up its own wxLog dialog
1090  // we don't want that. we want bare metal portability with no UI here.
1091  if( !wxRmdir( aLibraryPath ) )
1092  {
1093  THROW_IO_ERROR( wxString::Format( _( "footprint library '%s' cannot be deleted" ),
1094  aLibraryPath.GetData() ) );
1095  }
1096 
1097  // For some reason removing a directory in Windows is not immediately updated. This delay
1098  // prevents an error when attempting to immediately recreate the same directory when over
1099  // writing an existing library.
1100 #ifdef __WINDOWS__
1101  wxMilliSleep( 250L );
1102 #endif
1103 
1104  if( m_cache && m_cache->GetPath() == aLibraryPath )
1105  {
1106  delete m_cache;
1107  m_cache = NULL;
1108  }
1109 
1110  return true;
1111 }
1112 
1113 
1114 bool GPCB_PLUGIN::IsFootprintLibWritable( const wxString& aLibraryPath )
1115 {
1116  LOCALE_IO toggle;
1117 
1118  init( NULL );
1119 
1120  cacheLib( aLibraryPath );
1121 
1122  return m_cache->IsWritable();
1123 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:104
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Function AllCuMask returns a mask holding the requested number of Cu LAYER_IDs.
Definition: lset.cpp:638
void SetEnd0(const wxPoint &aPoint)
bool IsModified(const wxString &aLibPath, const wxString &aFootprintName=wxEmptyString) const
Function IsModified check if the footprint cache has been modified relative to aLibPath and aFootprin...
const wxString KiCadFootprintFileExtension
MODULE_MAP::iterator MODULE_ITER
wxDateTime m_mod_time
The last file modified time stamp.
Class LINE_READER is an abstract class from which implementation specific LINE_READERs may be derived...
Definition: richio.h:81
bool m_writable
Writability status of the footprint file.
void SetShape(STROKE_T aShape)
GPCB_PLUGIN * m_owner
MODULE_MAP::const_iterator MODULE_CITER
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.
wxFileName m_file_name
The the full file name and path of the footprint to cache.
static int KiROUND(double v)
KiROUND rounds a floating point number to an int using "round halfway cases away from zero"...
Definition: common.h:107
Class LOCALE_IO is a class that can be instantiated within a scope in which you are expecting excepti...
Definition: common.h:166
#define OLD_GPCB_UNIT_CONV
wxArrayString FootprintEnumerate(const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL) override
Function FootprintEnumerate returns a list of footprint names contained within the library at aLibrar...
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.
virtual void SetLayer(LAYER_ID aLayer)
Function SetLayer sets the layer this item is on.
const wxPoint & GetEnd0() const
Smd pad, appears on the solder paste layer (default)
Definition: pad_shapes.h:59
double RAD2DECIDEG(double rad)
Definition: trigo.h:196
void SetPosition(const wxPoint &aPos) override
Definition: class_pad.h:169
Class GPCB_FPL_CACHE_ITEM is helper class for creating a footprint library cache. ...
void cacheLib(const wxString &aLibraryPath, const wxString &aFootprintName=wxEmptyString)
we only cache one footprint library for now, this determines which one.
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 SetDrillSize(const wxSize &aSize)
Definition: class_pad.h:187
GPCB_FPL_CACHE_ITEM(MODULE *aModule, const wxFileName &aFileName)
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:317
MODULE * GetModule() const
void Remove(const wxString &aFootprintName)
Class LIB_ID.
Definition: lib_id.h:56
Class PROPERTIES is a name/value tuple with unique names and optional values.
Definition: properties.h:34
PAD_SHAPE_T GetShape() const
Function GetShape.
Definition: class_pad.h:166
static const wxString traceFootprintLibrary(wxT("GedaPcbFootprintLib"))
Definition for enabling and disabling footprint library trace output.
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:90
Class FILE_LINE_READER is a LINE_READER that reads from an open file.
Definition: richio.h:180
Class LSET is a set of LAYER_IDs.
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:133
wxDateTime m_mod_time
The path of the library.
const wxString GedaPcbFootprintLibFileExtension
void SetPos0(const wxPoint &aPos)
Definition: class_pad.h:175
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.
const wxSize & GetSize() const
Definition: class_pad.h:182
void SetSize(const wxSize &aSize)
Definition: class_pad.h:181
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:89
wxFileName m_lib_path
Plugin object that owns the cache.
#define TRACE_PARAMS(arr)
#define THROW_IO_ERROR(x)
Definition: utf8.cpp:60
MODULE_MAP m_modules
Footprint library path modified time stamp.
void Load()
Save not implemented for the Geda PCB footprint library format.
void SetAttribute(PAD_ATTR_T aAttribute)
Definition: class_pad.cpp:297
wxString GetName() const
void SetLocalClearance(int aClearance)
Definition: class_pad.h:247
wxDateTime GetLibModificationTime() const
std::unique_ptr< MODULE > m_module
wxFileName GetFileName() const
MODULE * parseMODULE(LINE_READER *aLineReader)
Map of footprint file name per MODULE*.
bool IsWritable() const
void SetLayerSet(LSET aLayerMask)
Definition: class_pad.h:234
Struct PARSE_ERROR contains a filename or source description, a problem input line, a line number, a byte offset, and an error message which contains the the caller's report and his call site information: CPP source file, function, and line number.
Definition: ki_exception.h:94
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
Class to handle a graphic segment.
#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 SetLocalSolderMaskMargin(int aMargin)
Definition: class_pad.h:244
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)
bool IsPath(const wxString &aPath) const
Function IsPath checks if aPath is the same as the current cache path.
void SetDrawCoord()
Set draw coordinates (absolute values ) from relative coordinates.
void SetStart0(const wxPoint &aPoint)
The common library.
void SetShape(PAD_SHAPE_T aShape)
Definition: class_pad.h:167
void SetPadName(const wxString &name)
Set the pad name (sometimes called pad number, although it can be an array ref like AA12 the pad name...
Definition: class_pad.cpp:404
void SetOrientation(double aAngle)
Function SetOrientation sets the rotation angle of the pad.
Definition: class_pad.cpp:306
void SetAngle(double aAngle)
Function SetAngle sets the angle for arcs, and normalizes it within the range 0 - 360 degrees...
friend class GPCB_FPL_CACHE
Definition: gpcb_plugin.h:49
LINE_READER * m_reader
no ownership here.
Definition: gpcb_plugin.h:92
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. ...
bool IsModified() const
EDGE_MODULE class definition.
wxDateTime GetLastModificationTime() const
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:47
static long parseInt(const wxString &aValue, double aScalar)
Definition: gpcb_plugin.cpp:73
void SetWidth(int aWidth)