KiCad PCB EDA Suite
GPCB_FPL_CACHE Class Reference

Public Member Functions

 GPCB_FPL_CACHE (GPCB_PLUGIN *aOwner, const wxString &aLibraryPath)
 
wxString GetPath () const
 
bool IsWritable () const
 
FOOTPRINT_MAPGetFootprints ()
 
void Load ()
 Save not implemented for the Geda PCB footprint library format. More...
 
void Remove (const wxString &aFootprintName)
 
bool IsModified ()
 Return true if the cache is not up-to-date. More...
 

Static Public Member Functions

static long long GetTimestamp (const wxString &aLibPath)
 Generate a timestamp representing all source files in the cache (including the parent directory). More...
 

Private Member Functions

FOOTPRINTparseFOOTPRINT (LINE_READER *aLineReader)
 
bool testFlags (const wxString &aFlag, long aMask, const wxChar *aName)
 Test aFlag for aMask or aName. More...
 
void parseParameters (wxArrayString &aParameterList, LINE_READER *aLineReader)
 Extract parameters and tokens from aLineReader and adds them to aParameterList. More...
 

Private Attributes

GPCB_PLUGINm_owner
 Plugin object that owns the cache. More...
 
wxFileName m_lib_path
 The path of the library. More...
 
FOOTPRINT_MAP m_footprints
 Map of footprint file name to FOOTPRINT*. More...
 
bool m_cache_dirty
 Stored separately because it's expensive to check m_cache_timestamp against all the files. More...
 
long long m_cache_timestamp
 A hash of the timestamps for all the footprint files. More...
 

Detailed Description

Definition at line 132 of file gpcb_plugin.cpp.

Constructor & Destructor Documentation

◆ GPCB_FPL_CACHE()

GPCB_FPL_CACHE::GPCB_FPL_CACHE ( GPCB_PLUGIN aOwner,
const wxString &  aLibraryPath 
)

Definition at line 207 of file gpcb_plugin.cpp.

208 {
209  m_owner = aOwner;
210  m_lib_path.SetPath( aLibraryPath );
211  m_cache_timestamp = 0;
212  m_cache_dirty = true;
213 }
GPCB_PLUGIN * m_owner
Plugin object that owns the cache.
wxFileName m_lib_path
The path of the library.
long long m_cache_timestamp
A hash of the timestamps for all the footprint files.
bool m_cache_dirty
Stored separately because it's expensive to check m_cache_timestamp against all the files.

References m_cache_dirty, m_cache_timestamp, m_lib_path, and m_owner.

Member Function Documentation

◆ GetFootprints()

FOOTPRINT_MAP& GPCB_FPL_CACHE::GetFootprints ( )
inline

Definition at line 139 of file gpcb_plugin.cpp.

139 { return m_footprints; }
FOOTPRINT_MAP m_footprints
Map of footprint file name to FOOTPRINT*.

References m_footprints.

Referenced by GPCB_PLUGIN::FootprintEnumerate(), and GPCB_PLUGIN::getFootprint().

◆ GetPath()

wxString GPCB_FPL_CACHE::GetPath ( ) const
inline

Definition at line 137 of file gpcb_plugin.cpp.

137 { return m_lib_path.GetPath(); }
wxFileName m_lib_path
The path of the library.

References m_lib_path.

Referenced by GPCB_PLUGIN::FootprintLibDelete().

◆ GetTimestamp()

long long GPCB_FPL_CACHE::GetTimestamp ( const wxString &  aLibPath)
static

Generate a timestamp representing all source files in the cache (including the parent directory).

Timestamps should not be considered ordered. They either match or they don't.

Definition at line 302 of file gpcb_plugin.cpp.

303 {
304  wxString fileSpec = wxT( "*." ) + GedaPcbFootprintLibFileExtension;
305 
306  return TimestampDir( aLibPath, fileSpec );
307 }
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:504
const std::string GedaPcbFootprintLibFileExtension

References GedaPcbFootprintLibFileExtension, and TimestampDir().

Referenced by GPCB_PLUGIN::GetLibraryTimestamp(), and IsModified().

◆ IsModified()

bool GPCB_FPL_CACHE::IsModified ( )

Return true if the cache is not up-to-date.

Definition at line 294 of file gpcb_plugin.cpp.

295 {
297 
298  return m_cache_dirty;
299 }
static long long GetTimestamp(const wxString &aLibPath)
Generate a timestamp representing all source files in the cache (including the parent directory).
wxFileName m_lib_path
The path of the library.
long long m_cache_timestamp
A hash of the timestamps for all the footprint files.
bool m_cache_dirty
Stored separately because it's expensive to check m_cache_timestamp against all the files.

References GetTimestamp(), m_cache_dirty, m_cache_timestamp, and m_lib_path.

Referenced by GPCB_PLUGIN::validateCache().

◆ IsWritable()

bool GPCB_FPL_CACHE::IsWritable ( ) const
inline

Definition at line 138 of file gpcb_plugin.cpp.

138 { return m_lib_path.IsOk() && m_lib_path.IsDirWritable(); }
wxFileName m_lib_path
The path of the library.

References m_lib_path.

Referenced by GPCB_PLUGIN::FootprintDelete(), and GPCB_PLUGIN::IsFootprintLibWritable().

◆ Load()

void GPCB_FPL_CACHE::Load ( )

Save not implemented for the Geda PCB footprint library format.

Definition at line 216 of file gpcb_plugin.cpp.

217 {
218  m_cache_dirty = false;
219  m_cache_timestamp = 0;
220 
221  // Note: like our .pretty footprint libraries, the gpcb footprint libraries are folders,
222  // and the footprints are the .fp files inside this folder.
223 
224  wxDir dir( m_lib_path.GetPath() );
225 
226  if( !dir.IsOpened() )
227  {
228  THROW_IO_ERROR( wxString::Format( _( "Footprint library '%s' not found." ),
229  m_lib_path.GetPath().GetData() ) );
230  }
231 
232  wxString fullName;
233  wxString fileSpec = wxT( "*." ) + GedaPcbFootprintLibFileExtension;
234 
235  // wxFileName construction is egregiously slow. Construct it once and just swap out
236  // the filename thereafter.
237  WX_FILENAME fn( m_lib_path.GetPath(), wxT( "dummyName" ) );
238 
239  if( !dir.GetFirst( &fullName, fileSpec ) )
240  return;
241 
242  wxString cacheErrorMsg;
243 
244  do
245  {
246  fn.SetFullName( fullName );
247 
248  // Queue I/O errors so only files that fail to parse don't get loaded.
249  try
250  {
251  // reader now owns fp, will close on exception or return
252  FILE_LINE_READER reader( fn.GetFullPath() );
253  std::string name = TO_UTF8( fn.GetName() );
254  FOOTPRINT* footprint = parseFOOTPRINT( &reader );
255 
256  // The footprint name is the file name without the extension.
257  footprint->SetFPID( LIB_ID( wxEmptyString, fn.GetName() ) );
258  m_footprints.insert( name, new GPCB_FPL_CACHE_ITEM( footprint, fn ) );
259  }
260  catch( const IO_ERROR& ioe )
261  {
262  if( !cacheErrorMsg.IsEmpty() )
263  cacheErrorMsg += "\n\n";
264 
265  cacheErrorMsg += ioe.What();
266  }
267  } while( dir.GetNext( &fullName ) );
268 
269  if( !cacheErrorMsg.IsEmpty() )
270  THROW_IO_ERROR( cacheErrorMsg );
271 }
FOOTPRINT_MAP m_footprints
Map of footprint file name to FOOTPRINT*.
helper class for creating a footprint library cache.
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:34
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:96
A LINE_READER that reads from an open file.
Definition: richio.h:172
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:30
FOOTPRINT * parseFOOTPRINT(LINE_READER *aLineReader)
#define _(s)
wxFileName m_lib_path
The path of the library.
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)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
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:56
const std::string GedaPcbFootprintLibFileExtension
bool m_cache_dirty
Stored separately because it's expensive to check m_cache_timestamp against all the files.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:75
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38

References _, Format(), GedaPcbFootprintLibFileExtension, m_cache_dirty, m_cache_timestamp, m_footprints, m_lib_path, name, parseFOOTPRINT(), WX_FILENAME::SetFullName(), THROW_IO_ERROR, TO_UTF8, and IO_ERROR::What().

Referenced by GPCB_PLUGIN::validateCache().

◆ parseFOOTPRINT()

FOOTPRINT * GPCB_FPL_CACHE::parseFOOTPRINT ( LINE_READER aLineReader)
private

Definition at line 310 of file gpcb_plugin.cpp.

311 {
312  #define TEXT_DEFAULT_SIZE ( 40*IU_PER_MILS )
313  #define OLD_GPCB_UNIT_CONV IU_PER_MILS
314 
315  // Old version unit = 1 mil, so conv_unit is 10 or 0.1
316  #define NEW_GPCB_UNIT_CONV ( 0.01*IU_PER_MILS )
317 
318  int paramCnt;
319 
320  // GPCB unit = 0.01 mils and Pcbnew 0.1.
321  double conv_unit = NEW_GPCB_UNIT_CONV;
322  wxPoint textPos;
323  wxString msg;
324  wxArrayString parameters;
325  std::unique_ptr<FOOTPRINT> footprint = std::make_unique<FOOTPRINT>( nullptr );
326 
327  if( aLineReader->ReadLine() == nullptr )
328  {
329  msg = aLineReader->GetSource() + ": empty file";
330  THROW_IO_ERROR( msg );
331  }
332 
333  parameters.Clear();
334  parseParameters( parameters, aLineReader );
335  paramCnt = parameters.GetCount();
336 
337  /* From the Geda PCB documentation, valid Element definitions:
338  * Element [SFlags "Desc" "Name" "Value" MX MY TX TY TDir TScale TSFlags]
339  * Element (NFlags "Desc" "Name" "Value" MX MY TX TY TDir TScale TNFlags)
340  * Element (NFlags "Desc" "Name" "Value" TX TY TDir TScale TNFlags)
341  * Element (NFlags "Desc" "Name" TX TY TDir TScale TNFlags)
342  * Element ("Desc" "Name" TX TY TDir TScale TNFlags)
343  */
344 
345  if( parameters[0].CmpNoCase( wxT( "Element" ) ) != 0 )
346  {
347  msg.Printf( _( "Unknown token '%s'" ), parameters[0] );
348  THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader,
349  aLineReader->LineNumber(), 0 );
350  }
351 
352  if( paramCnt < 10 || paramCnt > 14 )
353  {
354  msg.Printf( _( "Element token contains %d parameters." ), paramCnt );
355  THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader,
356  aLineReader->LineNumber(), 0 );
357  }
358 
359  // Test symbol after "Element": if [ units = 0.01 mils, and if ( units = 1 mil
360  if( parameters[1] == wxT( "(" ) )
361  conv_unit = OLD_GPCB_UNIT_CONV;
362 
363  if( paramCnt > 10 )
364  {
365  footprint->SetDescription( parameters[3] );
366  footprint->SetReference( parameters[4] );
367  }
368  else
369  {
370  footprint->SetDescription( parameters[2] );
371  footprint->SetReference( parameters[3] );
372  }
373 
374  // Read value
375  if( paramCnt > 10 )
376  footprint->SetValue( parameters[5] );
377 
378  // With gEDA/pcb, value is meaningful after instantiation, only, so it's
379  // often empty in bare footprints.
380  if( footprint->Value().GetText().IsEmpty() )
381  footprint->Value().SetText( wxT( "Val**" ) );
382 
383 
384  if( paramCnt == 14 )
385  {
386  textPos = wxPoint( parseInt( parameters[8], conv_unit ),
387  parseInt( parameters[9], conv_unit ) );
388  }
389  else
390  {
391  textPos = wxPoint( parseInt( parameters[6], conv_unit ),
392  parseInt( parameters[7], conv_unit ) );
393  }
394 
395  int orientation = parseInt( parameters[paramCnt-4], 1.0 );
396  footprint->Reference().SetTextAngle(( orientation % 2) ? 900 : 0 );
397 
398  // Calculate size: default height is 40 mils, width 30 mil.
399  // real size is: default * ibuf[idx+3] / 100 (size in gpcb is given in percent of default size
400  int thsize = parseInt( parameters[paramCnt-3], TEXT_DEFAULT_SIZE ) / 100;
401  thsize = std::max( (int)( 5 * IU_PER_MILS ), thsize ); // Ensure a minimal size = 5 mils
402  int twsize = thsize * 30 / 40;
403  int thickness = thsize / 8;
404 
405  // gEDA/pcb aligns top/left, not pcbnew's default, center/center.
406  // Compensate for this by shifting the insertion point instead of the
407  // alignment, because alignment isn't changeable in the GUI.
408  textPos.x = textPos.x + twsize * footprint->GetReference().Len() / 2;
409  textPos.y += thsize / 2;
410 
411  // gEDA/pcb draws a bit too low/left, while pcbnew draws a bit too
412  // high/right. Compensate for similar appearance.
413  textPos.x -= thsize / 10;
414  textPos.y += thsize / 2;
415 
416  footprint->Reference().SetTextPos( textPos );
417  footprint->Reference().SetPos0( textPos );
418  footprint->Reference().SetTextSize( wxSize( twsize, thsize ) );
419  footprint->Reference().SetTextThickness( thickness );
420 
421  // gEDA/pcb shows only one of value/reference/description at a time. Which
422  // one is selectable by a global menu setting. pcbnew needs reference as
423  // well as value visible, so place the value right below the reference.
424  footprint->Value().SetTextAngle( footprint->Reference().GetTextAngle() );
425  footprint->Value().SetTextSize( footprint->Reference().GetTextSize() );
426  footprint->Value().SetTextThickness( footprint->Reference().GetTextThickness() );
427  textPos.y += thsize * 13 / 10; // 130% line height
428  footprint->Value().SetTextPos( textPos );
429  footprint->Value().SetPos0( textPos );
430 
431  while( aLineReader->ReadLine() )
432  {
433  parameters.Clear();
434  parseParameters( parameters, aLineReader );
435 
436  if( parameters.IsEmpty() || parameters[0] == wxT( "(" ) )
437  continue;
438 
439  if( parameters[0] == wxT( ")" ) )
440  break;
441 
442  paramCnt = parameters.GetCount();
443 
444  // Test units value for a string line param (more than 3 parameters : ident [ xx ] )
445  if( paramCnt > 3 )
446  {
447  if( parameters[1] == wxT( "(" ) )
448  conv_unit = OLD_GPCB_UNIT_CONV;
449  else
450  conv_unit = NEW_GPCB_UNIT_CONV;
451  }
452 
453  wxLogTrace( traceGedaPcbPlugin, wxT( "%s parameter count = %d." ),
454  parameters[0], paramCnt );
455 
456  // Parse a line with format: ElementLine [X1 Y1 X2 Y2 Thickness]
457  if( parameters[0].CmpNoCase( wxT( "ElementLine" ) ) == 0 )
458  {
459  if( paramCnt != 8 )
460  {
461  msg.Printf( wxT( "ElementLine token contains %d parameters." ), paramCnt );
462  THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader,
463  aLineReader->LineNumber(), 0 );
464  }
465 
466  FP_SHAPE* shape = new FP_SHAPE( footprint.get(), SHAPE_T::SEGMENT );
467  shape->SetLayer( F_SilkS );
468  shape->SetStart0( wxPoint( parseInt( parameters[2], conv_unit ),
469  parseInt( parameters[3], conv_unit ) ) );
470  shape->SetEnd0( wxPoint( parseInt( parameters[4], conv_unit ),
471  parseInt( parameters[5], conv_unit ) ) );
472  shape->SetWidth( parseInt( parameters[6], conv_unit ) );
473  shape->SetDrawCoord();
474  footprint->Add( shape );
475  continue;
476  }
477 
478  // Parse an arc with format: ElementArc [X Y Width Height StartAngle DeltaAngle Thickness]
479  if( parameters[0].CmpNoCase( wxT( "ElementArc" ) ) == 0 )
480  {
481  if( paramCnt != 10 )
482  {
483  msg.Printf( wxT( "ElementArc token contains %d parameters." ), paramCnt );
484  THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader,
485  aLineReader->LineNumber(), 0 );
486  }
487 
488  // Pcbnew does know ellipse so we must have Width = Height
489  FP_SHAPE* shape = new FP_SHAPE( footprint.get(), SHAPE_T::ARC );
490  shape->SetLayer( F_SilkS );
491  footprint->Add( shape );
492 
493  // for and arc: ibuf[3] = ibuf[4]. Pcbnew does not know ellipses
494  int radius = ( parseInt( parameters[4], conv_unit ) +
495  parseInt( parameters[5], conv_unit ) ) / 2;
496 
497  wxPoint centre( parseInt( parameters[2], conv_unit ),
498  parseInt( parameters[3], conv_unit ) );
499 
500  shape->SetCenter0( centre );
501 
502  // Pcbnew start angles are inverted and 180 degrees from Geda PCB angles.
503  double start_angle = parseInt( parameters[6], -10.0 ) + 1800.0;
504 
505  // Pcbnew delta angle direction is the opposite of Geda PCB delta angles.
506  double sweep_angle = parseInt( parameters[7], -10.0 );
507 
508  // Geda PCB does not support circles.
509  if( sweep_angle == -3600.0 )
510  shape->SetShape( SHAPE_T::CIRCLE );
511 
512  // Calculate start point coordinate of arc
513  wxPoint arcStart( radius, 0 );
514  RotatePoint( &arcStart, -start_angle );
515  shape->SetStart0( arcStart + centre );
516 
517  // Angle value is clockwise in gpcb and Pcbnew.
518  shape->SetArcAngleAndEnd0( sweep_angle );
519 
520  shape->SetWidth( parseInt( parameters[8], conv_unit ) );
521  shape->SetDrawCoord();
522  continue;
523  }
524 
525  // Parse a Pad with no hole with format:
526  // Pad [rX1 rY1 rX2 rY2 Thickness Clearance Mask "Name" "Number" SFlags]
527  // Pad (rX1 rY1 rX2 rY2 Thickness Clearance Mask "Name" "Number" NFlags)
528  // Pad (aX1 aY1 aX2 aY2 Thickness "Name" "Number" NFlags)
529  // Pad (aX1 aY1 aX2 aY2 Thickness "Name" NFlags)
530  if( parameters[0].CmpNoCase( wxT( "Pad" ) ) == 0 )
531  {
532  if( paramCnt < 10 || paramCnt > 13 )
533  {
534  msg.Printf( wxT( "Pad token contains %d parameters." ), paramCnt );
535  THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader,
536  aLineReader->LineNumber(), 0 );
537  }
538 
539  PAD* pad = new PAD( footprint.get() );
540 
541  static const LSET pad_front( 3, F_Cu, F_Mask, F_Paste );
542  static const LSET pad_back( 3, B_Cu, B_Mask, B_Paste );
543 
544  pad->SetShape( PAD_SHAPE::RECT );
545  pad->SetAttribute( PAD_ATTRIB::SMD );
546  pad->SetLayerSet( pad_front );
547 
548  if( testFlags( parameters[paramCnt-2], 0x0080, wxT( "onsolder" ) ) )
549  pad->SetLayerSet( pad_back );
550 
551  // Set the pad name:
552  // Pcbnew pad name is used for electrical connection calculations.
553  // Accordingly it should be mapped to gEDA's pin/pad number,
554  // which is used for the same purpose.
555  // gEDA also features a pin/pad "name", which is an arbitrary string
556  // and set to the pin name of the netlist on instantiation. Many gEDA
557  // bare footprints use identical strings for name and number, so this
558  // can be a bit confusing.
559  pad->SetNumber( parameters[paramCnt-3] );
560 
561  int x1 = parseInt( parameters[2], conv_unit );
562  int x2 = parseInt( parameters[4], conv_unit );
563  int y1 = parseInt( parameters[3], conv_unit );
564  int y2 = parseInt( parameters[5], conv_unit );
565  int width = parseInt( parameters[6], conv_unit );
566  wxPoint delta( x2 - x1, y2 - y1 );
567  double angle = atan2( (double)delta.y, (double)delta.x );
568 
569  // Get the pad clearance and the solder mask clearance.
570  if( paramCnt == 13 )
571  {
572  int clearance = parseInt( parameters[7], conv_unit );
573  // One of gEDA's oddities is that clearance between pad and polygon
574  // is given as the gap on both sides of the pad together, so for
575  // KiCad it has to halfed.
576  pad->SetLocalClearance( clearance / 2 );
577 
578  // In GEDA, the mask value is the size of the hole in this
579  // solder mask. In Pcbnew, it is a margin, therefore the distance
580  // between the copper and the mask
581  int maskMargin = parseInt( parameters[8], conv_unit );
582  maskMargin = ( maskMargin - width ) / 2;
583  pad->SetLocalSolderMaskMargin( maskMargin );
584  }
585 
586  // Negate angle (due to Y reversed axis) and convert it to internal units
587  angle = - RAD2DECIDEG( angle );
588  pad->SetOrientation( KiROUND( angle ) );
589 
590  wxPoint padPos( (x1 + x2) / 2, (y1 + y2) / 2 );
591 
592  pad->SetSize( wxSize( KiROUND( EuclideanNorm( delta ) ) + width, 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->SetNumber( 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  return footprint.release();
691 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:146
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:750
void SetEnd0(const wxPoint &aPoint)
Definition: fp_shape.h:114
virtual const wxString & GetSource() const
Returns the name of the source of the lines in an abstract sense.
Definition: richio.h:109
#define OLD_GPCB_UNIT_CONV
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:161
const wxChar *const traceGedaPcbPlugin
Flag to enable GEDA PCB plugin debug output.
void SetArcAngleAndEnd0(double aAngle, bool aCheckNegativeAngle=false)
Sets the angle for arcs, and normalizes it within the range 0 - 360 degrees.
Definition: fp_shape.cpp:184
Smd pad, appears on the solder paste layer (default)
double RAD2DECIDEG(double rad)
Definition: trigo.h:234
void parseParameters(wxArrayString &aParameterList, LINE_READER *aLineReader)
Extract parameters and tokens from aLineReader and adds them to aParameterList.
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:229
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:504
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:164
virtual unsigned LineNumber() const
Return the line number of the last line read from this LINE_READER.
Definition: richio.h:135
#define NEW_GPCB_UNIT_CONV
#define _(s)
void SetWidth(int aWidth)
Definition: eda_shape.h:88
void SetDrawCoord()
Set draw coordinates (absolute values ) from relative coordinates.
Definition: fp_shape.cpp:81
void SetStart0(const wxPoint &aPoint)
Definition: fp_shape.h:111
virtual char * ReadLine()=0
Read a line of text into the buffer and increments the line number counter.
#define TEXT_DEFAULT_SIZE
Definition: layer_ids.h:71
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
void SetShape(SHAPE_T aShape)
Definition: eda_shape.h:91
#define IU_PER_MILS
Definition: plotter.cpp:136
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:73
constexpr int delta
bool testFlags(const wxString &aFlag, long aMask, const wxChar *aName)
Test aFlag for aMask or aName.
Definition: pad.h:57
void SetCenter0(const wxPoint &aPt)
Definition: fp_shape.cpp:158
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
static long parseInt(const wxString &aValue, double aScalar)
Definition: gpcb_plugin.cpp:52

References _, LSET::AllCuMask(), PNS::angle(), ARC, B_Cu, B_Mask, B_Paste, CIRCLE, delta, EuclideanNorm(), F_Cu, F_Mask, F_Paste, F_SilkS, LINE_READER::GetSource(), IU_PER_MILS, KiROUND(), LINE_READER::LineNumber(), NEW_GPCB_UNIT_CONV, OLD_GPCB_UNIT_CONV, OVAL, PAD, pad, parseInt(), parseParameters(), RAD2DECIDEG(), LINE_READER::ReadLine(), RECT, RotatePoint(), SEGMENT, FP_SHAPE::SetArcAngleAndEnd0(), FP_SHAPE::SetCenter0(), FP_SHAPE::SetDrawCoord(), FP_SHAPE::SetEnd0(), BOARD_ITEM::SetLayer(), EDA_SHAPE::SetShape(), FP_SHAPE::SetStart0(), EDA_SHAPE::SetWidth(), SMD, testFlags(), TEXT_DEFAULT_SIZE, THROW_IO_ERROR, THROW_PARSE_ERROR, and traceGedaPcbPlugin.

Referenced by Load().

◆ parseParameters()

void GPCB_FPL_CACHE::parseParameters ( wxArrayString &  aParameterList,
LINE_READER aLineReader 
)
private

Extract parameters and tokens from aLineReader and adds them to aParameterList.

Delimiter characters are: [ ] ( ) Begin and end of parameter list and units indicator " is a string delimiter space is the param separator The first word is the keyword the second item is one of ( or [ other are parameters (number or delimited string) last parameter is ) or ]

Parameters
aParameterListThis list of parameters parsed.
aLineReaderThe line reader object to parse.

Definition at line 694 of file gpcb_plugin.cpp.

695 {
696  char key;
697  wxString tmp;
698  char* line = aLineReader->Line();
699 
700  // Last line already ready in main parser loop.
701  while( *line != 0 )
702  {
703  key = *line;
704  line++;
705 
706  switch( key )
707  {
708  case '[':
709  case '(':
710  if( !tmp.IsEmpty() )
711  {
712  aParameterList.Add( tmp );
713  tmp.Clear();
714  }
715 
716  tmp.Append( key );
717  aParameterList.Add( tmp );
718  tmp.Clear();
719 
720  // Opening delimiter "(" after Element statement. Any other occurrence is part
721  // of a keyword definition.
722  if( aParameterList.GetCount() == 1 )
723  {
724  wxLogTrace( traceGedaPcbPlugin, dump( aParameterList ) );
725  return;
726  }
727 
728  break;
729 
730  case ']':
731  case ')':
732  if( !tmp.IsEmpty() )
733  {
734  aParameterList.Add( tmp );
735  tmp.Clear();
736  }
737 
738  tmp.Append( key );
739  aParameterList.Add( tmp );
740  wxLogTrace( traceGedaPcbPlugin, dump( aParameterList ) );
741  return;
742 
743  case '\n':
744  case '\r':
745  // Element descriptions can span multiple lines.
746  line = aLineReader->ReadLine();
748 
749  case '\t':
750  case ' ':
751  if( !tmp.IsEmpty() )
752  {
753  aParameterList.Add( tmp );
754  tmp.Clear();
755  }
756 
757  break;
758 
759  case '"':
760  // Handle empty quotes.
761  if( *line == '"' )
762  {
763  line++;
764  tmp.Clear();
765  aParameterList.Add( wxEmptyString );
766  break;
767  }
768 
769  while( *line != 0 )
770  {
771  key = *line;
772  line++;
773 
774  if( key == '"' )
775  {
776  aParameterList.Add( tmp );
777  tmp.Clear();
778  break;
779  }
780  else
781  {
782  tmp.Append( key );
783  }
784  }
785 
786  break;
787 
788  case '#':
789  line = aLineReader->ReadLine();
790  break;
791 
792  default:
793  tmp.Append( key );
794  break;
795  }
796  }
797 }
char * Line() const
Return a pointer to the last line that was read in.
Definition: richio.h:117
const wxChar *const traceGedaPcbPlugin
Flag to enable GEDA PCB plugin debug output.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
wxString dump(const wxArrayString &aArray)
Debug helper for printing wxArrayString contents.
virtual char * ReadLine()=0
Read a line of text into the buffer and increments the line number counter.

References dump(), KI_FALLTHROUGH, LINE_READER::Line(), LINE_READER::ReadLine(), and traceGedaPcbPlugin.

Referenced by parseFOOTPRINT().

◆ Remove()

void GPCB_FPL_CACHE::Remove ( const wxString &  aFootprintName)

Definition at line 274 of file gpcb_plugin.cpp.

275 {
276  std::string footprintName = TO_UTF8( aFootprintName );
277 
278  FOOTPRINT_MAP::const_iterator it = m_footprints.find( footprintName );
279 
280  if( it == m_footprints.end() )
281  {
282  THROW_IO_ERROR( wxString::Format( _( "Library '%s' has no footprint '%s'." ),
283  m_lib_path.GetPath().GetData(),
284  aFootprintName.GetData() ) );
285  }
286 
287  // Remove the footprint from the cache and delete the footprint file from the library.
288  wxString fullPath = it->second->GetFileName().GetFullPath();
289  m_footprints.erase( footprintName );
290  wxRemoveFile( fullPath );
291 }
FOOTPRINT_MAP m_footprints
Map of footprint file name to FOOTPRINT*.
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:96
#define _(s)
wxFileName m_lib_path
The path of the library.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38

References _, Format(), m_footprints, m_lib_path, THROW_IO_ERROR, and TO_UTF8.

Referenced by GPCB_PLUGIN::FootprintDelete().

◆ testFlags()

bool GPCB_FPL_CACHE::testFlags ( const wxString &  aFlag,
long  aMask,
const wxChar *  aName 
)
private

Test aFlag for aMask or aName.

Parameters
aFlagis a list of flags to test against: can be a bit field flag or a list name flag a bit field flag is an hexadecimal value: Ox00020000 a list name flag is a string list of flags, comma separated like square,option1.
aMaskis the flag list to test.
aNameis the flag name to find in list.
Returns
true if found.

Definition at line 800 of file gpcb_plugin.cpp.

801 {
802  wxString number;
803 
804  if( aFlag.StartsWith( wxT( "0x" ), &number ) || aFlag.StartsWith( wxT( "0X" ), &number ) )
805  {
806  long lflags;
807 
808  if( number.ToLong( &lflags, 16 ) && ( lflags & aMask ) )
809  return true;
810  }
811  else if( aFlag.Contains( aName ) )
812  {
813  return true;
814  }
815 
816  return false;
817 }

Referenced by parseFOOTPRINT().

Member Data Documentation

◆ m_cache_dirty

bool GPCB_FPL_CACHE::m_cache_dirty
private

Stored separately because it's expensive to check m_cache_timestamp against all the files.

Definition at line 200 of file gpcb_plugin.cpp.

Referenced by GPCB_FPL_CACHE(), IsModified(), and Load().

◆ m_cache_timestamp

long long GPCB_FPL_CACHE::m_cache_timestamp
private

A hash of the timestamps for all the footprint files.

Definition at line 202 of file gpcb_plugin.cpp.

Referenced by GPCB_FPL_CACHE(), IsModified(), and Load().

◆ m_footprints

FOOTPRINT_MAP GPCB_FPL_CACHE::m_footprints
private

Map of footprint file name to FOOTPRINT*.

Definition at line 198 of file gpcb_plugin.cpp.

Referenced by GetFootprints(), Load(), and Remove().

◆ m_lib_path

wxFileName GPCB_FPL_CACHE::m_lib_path
private

The path of the library.

Definition at line 197 of file gpcb_plugin.cpp.

Referenced by GetPath(), GPCB_FPL_CACHE(), IsModified(), IsWritable(), Load(), and Remove().

◆ m_owner

GPCB_PLUGIN* GPCB_FPL_CACHE::m_owner
private

Plugin object that owns the cache.

Definition at line 196 of file gpcb_plugin.cpp.

Referenced by GPCB_FPL_CACHE().


The documentation for this class was generated from the following file: