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 );
212 m_cache_dirty = true;
213}
long long m_cache_timestamp
A hash of the timestamps for all the footprint files.
wxFileName m_lib_path
The path of the library.
bool m_cache_dirty
Stored separately because it's expensive to check m_cache_timestamp against all the files.
GPCB_PLUGIN * m_owner
Plugin object that owns the cache.

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(); }

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:536
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).

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(); }

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;
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 += wxT( "\n\n" );
264
265 cacheErrorMsg += ioe.What();
266 }
267 } while( dir.GetNext( &fullName ) );
268
269 if( !cacheErrorMsg.IsEmpty() )
270 THROW_IO_ERROR( cacheErrorMsg );
271}
const char * name
Definition: DXF_plotter.cpp:56
A LINE_READER that reads from an open file.
Definition: richio.h:173
void SetFPID(const LIB_ID &aFPID)
Definition: footprint.h:213
helper class for creating a footprint library cache.
FOOTPRINT * parseFOOTPRINT(LINE_READER *aLineReader)
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:76
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:30
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:49
A wrapper around a wxFileName which is much more performant with a subset of the API.
Definition: wx_filename.h:49
#define _(s)
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:96
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

References _, Format(), GedaPcbFootprintLibFileExtension, WX_FILENAME::GetFullPath(), WX_FILENAME::GetName(), m_cache_dirty, m_cache_timestamp, m_footprints, m_lib_path, name, parseFOOTPRINT(), FOOTPRINT::SetFPID(), 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*pcbIUScale.IU_PER_MILS )
313 #define OLD_GPCB_UNIT_CONV pcbIUScale.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*pcbIUScale.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 VECTOR2I 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() + wxT( ": 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 = VECTOR2I( parseInt( parameters[8], conv_unit ),
387 parseInt( parameters[9], conv_unit ) );
388 }
389 else
390 {
391 textPos = VECTOR2I( 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) ? ANGLE_VERTICAL : ANGLE_HORIZONTAL );
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 * pcbIUScale.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( VECTOR2I( parseInt( parameters[2], conv_unit ),
469 parseInt( parameters[3], conv_unit ) ) );
470 shape->SetEnd0( VECTOR2I( parseInt( parameters[4], conv_unit ),
471 parseInt( parameters[5], conv_unit ) ) );
472 shape->SetStroke( STROKE_PARAMS( parseInt( parameters[6], conv_unit ),
474 shape->SetDrawCoord();
475 footprint->Add( shape );
476 continue;
477 }
478
479 // Parse an arc with format: ElementArc [X Y Width Height StartAngle DeltaAngle Thickness]
480 if( parameters[0].CmpNoCase( wxT( "ElementArc" ) ) == 0 )
481 {
482 if( paramCnt != 10 )
483 {
484 msg.Printf( wxT( "ElementArc token contains %d parameters." ), paramCnt );
485 THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader,
486 aLineReader->LineNumber(), 0 );
487 }
488
489 // Pcbnew does know ellipse so we must have Width = Height
490 FP_SHAPE* shape = new FP_SHAPE( footprint.get(), SHAPE_T::ARC );
491 shape->SetLayer( F_SilkS );
492 footprint->Add( shape );
493
494 // for and arc: ibuf[3] = ibuf[4]. Pcbnew does not know ellipses
495 int radius = ( parseInt( parameters[4], conv_unit ) +
496 parseInt( parameters[5], conv_unit ) ) / 2;
497
498 VECTOR2I centre( parseInt( parameters[2], conv_unit ),
499 parseInt( parameters[3], conv_unit ) );
500
501 shape->SetCenter0( centre );
502
503 // Pcbnew start angles are inverted and 180 degrees from Geda PCB angles.
504 EDA_ANGLE start_angle( (int) parseInt( parameters[6], -10.0 ), TENTHS_OF_A_DEGREE_T );
505 start_angle += ANGLE_180;
506
507 // Pcbnew delta angle direction is the opposite of Geda PCB delta angles.
508 EDA_ANGLE sweep_angle( (int) parseInt( parameters[7], -10.0 ), TENTHS_OF_A_DEGREE_T );
509
510 // Geda PCB does not support circles.
511 if( sweep_angle == -ANGLE_360 )
512 shape->SetShape( SHAPE_T::CIRCLE );
513
514 // Calculate start point coordinate of arc
515 VECTOR2I arcStart( radius, 0 );
516 RotatePoint( arcStart, -start_angle );
517 shape->SetStart0( arcStart + centre );
518
519 // Angle value is clockwise in gpcb and Pcbnew.
520 shape->SetArcAngleAndEnd0( sweep_angle );
521
522 shape->SetStroke( STROKE_PARAMS( parseInt( parameters[8], conv_unit ),
524 shape->SetDrawCoord();
525 continue;
526 }
527
528 // Parse a Pad with no hole with format:
529 // Pad [rX1 rY1 rX2 rY2 Thickness Clearance Mask "Name" "Number" SFlags]
530 // Pad (rX1 rY1 rX2 rY2 Thickness Clearance Mask "Name" "Number" NFlags)
531 // Pad (aX1 aY1 aX2 aY2 Thickness "Name" "Number" NFlags)
532 // Pad (aX1 aY1 aX2 aY2 Thickness "Name" NFlags)
533 if( parameters[0].CmpNoCase( wxT( "Pad" ) ) == 0 )
534 {
535 if( paramCnt < 10 || paramCnt > 13 )
536 {
537 msg.Printf( wxT( "Pad token contains %d parameters." ), paramCnt );
538 THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader,
539 aLineReader->LineNumber(), 0 );
540 }
541
542 std::unique_ptr<PAD> pad = std::make_unique<PAD>( footprint.get() );
543
544 static const LSET pad_front( 3, F_Cu, F_Mask, F_Paste );
545 static const LSET pad_back( 3, B_Cu, B_Mask, B_Paste );
546
547 pad->SetShape( PAD_SHAPE::RECT );
548 pad->SetAttribute( PAD_ATTRIB::SMD );
549 pad->SetLayerSet( pad_front );
550
551 if( testFlags( parameters[paramCnt-2], 0x0080, wxT( "onsolder" ) ) )
552 pad->SetLayerSet( pad_back );
553
554 // Set the pad name:
555 // Pcbnew pad name is used for electrical connection calculations.
556 // Accordingly it should be mapped to gEDA's pin/pad number,
557 // which is used for the same purpose.
558 // gEDA also features a pin/pad "name", which is an arbitrary string
559 // and set to the pin name of the netlist on instantiation. Many gEDA
560 // bare footprints use identical strings for name and number, so this
561 // can be a bit confusing.
562 pad->SetNumber( parameters[paramCnt-3] );
563
564 int x1 = parseInt( parameters[2], conv_unit );
565 int x2 = parseInt( parameters[4], conv_unit );
566 int y1 = parseInt( parameters[3], conv_unit );
567 int y2 = parseInt( parameters[5], conv_unit );
568 int width = parseInt( parameters[6], conv_unit );
569 VECTOR2I delta( x2 - x1, y2 - y1 );
570 double angle = atan2( (double)delta.y, (double)delta.x );
571
572 // Get the pad clearance and the solder mask clearance.
573 if( paramCnt == 13 )
574 {
575 int clearance = parseInt( parameters[7], conv_unit );
576 // One of gEDA's oddities is that clearance between pad and polygon
577 // is given as the gap on both sides of the pad together, so for
578 // KiCad it has to halfed.
579 pad->SetLocalClearance( clearance / 2 );
580
581 // In GEDA, the mask value is the size of the hole in this
582 // solder mask. In Pcbnew, it is a margin, therefore the distance
583 // between the copper and the mask
584 int maskMargin = parseInt( parameters[8], conv_unit );
585 maskMargin = ( maskMargin - width ) / 2;
586 pad->SetLocalSolderMaskMargin( maskMargin );
587 }
588
589 // Negate angle (due to Y reversed axis)
590 EDA_ANGLE orient( -angle, RADIANS_T );
591 pad->SetOrientation( orient );
592
593 VECTOR2I padPos( ( x1 + x2 ) / 2, ( y1 + y2 ) / 2 );
594
595 pad->SetSize( wxSize( KiROUND( EuclideanNorm( delta ) ) + width, width ) );
596
597 // Set the relative position before adjusting the absolute position
598 pad->SetPos0( padPos );
599 padPos += footprint->GetPosition();
600 pad->SetPosition( padPos );
601
602 if( !testFlags( parameters[paramCnt-2], 0x0100, wxT( "square" ) ) )
603 {
604 if( pad->GetSize().x == pad->GetSize().y )
605 pad->SetShape( PAD_SHAPE::CIRCLE );
606 else
607 pad->SetShape( PAD_SHAPE::OVAL );
608 }
609
610 if( pad->GetSizeX() > 0 && pad->GetSizeY() > 0 )
611 {
612 footprint->Add( pad.release() );
613 }
614 else
615 {
616 wxLogError( _( "Invalid zero-sized pad ignored in\nfile: %s" ),
617 aLineReader->GetSource() );
618 }
619
620 continue;
621 }
622
623 // Parse a Pin with through hole with format:
624 // Pin [rX rY Thickness Clearance Mask Drill "Name" "Number" SFlags]
625 // Pin (rX rY Thickness Clearance Mask Drill "Name" "Number" NFlags)
626 // Pin (aX aY Thickness Drill "Name" "Number" NFlags)
627 // Pin (aX aY Thickness Drill "Name" NFlags)
628 // Pin (aX aY Thickness "Name" NFlags)
629 if( parameters[0].CmpNoCase( wxT( "Pin" ) ) == 0 )
630 {
631 if( paramCnt < 8 || paramCnt > 12 )
632 {
633 msg.Printf( wxT( "Pin token contains %d parameters." ), paramCnt );
634 THROW_PARSE_ERROR( msg, aLineReader->GetSource(), (const char *)aLineReader,
635 aLineReader->LineNumber(), 0 );
636 }
637
638 PAD* pad = new PAD( footprint.get() );
639
640 pad->SetShape( PAD_SHAPE::CIRCLE );
641
642 static const LSET pad_set = LSET::AllCuMask() | LSET( 3, F_SilkS, F_Mask, B_Mask );
643
644 pad->SetLayerSet( pad_set );
645
646 if( testFlags( parameters[paramCnt-2], 0x0100, wxT( "square" ) ) )
647 pad->SetShape( PAD_SHAPE::RECT );
648
649 // Set the pad name:
650 // Pcbnew pad name is used for electrical connection calculations.
651 // Accordingly it should be mapped to gEDA's pin/pad number,
652 // which is used for the same purpose.
653 pad->SetNumber( parameters[paramCnt-3] );
654
655 VECTOR2I padPos( parseInt( parameters[2], conv_unit ),
656 parseInt( parameters[3], conv_unit ) );
657
658 int padSize = parseInt( parameters[4], conv_unit );
659
660 pad->SetSize( wxSize( padSize, padSize ) );
661
662 int drillSize = 0;
663
664 // Get the pad clearance, solder mask clearance, and drill size.
665 if( paramCnt == 12 )
666 {
667 int clearance = parseInt( parameters[5], conv_unit );
668 // One of gEDA's oddities is that clearance between pad and polygon
669 // is given as the gap on both sides of the pad together, so for
670 // KiCad it has to halfed.
671 pad->SetLocalClearance( clearance / 2 );
672
673 // In GEDA, the mask value is the size of the hole in this
674 // solder mask. In Pcbnew, it is a margin, therefore the distance
675 // between the copper and the mask
676 int maskMargin = parseInt( parameters[6], conv_unit );
677 maskMargin = ( maskMargin - padSize ) / 2;
678 pad->SetLocalSolderMaskMargin( maskMargin );
679
680 drillSize = parseInt( parameters[7], conv_unit );
681 }
682 else
683 {
684 drillSize = parseInt( parameters[5], conv_unit );
685 }
686
687 pad->SetDrillSize( wxSize( drillSize, drillSize ) );
688
689 // Set the relative position before adjusting the absolute position
690 pad->SetPos0( padPos );
691 padPos += footprint->GetPosition();
692 pad->SetPosition( padPos );
693
694 if( pad->GetShape() == PAD_SHAPE::CIRCLE && pad->GetSize().x != pad->GetSize().y )
695 pad->SetShape( PAD_SHAPE::OVAL );
696
697 footprint->Add( pad );
698 continue;
699 }
700 }
701
702 return footprint.release();
703}
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:109
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:226
void SetShape(SHAPE_T aShape)
Definition: eda_shape.h:112
void SetEnd0(const VECTOR2I &aPoint)
Definition: fp_shape.h:94
void SetStart0(const VECTOR2I &aPoint)
Definition: fp_shape.h:91
virtual void SetDrawCoord()
Set draw coordinates (absolute values ) from relative coordinates.
Definition: fp_shape.cpp:80
void SetArcAngleAndEnd0(const EDA_ANGLE &aAngle, bool aCheckNegativeAngle=false)
Sets the angle for arcs, and normalizes it within the range 0 - 360 degrees.
Definition: fp_shape.cpp:193
void SetCenter0(const VECTOR2I &aPt)
Definition: fp_shape.cpp:161
void parseParameters(wxArrayString &aParameterList, LINE_READER *aLineReader)
Extract parameters and tokens from aLineReader and adds them to aParameterList.
bool testFlags(const wxString &aFlag, long aMask, const wxChar *aName)
Test aFlag for aMask or aName.
virtual char * ReadLine()=0
Read a line of text into the buffer and increments the line number counter.
virtual const wxString & GetSource() const
Returns the name of the source of the lines in an abstract sense.
Definition: richio.h:109
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:530
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:773
Definition: pad.h:59
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: pcb_shape.h:72
Simple container to manage line stroke parameters.
Definition: stroke_params.h:88
static constexpr EDA_ANGLE & ANGLE_180
Definition: eda_angle.h:427
static constexpr EDA_ANGLE & ANGLE_HORIZONTAL
Definition: eda_angle.h:419
@ TENTHS_OF_A_DEGREE_T
Definition: eda_angle.h:30
@ RADIANS_T
Definition: eda_angle.h:32
static constexpr EDA_ANGLE & ANGLE_360
Definition: eda_angle.h:429
static constexpr EDA_ANGLE & ANGLE_VERTICAL
Definition: eda_angle.h:420
static long parseInt(const wxString &aValue, double aScalar)
Definition: gpcb_plugin.cpp:52
#define NEW_GPCB_UNIT_CONV
#define OLD_GPCB_UNIT_CONV
#define TEXT_DEFAULT_SIZE
const wxChar *const traceGedaPcbPlugin
Flag to enable GEDA PCB plugin debug output.
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:164
@ F_Paste
Definition: layer_ids.h:101
@ B_Mask
Definition: layer_ids.h:106
@ B_Cu
Definition: layer_ids.h:95
@ F_Mask
Definition: layer_ids.h:107
@ B_Paste
Definition: layer_ids.h:100
@ F_SilkS
Definition: layer_ids.h:104
@ F_Cu
Definition: layer_ids.h:64
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
@ SMD
Smd pad, appears on the solder paste layer (default)
const double IU_PER_MILS
Definition: base_units.h:78
constexpr int delta
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Definition: trigo.cpp:183
double EuclideanNorm(const VECTOR2I &vector)
Definition: trigo.h:129
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:85
VECTOR2< int > VECTOR2I
Definition: vector2d.h:618

References _, LSET::AllCuMask(), PNS::angle(), ANGLE_180, ANGLE_360, ANGLE_HORIZONTAL, ANGLE_VERTICAL, ARC, B_Cu, B_Mask, B_Paste, CIRCLE, delta, EuclideanNorm(), F_Cu, F_Mask, F_Paste, F_SilkS, LINE_READER::GetSource(), EDA_IU_SCALE::IU_PER_MILS, KiROUND(), LINE_READER::LineNumber(), NEW_GPCB_UNIT_CONV, OLD_GPCB_UNIT_CONV, OVAL, pad, PAD, parseInt(), parseParameters(), pcbIUScale, RADIANS_T, 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(), PCB_SHAPE::SetStroke(), SMD, SOLID, TENTHS_OF_A_DEGREE_T, testFlags(), TEXT_DEFAULT_SIZE, THROW_IO_ERROR, THROW_PARSE_ERROR, traceGedaPcbPlugin, VECTOR2< T >::x, and VECTOR2< T >::y.

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 706 of file gpcb_plugin.cpp.

707{
708 char key;
709 wxString tmp;
710 char* line = aLineReader->Line();
711
712 // Last line already ready in main parser loop.
713 while( *line != 0 )
714 {
715 key = *line;
716 line++;
717
718 switch( key )
719 {
720 case '[':
721 case '(':
722 if( !tmp.IsEmpty() )
723 {
724 aParameterList.Add( tmp );
725 tmp.Clear();
726 }
727
728 tmp.Append( key );
729 aParameterList.Add( tmp );
730 tmp.Clear();
731
732 // Opening delimiter "(" after Element statement. Any other occurrence is part
733 // of a keyword definition.
734 if( aParameterList.GetCount() == 1 )
735 {
736 wxLogTrace( traceGedaPcbPlugin, dump( aParameterList ) );
737 return;
738 }
739
740 break;
741
742 case ']':
743 case ')':
744 if( !tmp.IsEmpty() )
745 {
746 aParameterList.Add( tmp );
747 tmp.Clear();
748 }
749
750 tmp.Append( key );
751 aParameterList.Add( tmp );
752 wxLogTrace( traceGedaPcbPlugin, dump( aParameterList ) );
753 return;
754
755 case '\n':
756 case '\r':
757 // Element descriptions can span multiple lines.
758 line = aLineReader->ReadLine();
760
761 case '\t':
762 case ' ':
763 if( !tmp.IsEmpty() )
764 {
765 aParameterList.Add( tmp );
766 tmp.Clear();
767 }
768
769 break;
770
771 case '"':
772 // Handle empty quotes.
773 if( *line == '"' )
774 {
775 line++;
776 tmp.Clear();
777 aParameterList.Add( wxEmptyString );
778 break;
779 }
780
781 while( *line != 0 )
782 {
783 key = *line;
784 line++;
785
786 if( key == '"' )
787 {
788 aParameterList.Add( tmp );
789 tmp.Clear();
790 break;
791 }
792 else
793 {
794 tmp.Append( key );
795 }
796 }
797
798 break;
799
800 case '#':
801 line = aLineReader->ReadLine();
802 break;
803
804 default:
805 tmp.Append( key );
806 break;
807 }
808 }
809}
char * Line() const
Return a pointer to the last line that was read in.
Definition: richio.h:117
#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.

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}

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 812 of file gpcb_plugin.cpp.

813{
814 wxString number;
815
816 if( aFlag.StartsWith( wxT( "0x" ), &number ) || aFlag.StartsWith( wxT( "0X" ), &number ) )
817 {
818 long lflags;
819
820 if( number.ToLong( &lflags, 16 ) && ( lflags & aMask ) )
821 return true;
822 }
823 else if( aFlag.Contains( aName ) )
824 {
825 return true;
826 }
827
828 return false;
829}

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: