KiCad PCB EDA Suite
PCB_PARSER Class Reference

Read a Pcbnew s-expression formatted LINE_READER object and returns the appropriate BOARD_ITEM object. More...

#include <pcb_parser.h>

Inheritance diagram for PCB_PARSER:

Classes

struct  GROUP_INFO
 

Public Member Functions

 PCB_PARSER (LINE_READER *aReader=nullptr)
 
LINE_READERSetLineReader (LINE_READER *aReader)
 Set aLineReader into the parser, and returns the previous one, if any. More...
 
void SetBoard (BOARD *aBoard)
 
void SetProgressReporter (PROGRESS_REPORTER *aProgressReporter, const LINE_READER *aLineReader, unsigned aLineCount)
 
BOARD_ITEMParse ()
 
FOOTPRINTparseFOOTPRINT (wxArrayString *aInitialComments=nullptr)
 
bool IsTooRecent ()
 Return whether a version number, if any was parsed, was too recent. More...
 
wxString GetRequiredVersion ()
 Return a string representing the version of KiCad required to open this file. More...
 

Private Types

typedef std::unordered_map< std::string, PCB_LAYER_IDLAYER_ID_MAP
 
typedef std::unordered_map< std::string, LSETLSET_MAP
 
typedef std::unordered_map< wxString, KIIDKIID_MAP
 

Private Member Functions

int getNetCode (int aNetCode)
 < Convert net code using the mapping table if available, otherwise returns unchanged net code if < 0 or if is is out of range More...
 
void pushValueIntoMap (int aIndex, int aValue)
 Add aValue value in netcode mapping (m_netCodes) at aIndex. More...
 
void init ()
 Clear and re-establish m_layerMap with the default layer names. More...
 
void checkpoint ()
 
void createOldLayerMapping (std::unordered_map< std::string, std::string > &aMap)
 Create a mapping from the (short-lived) bug where layer names were translated. More...
 
void skipCurrent ()
 Skip the current token level, i.e search for the RIGHT parenthesis which closes the current description. More...
 
void parseHeader ()
 
void parseGeneralSection ()
 
void parsePAGE_INFO ()
 
void parseTITLE_BLOCK ()
 
void parseLayers ()
 
void parseLayer (LAYER *aLayer)
 
void parseBoardStackup ()
 
void parseSetup ()
 
void parseDefaults (BOARD_DESIGN_SETTINGS &aSettings)
 
void parseDefaultTextDims (BOARD_DESIGN_SETTINGS &aSettings, int aLayer)
 
void parseNETINFO_ITEM ()
 
void parseNETCLASS ()
 
PCB_SHAPEparsePCB_SHAPE ()
 
PCB_TEXTparsePCB_TEXT ()
 
PCB_DIMENSION_BASEparseDIMENSION ()
 
FOOTPRINTparseFOOTPRINT_unchecked (wxArrayString *aInitialComments=nullptr)
 
FP_TEXTparseFP_TEXT ()
 
FP_SHAPEparseFP_SHAPE ()
 
PADparsePAD (FOOTPRINT *aParent=nullptr)
 
bool parsePAD_option (PAD *aPad)
 
PCB_ARCparseARC ()
 
PCB_TRACKparsePCB_TRACK ()
 
PCB_VIAparsePCB_VIA ()
 
ZONEparseZONE (BOARD_ITEM_CONTAINER *aParent)
 
PCB_TARGETparsePCB_TARGET ()
 
BOARDparseBOARD ()
 
void parseGROUP (BOARD_ITEM *aParent)
 
BOARDparseBOARD_unchecked ()
 
template<class T , class M >
lookUpLayer (const M &aMap)
 Parse the current token for the layer definition of a BOARD_ITEM object. More...
 
PCB_LAYER_ID parseBoardItemLayer ()
 Parse the layer definition of a BOARD_ITEM object. More...
 
LSET parseBoardItemLayersAsMask ()
 Parse the layers definition of a BOARD_ITEM object. More...
 
wxPoint parseXY ()
 Parse a coordinate pair (xy X Y) in board units (mm). More...
 
void parseXY (int *aX, int *aY)
 
std::pair< wxString, wxString > parseProperty ()
 
void parseOutlinePoints (SHAPE_LINE_CHAIN &aPoly)
 Parses possible outline points and stores them into aPoly. More...
 
void parseEDA_TEXT (EDA_TEXT *aText)
 Parse the common settings for any object derived from EDA_TEXT. More...
 
FP_3DMODELparse3DModel ()
 
double parseDouble ()
 Parse the current token as an ASCII numeric string with possible leading whitespace into a double precision floating point number. More...
 
double parseDouble (const char *aExpected)
 
double parseDouble (PCB_KEYS_T::T aToken)
 
double parseAngle ()
 Parse angles into deci-degrees. More...
 
double parseAngle (const char *aExpected)
 
int parseBoardUnits ()
 
int parseBoardUnits (const char *aExpected)
 
int parseBoardUnits (PCB_KEYS_T::T aToken)
 
int parseInt ()
 
int parseInt (const char *aExpected)
 
long parseHex ()
 
bool parseBool ()
 
KIID CurStrToKIID ()
 
void resolveGroups (BOARD_ITEM *aParent)
 Called after parsing a footprint definition or board to build the group membership lists. More...
 

Private Attributes

BOARDm_board
 
LAYER_ID_MAP m_layerIndices
 map layer name to it's index More...
 
LSET_MAP m_layerMasks
 map layer names to their masks More...
 
std::set< wxString > m_undefinedLayers
 set of layers not defined in layers section More...
 
std::vector< int > m_netCodes
 net codes mapping for boards being loaded More...
 
bool m_tooRecent
 true if version parses as later than supported More...
 
int m_requiredVersion
 set to the KiCad format version this board requires More...
 
bool m_resetKIIDs
 reading into an existing board; reset UUIDs More...
 
KIID_MAP m_resetKIIDMap
 
bool m_showLegacyZoneWarning
 
PROGRESS_REPORTERm_progressReporter
 optional; may be nullptr More...
 
const LINE_READERm_lineReader
 for progress reporting More...
 
unsigned m_lastProgressLine
 
unsigned m_lineCount
 for progress reporting More...
 
std::vector< GROUP_INFOm_groupInfos
 

Detailed Description

Read a Pcbnew s-expression formatted LINE_READER object and returns the appropriate BOARD_ITEM object.

Definition at line 71 of file pcb_parser.h.

Member Typedef Documentation

◆ KIID_MAP

typedef std::unordered_map< wxString, KIID > PCB_PARSER::KIID_MAP
private

Definition at line 365 of file pcb_parser.h.

◆ LAYER_ID_MAP

typedef std::unordered_map< std::string, PCB_LAYER_ID > PCB_PARSER::LAYER_ID_MAP
private

Definition at line 363 of file pcb_parser.h.

◆ LSET_MAP

typedef std::unordered_map< std::string, LSET > PCB_PARSER::LSET_MAP
private

Definition at line 364 of file pcb_parser.h.

Constructor & Destructor Documentation

◆ PCB_PARSER()

PCB_PARSER::PCB_PARSER ( LINE_READER aReader = nullptr)
inline

Definition at line 74 of file pcb_parser.h.

74  :
75  PCB_LEXER( aReader ),
76  m_board( nullptr ),
77  m_resetKIIDs( false ),
78  m_progressReporter( nullptr ),
79  m_lineReader( nullptr ),
80  m_lastProgressLine( 0 ),
81  m_lineCount( 0 )
82  {
83  init();
84  }
unsigned m_lineCount
for progress reporting
Definition: pcb_parser.h:384
const LINE_READER * m_lineReader
for progress reporting
Definition: pcb_parser.h:382
PROGRESS_REPORTER * m_progressReporter
optional; may be nullptr
Definition: pcb_parser.h:381
BOARD * m_board
Definition: pcb_parser.h:367
void init()
Clear and re-establish m_layerMap with the default layer names.
Definition: pcb_parser.cpp:67
unsigned m_lastProgressLine
Definition: pcb_parser.h:383
bool m_resetKIIDs
reading into an existing board; reset UUIDs
Definition: pcb_parser.h:374

References init().

Member Function Documentation

◆ checkpoint()

void PCB_PARSER::checkpoint ( )
private

Definition at line 112 of file pcb_parser.cpp.

113 {
114  const unsigned PROGRESS_DELTA = 250;
115 
116  if( m_progressReporter )
117  {
118  unsigned curLine = m_lineReader->LineNumber();
119 
120  if( curLine > m_lastProgressLine + PROGRESS_DELTA )
121  {
122  m_progressReporter->SetCurrentProgress( ( (double) curLine )
123  / std::max( 1U, m_lineCount ) );
124 
126  THROW_IO_ERROR( ( "Open cancelled by user." ) );
127 
128  m_lastProgressLine = curLine;
129  }
130  }
131 }
unsigned m_lineCount
for progress reporting
Definition: pcb_parser.h:384
const LINE_READER * m_lineReader
for progress reporting
Definition: pcb_parser.h:382
PROGRESS_REPORTER * m_progressReporter
optional; may be nullptr
Definition: pcb_parser.h:381
virtual unsigned LineNumber() const
Return the line number of the last line read from this LINE_READER.
Definition: richio.h:135
unsigned m_lastProgressLine
Definition: pcb_parser.h:383
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
virtual void SetCurrentProgress(double aProgress)=0
Set the progress value to aProgress (0..1).

References THROW_IO_ERROR.

◆ createOldLayerMapping()

void PCB_PARSER::createOldLayerMapping ( std::unordered_map< std::string, std::string > &  aMap)
private

Create a mapping from the (short-lived) bug where layer names were translated.

Todo:
Remove this once we support custom layer names.
Parameters
aMapstring mapping from translated to English layer names.

Definition at line 1535 of file pcb_parser.cpp.

1536 {
1537  // N.B. This mapping only includes Italian, Polish and French as they were the only languages
1538  // that mapped the layer names as of cc2022b1ac739aa673d2a0b7a2047638aa7a47b3 (kicad-i18n)
1539  // when the bug was fixed in KiCad source.
1540 
1541  // Italian
1542  aMap["Adesivo.Retro"] = "B.Adhes";
1543  aMap["Adesivo.Fronte"] = "F.Adhes";
1544  aMap["Pasta.Retro"] = "B.Paste";
1545  aMap["Pasta.Fronte"] = "F.Paste";
1546  aMap["Serigrafia.Retro"] = "B.SilkS";
1547  aMap["Serigrafia.Fronte"] = "F.SilkS";
1548  aMap["Maschera.Retro"] = "B.Mask";
1549  aMap["Maschera.Fronte"] = "F.Mask";
1550  aMap["Grafica"] = "Dwgs.User";
1551  aMap["Commenti"] = "Cmts.User";
1552  aMap["Eco1"] = "Eco1.User";
1553  aMap["Eco2"] = "Eco2.User";
1554  aMap["Contorno.scheda"] = "Edge.Cuts";
1555 
1556  // Polish
1557  aMap["Kleju_Dolna"] = "B.Adhes";
1558  aMap["Kleju_Gorna"] = "F.Adhes";
1559  aMap["Pasty_Dolna"] = "B.Paste";
1560  aMap["Pasty_Gorna"] = "F.Paste";
1561  aMap["Opisowa_Dolna"] = "B.SilkS";
1562  aMap["Opisowa_Gorna"] = "F.SilkS";
1563  aMap["Maski_Dolna"] = "B.Mask";
1564  aMap["Maski_Gorna"] = "F.Mask";
1565  aMap["Rysunkowa"] = "Dwgs.User";
1566  aMap["Komentarzy"] = "Cmts.User";
1567  aMap["ECO1"] = "Eco1.User";
1568  aMap["ECO2"] = "Eco2.User";
1569  aMap["Krawedziowa"] = "Edge.Cuts";
1570 
1571  // French
1572  aMap["Dessous.Adhes"] = "B.Adhes";
1573  aMap["Dessus.Adhes"] = "F.Adhes";
1574  aMap["Dessous.Pate"] = "B.Paste";
1575  aMap["Dessus.Pate"] = "F.Paste";
1576  aMap["Dessous.SilkS"] = "B.SilkS";
1577  aMap["Dessus.SilkS"] = "F.SilkS";
1578  aMap["Dessous.Masque"] = "B.Mask";
1579  aMap["Dessus.Masque"] = "F.Mask";
1580  aMap["Dessin.User"] = "Dwgs.User";
1581  aMap["Contours.Ci"] = "Edge.Cuts";
1582 }

◆ CurStrToKIID()

KIID PCB_PARSER::CurStrToKIID ( )
private

Definition at line 5537 of file pcb_parser.cpp.

5538 {
5539  KIID aId;
5540 
5541  if( m_resetKIIDs )
5542  {
5543  aId = KIID();
5544  m_resetKIIDMap.insert( std::make_pair( CurStr(), aId ) );
5545  }
5546  else
5547  {
5548  aId = KIID( CurStr() );
5549  }
5550 
5551  return aId;
5552 }
KIID_MAP m_resetKIIDMap
Definition: pcb_parser.h:377
Definition: kiid.h:44
bool m_resetKIIDs
reading into an existing board; reset UUIDs
Definition: pcb_parser.h:374

◆ getNetCode()

int PCB_PARSER::getNetCode ( int  aNetCode)
inlineprivate

< Convert net code using the mapping table if available, otherwise returns unchanged net code if < 0 or if is is out of range

Definition at line 146 of file pcb_parser.h.

147  {
148  if( ( aNetCode >= 0 ) && ( aNetCode < (int) m_netCodes.size() ) )
149  return m_netCodes[aNetCode];
150 
151  return aNetCode;
152  }
std::vector< int > m_netCodes
net codes mapping for boards being loaded
Definition: pcb_parser.h:371

References m_netCodes.

◆ GetRequiredVersion()

wxString PCB_PARSER::GetRequiredVersion ( )

Return a string representing the version of KiCad required to open this file.

Not particularly meaningful if IsTooRecent() returns false.

Definition at line 246 of file pcb_parser.cpp.

247 {
248  int year, month, day;
249 
250  year = m_requiredVersion / 10000;
251  month = ( m_requiredVersion / 100 ) - ( year * 100 );
252  day = m_requiredVersion - ( year * 10000 ) - ( month * 100 );
253 
254  // wx throws an assertion, not a catchable exception, when the date is invalid.
255  // User input shouldn't give wx asserts, so check manually and throw a proper
256  // error instead
257  if( day <= 0 || month <= 0 || month > 12 ||
258  day > wxDateTime::GetNumberOfDays( (wxDateTime::Month)( month - 1 ), year ) )
259  {
260  wxString err;
261  err.Printf( _( "Cannot interpret date code %d" ), m_requiredVersion );
262  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
263  }
264 
265  wxDateTime date( day, (wxDateTime::Month)( month - 1 ), year, 0, 0, 0, 0 );
266  return date.FormatDate();
267 }
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:164
#define _(s)
int m_requiredVersion
set to the KiCad format version this board requires
Definition: pcb_parser.h:373

References _, and THROW_PARSE_ERROR.

Referenced by PCB_IO::DoLoad(), CLIPBOARD_IO::Load(), and PCB_IO::Parse().

◆ init()

void PCB_PARSER::init ( )
private

Clear and re-establish m_layerMap with the default layer names.

m_layerMap will have some of its entries overwritten whenever a (new) board is encountered.

Definition at line 67 of file pcb_parser.cpp.

68 {
70  m_tooRecent = false;
72  m_layerIndices.clear();
73  m_layerMasks.clear();
74  m_resetKIIDMap.clear();
75 
76  // Add untranslated default (i.e. English) layernames.
77  // Some may be overridden later if parsing a board rather than a footprint.
78  // The English name will survive if parsing only a footprint.
79  for( LAYER_NUM layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer )
80  {
81  std::string untranslated = TO_UTF8( wxString( LSET::Name( PCB_LAYER_ID( layer ) ) ) );
82 
83  m_layerIndices[ untranslated ] = PCB_LAYER_ID( layer );
84  m_layerMasks[ untranslated ] = LSET( PCB_LAYER_ID( layer ) );
85  }
86 
87  m_layerMasks[ "*.Cu" ] = LSET::AllCuMask();
88  m_layerMasks[ "*In.Cu" ] = LSET::InternalCuMask();
89  m_layerMasks[ "F&B.Cu" ] = LSET( 2, F_Cu, B_Cu );
90  m_layerMasks[ "*.Adhes" ] = LSET( 2, B_Adhes, F_Adhes );
91  m_layerMasks[ "*.Paste" ] = LSET( 2, B_Paste, F_Paste );
92  m_layerMasks[ "*.Mask" ] = LSET( 2, B_Mask, F_Mask );
93  m_layerMasks[ "*.SilkS" ] = LSET( 2, B_SilkS, F_SilkS );
94  m_layerMasks[ "*.Fab" ] = LSET( 2, B_Fab, F_Fab );
95  m_layerMasks[ "*.CrtYd" ] = LSET( 2, B_CrtYd, F_CrtYd );
96 
97  // This is for the first pretty & *.kicad_pcb formats, which had
98  // Inner1_Cu - Inner14_Cu with the numbering sequence
99  // reversed from the subsequent format's In1_Cu - In30_Cu numbering scheme.
100  // The newer format brought in an additional 16 Cu layers and flipped the cu stack but
101  // kept the gap between one of the outside layers and the last cu internal.
102 
103  for( int i=1; i<=14; ++i )
104  {
105  std::string key = StrPrintf( "Inner%d.Cu", i );
106 
107  m_layerMasks[ key ] = LSET( PCB_LAYER_ID( In15_Cu - i ) );
108  }
109 }
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:750
int LAYER_NUM
This can be replaced with int and removed.
Definition: layer_ids.h:41
bool m_tooRecent
true if version parses as later than supported
Definition: pcb_parser.h:372
KIID_MAP m_resetKIIDMap
Definition: pcb_parser.h:377
int StrPrintf(std::string *result, const char *format,...)
This is like sprintf() but the output is appended to a std::string instead of to a character array.
Definition: richio.cpp:79
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:96
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:504
static const wxChar * Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition: lset.cpp:82
static LSET InternalCuMask()
Return a complete set of internal copper layers which is all Cu layers except F_Cu and B_Cu.
Definition: lset.cpp:710
bool m_showLegacyZoneWarning
Definition: pcb_parser.h:379
int m_requiredVersion
set to the KiCad format version this board requires
Definition: pcb_parser.h:373
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:65
Definition: layer_ids.h:71
LAYER_ID_MAP m_layerIndices
map layer name to it's index
Definition: pcb_parser.h:368
LSET_MAP m_layerMasks
map layer names to their masks
Definition: pcb_parser.h:369

References LSET::AllCuMask(), B_Adhes, B_CrtYd, B_Cu, B_Fab, B_Mask, B_Paste, B_SilkS, F_Adhes, F_CrtYd, F_Cu, F_Fab, F_Mask, F_Paste, F_SilkS, In15_Cu, LSET::InternalCuMask(), LSET::Name(), PCB_LAYER_ID_COUNT, StrPrintf(), and TO_UTF8.

Referenced by PCB_PARSER(), and SetBoard().

◆ IsTooRecent()

bool PCB_PARSER::IsTooRecent ( )
inline

Return whether a version number, if any was parsed, was too recent.

Definition at line 132 of file pcb_parser.h.

133  {
134  return m_tooRecent;
135  }
bool m_tooRecent
true if version parses as later than supported
Definition: pcb_parser.h:372

References m_tooRecent.

Referenced by PCB_IO::DoLoad(), CLIPBOARD_IO::Load(), and PCB_IO::Parse().

◆ lookUpLayer()

template<class T , class M >
T PCB_PARSER::lookUpLayer ( const M &  aMap)
private

Parse the current token for the layer definition of a BOARD_ITEM object.

Parameters
aMapis the LAYER_{NUM|MSK}_MAP to use for the lookup.
Returns
The result of the parsed BOARD_ITEM layer or set designator.
Exceptions
IO_ERRORif the layer is not valid.
PARSE_ERRORif the layer syntax is incorrect.

Definition at line 1717 of file pcb_parser.cpp.

1718 {
1719  // avoid constructing another std::string, use lexer's directly
1720  typename M::const_iterator it = aMap.find( curText );
1721 
1722  if( it == aMap.end() )
1723  {
1724  m_undefinedLayers.insert( curText );
1725  return Rescue;
1726  }
1727 
1728  // Some files may have saved items to the Rescue Layer due to an issue in v5
1729  if( it->second == Rescue )
1730  m_undefinedLayers.insert( curText );
1731 
1732  return it->second;
1733 }
std::set< wxString > m_undefinedLayers
set of layers not defined in layers section
Definition: pcb_parser.h:370

References Rescue.

◆ Parse()

BOARD_ITEM * PCB_PARSER::Parse ( )

Definition at line 626 of file pcb_parser.cpp.

627 {
628  T token;
629  BOARD_ITEM* item;
630  LOCALE_IO toggle;
631 
632  m_groupInfos.clear();
633 
634  // FOOTPRINTS can be prefixed with an initial block of single line comments and these are
635  // kept for Format() so they round trip in s-expression form. BOARDs might eventually do
636  // the same, but currently do not.
637  std::unique_ptr<wxArrayString> initial_comments( ReadCommentLines() );
638 
639  token = CurTok();
640 
641  if( token == -1 ) // EOF
642  Unexpected( token );
643 
644  if( token != T_LEFT )
645  Expecting( T_LEFT );
646 
647  switch( NextTok() )
648  {
649  case T_kicad_pcb:
650  if( m_board == nullptr )
651  m_board = new BOARD();
652 
653  item = (BOARD_ITEM*) parseBOARD();
654  break;
655 
656  case T_module: // legacy token
657  case T_footprint:
658  item = (BOARD_ITEM*) parseFOOTPRINT( initial_comments.release() );
659 
660  // Locking a footprint has no meaning outside of a board.
661  item->SetLocked( false );
662  break;
663 
664  default:
665  wxString err;
666  err.Printf( _( "Unknown token '%s'" ), FromUTF8() );
667  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
668  }
669 
670  resolveGroups( item );
671 
672  return item;
673 }
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:40
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:49
FOOTPRINT * parseFOOTPRINT(wxArrayString *aInitialComments=nullptr)
BOARD * parseBOARD()
Definition: pcb_parser.cpp:676
virtual void SetLocked(bool aLocked)
Modify the 'lock' status for of the item.
Definition: board_item.h:221
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:164
std::vector< GROUP_INFO > m_groupInfos
Definition: pcb_parser.h:399
#define _(s)
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:190
BOARD * m_board
Definition: pcb_parser.h:367
void resolveGroups(BOARD_ITEM *aParent)
Called after parsing a footprint definition or board to build the group membership lists.
Definition: pcb_parser.cpp:936

References _, BOARD_ITEM::SetLocked(), and THROW_PARSE_ERROR.

Referenced by PCB_IO::DoLoad(), CLIPBOARD_IO::Load(), FP_CACHE::Load(), parse(), PCB_IO::Parse(), KI_TEST::ReadBoardItemFromFile(), and KI_TEST::ReadBoardItemFromStream().

◆ parse3DModel()

FP_3DMODEL * PCB_PARSER::parse3DModel ( )
private

Definition at line 520 of file pcb_parser.cpp.

521 {
522  wxCHECK_MSG( CurTok() == T_model, nullptr,
523  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as FP_3DMODEL." ) );
524 
525  T token;
526 
527  FP_3DMODEL* n3D = new FP_3DMODEL;
528  NeedSYMBOLorNUMBER();
529  n3D->m_Filename = FromUTF8();
530 
531  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
532  {
533  if( token == T_LEFT )
534  token = NextTok();
535 
536  switch( token )
537  {
538  case T_at:
539  NeedLEFT();
540  token = NextTok();
541 
542  if( token != T_xyz )
543  Expecting( T_xyz );
544 
545  /* Note:
546  * Prior to KiCad v5, model offset was designated by "at",
547  * and the units were in inches.
548  * Now we use mm, but support reading of legacy files
549  */
550 
551  n3D->m_Offset.x = parseDouble( "x value" ) * 25.4f;
552  n3D->m_Offset.y = parseDouble( "y value" ) * 25.4f;
553  n3D->m_Offset.z = parseDouble( "z value" ) * 25.4f;
554 
555  NeedRIGHT(); // xyz
556  NeedRIGHT(); // at
557  break;
558 
559  case T_hide:
560  n3D->m_Show = false;
561  break;
562 
563  case T_opacity:
564  n3D->m_Opacity = parseDouble( "opacity value" );
565  NeedRIGHT();
566  break;
567 
568  case T_offset:
569  NeedLEFT();
570  token = NextTok();
571 
572  if( token != T_xyz )
573  Expecting( T_xyz );
574 
575  /*
576  * 3D model offset is in mm
577  */
578  n3D->m_Offset.x = parseDouble( "x value" );
579  n3D->m_Offset.y = parseDouble( "y value" );
580  n3D->m_Offset.z = parseDouble( "z value" );
581 
582  NeedRIGHT(); // xyz
583  NeedRIGHT(); // offset
584  break;
585 
586  case T_scale:
587  NeedLEFT();
588  token = NextTok();
589 
590  if( token != T_xyz )
591  Expecting( T_xyz );
592 
593  n3D->m_Scale.x = parseDouble( "x value" );
594  n3D->m_Scale.y = parseDouble( "y value" );
595  n3D->m_Scale.z = parseDouble( "z value" );
596 
597  NeedRIGHT(); // xyz
598  NeedRIGHT(); // scale
599  break;
600 
601  case T_rotate:
602  NeedLEFT();
603  token = NextTok();
604 
605  if( token != T_xyz )
606  Expecting( T_xyz );
607 
608  n3D->m_Rotation.x = parseDouble( "x value" );
609  n3D->m_Rotation.y = parseDouble( "y value" );
610  n3D->m_Rotation.z = parseDouble( "z value" );
611 
612  NeedRIGHT(); // xyz
613  NeedRIGHT(); // rotate
614  break;
615 
616  default:
617  Expecting( "at, hide, opacity, offset, scale, or rotate" );
618  }
619 
620  }
621 
622  return n3D;
623 }
VECTOR3D m_Offset
3D model offset (mm)
Definition: footprint.h:95
bool m_Show
Include model in rendering.
Definition: footprint.h:98
VECTOR3D m_Scale
3D model scaling factor (dimensionless)
Definition: footprint.h:93
double m_Opacity
Definition: footprint.h:96
wxString m_Filename
The 3D shape filename in 3D library.
Definition: footprint.h:97
VECTOR3D m_Rotation
3D model rotation (degrees)
Definition: footprint.h:94
double parseDouble()
Parse the current token as an ASCII numeric string with possible leading whitespace into a double pre...
Definition: pcb_parser.cpp:167

References FP_3DMODEL::m_Filename, FP_3DMODEL::m_Offset, FP_3DMODEL::m_Opacity, FP_3DMODEL::m_Rotation, FP_3DMODEL::m_Scale, FP_3DMODEL::m_Show, parseDouble(), FP_3DMODEL::VECTOR3D::x, FP_3DMODEL::VECTOR3D::y, and FP_3DMODEL::VECTOR3D::z.

◆ parseAngle() [1/2]

double PCB_PARSER::parseAngle ( )
inlineprivate

Parse angles into deci-degrees.

Definition at line 317 of file pcb_parser.h.

317 { return parseDouble() * 10.0; }
double parseDouble()
Parse the current token as an ASCII numeric string with possible leading whitespace into a double pre...
Definition: pcb_parser.cpp:167

References parseDouble().

◆ parseAngle() [2/2]

double PCB_PARSER::parseAngle ( const char *  aExpected)
inlineprivate

Definition at line 319 of file pcb_parser.h.

320  {
321  return parseDouble( aExpected ) * 10.0;
322  }
double parseDouble()
Parse the current token as an ASCII numeric string with possible leading whitespace into a double pre...
Definition: pcb_parser.cpp:167

References parseDouble().

◆ parseARC()

PCB_ARC * PCB_PARSER::parseARC ( )
private

Definition at line 4621 of file pcb_parser.cpp.

4622 {
4623  wxCHECK_MSG( CurTok() == T_arc, nullptr,
4624  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as ARC." ) );
4625 
4626  wxPoint pt;
4627  T token;
4628 
4629  std::unique_ptr<PCB_ARC> arc = std::make_unique<PCB_ARC>( m_board );
4630 
4631  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4632  {
4633  if( token == T_locked )
4634  {
4635  arc->SetLocked( true );
4636  token = NextTok();
4637  }
4638 
4639  if( token != T_LEFT )
4640  Expecting( T_LEFT );
4641 
4642  token = NextTok();
4643 
4644  switch( token )
4645  {
4646  case T_start:
4647  pt.x = parseBoardUnits( "start x" );
4648  pt.y = parseBoardUnits( "start y" );
4649  arc->SetStart( pt );
4650  break;
4651 
4652  case T_mid:
4653  pt.x = parseBoardUnits( "mid x" );
4654  pt.y = parseBoardUnits( "mid y" );
4655  arc->SetMid( pt );
4656  break;
4657 
4658  case T_end:
4659  pt.x = parseBoardUnits( "end x" );
4660  pt.y = parseBoardUnits( "end y" );
4661  arc->SetEnd( pt );
4662  break;
4663 
4664  case T_width:
4665  arc->SetWidth( parseBoardUnits( "width" ) );
4666  break;
4667 
4668  case T_layer:
4669  arc->SetLayer( parseBoardItemLayer() );
4670  break;
4671 
4672  case T_net:
4673  if( !arc->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
4675  _( "Invalid net ID in\nfile: '%s'\nline: %d\noffset: %d." ), CurSource(),
4676  CurLineNumber(), CurOffset() ) );
4677  break;
4678 
4679  case T_tstamp:
4680  NextTok();
4681  const_cast<KIID&>( arc->m_Uuid ) = CurStrToKIID();
4682  break;
4683 
4684  // We continue to parse the status field but it is no longer written
4685  case T_status:
4686  arc->SetStatus( static_cast<EDA_ITEM_FLAGS>( parseHex() ) );
4687  break;
4688 
4689  // Continue to process "(locked)" format which was output during 5.99 development
4690  case T_locked:
4691  arc->SetLocked( true );
4692  break;
4693 
4694  default:
4695  Expecting( "start, mid, end, width, layer, net, tstamp, or status" );
4696  }
4697 
4698  NeedRIGHT();
4699  }
4700 
4701  return arc.release();
4702 }
KIID CurStrToKIID()
int parseBoardUnits()
Definition: pcb_parser.cpp:197
PCB_LAYER_ID parseBoardItemLayer()
Parse the layer definition of a BOARD_ITEM object.
#define _(s)
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
int getNetCode(int aNetCode)
< Convert net code using the mapping table if available, otherwise returns unchanged net code if < 0 ...
Definition: pcb_parser.h:146
BOARD * m_board
Definition: pcb_parser.h:367
long parseHex()
Definition: pcb_parser.h:344
int parseInt()
Definition: pcb_parser.h:333
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38

References _, Format(), parseHex(), parseInt(), and THROW_IO_ERROR.

◆ parseBOARD()

BOARD * PCB_PARSER::parseBOARD ( )
private

Definition at line 676 of file pcb_parser.cpp.

677 {
678  try
679  {
680  return parseBOARD_unchecked();
681  }
682  catch( const PARSE_ERROR& parse_error )
683  {
684  if( m_tooRecent )
685  throw FUTURE_FORMAT_ERROR( parse_error, GetRequiredVersion() );
686  else
687  throw;
688  }
689 }
bool m_tooRecent
true if version parses as later than supported
Definition: pcb_parser.h:372
wxString GetRequiredVersion()
Return a string representing the version of KiCad required to open this file.
Definition: pcb_parser.cpp:246
BOARD * parseBOARD_unchecked()
Definition: pcb_parser.cpp:692
A filename or source description, a problem input line, a line number, a byte offset,...
Definition: ki_exception.h:118
Variant of PARSE_ERROR indicating that a syntax or related error was likely caused by a file generate...
Definition: ki_exception.h:174

◆ parseBOARD_unchecked()

BOARD * PCB_PARSER::parseBOARD_unchecked ( )
private

Definition at line 692 of file pcb_parser.cpp.

693 {
694  T token;
695  std::map<wxString, wxString> properties;
696 
697  parseHeader();
698 
699  std::vector<BOARD_ITEM*> bulkAddedItems;
700  BOARD_ITEM* item = nullptr;
701 
702  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
703  {
704  checkpoint();
705 
706  if( token != T_LEFT )
707  Expecting( T_LEFT );
708 
709  token = NextTok();
710 
711  if( token == T_page && m_requiredVersion <= 20200119 )
712  token = T_paper;
713 
714  switch( token )
715  {
716  case T_host: // legacy token
717  NeedSYMBOL();
718  m_board->SetGenerator( FromUTF8() );
719 
720  // Older formats included build data
722  NeedSYMBOL();
723 
724  NeedRIGHT();
725  break;
726 
727  case T_generator:
728  NeedSYMBOL();
729  m_board->SetGenerator( FromUTF8() );
730  NeedRIGHT();
731  break;
732 
733  case T_general:
735  break;
736 
737  case T_paper:
738  parsePAGE_INFO();
739  break;
740 
741  case T_title_block:
743  break;
744 
745  case T_layers:
746  parseLayers();
747  break;
748 
749  case T_setup:
750  parseSetup();
751  break;
752 
753  case T_property:
754  properties.insert( parseProperty() );
755  break;
756 
757  case T_net:
759  break;
760 
761  case T_net_class:
762  parseNETCLASS();
764  break;
765 
766  case T_gr_arc:
767  case T_gr_curve:
768  case T_gr_line:
769  case T_gr_poly:
770  case T_gr_circle:
771  case T_gr_rect:
772  item = parsePCB_SHAPE();
774  bulkAddedItems.push_back( item );
775  break;
776 
777  case T_gr_text:
778  item = parsePCB_TEXT();
780  bulkAddedItems.push_back( item );
781  break;
782 
783  case T_dimension:
784  item = parseDIMENSION();
786  bulkAddedItems.push_back( item );
787  break;
788 
789  case T_module: // legacy token
790  case T_footprint:
791  item = parseFOOTPRINT();
793  bulkAddedItems.push_back( item );
794  break;
795 
796  case T_segment:
797  item = parsePCB_TRACK();
799  bulkAddedItems.push_back( item );
800  break;
801 
802  case T_arc:
803  item = parseARC();
805  bulkAddedItems.push_back( item );
806  break;
807 
808  case T_group:
809  parseGROUP( m_board );
810  break;
811 
812  case T_via:
813  item = parsePCB_VIA();
815  bulkAddedItems.push_back( item );
816  break;
817 
818  case T_zone:
819  item = parseZONE( m_board );
821  bulkAddedItems.push_back( item );
822  break;
823 
824  case T_target:
825  item = parsePCB_TARGET();
827  bulkAddedItems.push_back( item );
828  break;
829 
830  default:
831  wxString err;
832  err.Printf( _( "Unknown token '%s'" ), FromUTF8() );
833  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
834  }
835  }
836 
837  if( bulkAddedItems.size() > 0 )
838  m_board->FinalizeBulkAdd( bulkAddedItems );
839 
840  m_board->SetProperties( properties );
841 
842  if( m_undefinedLayers.size() > 0 )
843  {
844  bool deleteItems;
845  std::vector<BOARD_ITEM*> deleteList;
846  wxString msg = wxString::Format( _( "Items found on undefined layers. Do you wish to\n"
847  "rescue them to the User.Comments layer?" ) );
848  wxString details = wxString::Format( _( "Undefined layers:" ) );
849 
850  for( const wxString& undefinedLayer : m_undefinedLayers )
851  details += wxT( "\n " ) + undefinedLayer;
852 
853  wxRichMessageDialog dlg( nullptr, msg, _( "Warning" ),
854  wxYES_NO | wxCANCEL | wxCENTRE | wxICON_WARNING | wxSTAY_ON_TOP );
855  dlg.ShowDetailedText( details );
856  dlg.SetYesNoCancelLabels( _( "Rescue" ), _( "Delete" ), _( "Cancel" ) );
857 
858  switch( dlg.ShowModal() )
859  {
860  case wxID_YES: deleteItems = false; break;
861  case wxID_NO: deleteItems = true; break;
862  case wxID_CANCEL:
863  default: THROW_IO_ERROR( wxT( "CANCEL" ) );
864  }
865 
866  auto visitItem = [&]( BOARD_ITEM* curr_item )
867  {
868  if( curr_item->GetLayer() == Rescue )
869  {
870  if( deleteItems )
871  deleteList.push_back( curr_item );
872  else
873  curr_item->SetLayer( Cmts_User );
874  }
875  };
876 
877  for( PCB_TRACK* track : m_board->Tracks() )
878  {
879  if( track->Type() == PCB_VIA_T )
880  {
881  PCB_VIA* via = static_cast<PCB_VIA*>( track );
882  PCB_LAYER_ID top_layer, bottom_layer;
883 
884  if( via->GetViaType() == VIATYPE::THROUGH )
885  continue;
886 
887  via->LayerPair( &top_layer, &bottom_layer );
888 
889  if( top_layer == Rescue || bottom_layer == Rescue )
890  {
891  if( deleteItems )
892  deleteList.push_back( via );
893  else
894  {
895  if( top_layer == Rescue )
896  top_layer = F_Cu;
897 
898  if( bottom_layer == Rescue )
899  bottom_layer = B_Cu;
900 
901  via->SetLayerPair( top_layer, bottom_layer );
902  }
903  }
904  }
905  else
906  {
907  visitItem( track );
908  }
909  }
910 
911  for( BOARD_ITEM* zone : m_board->Zones() )
912  visitItem( zone );
913 
914  for( BOARD_ITEM* drawing : m_board->Drawings() )
915  visitItem( drawing );
916 
917  for( FOOTPRINT* fp : m_board->Footprints() )
918  {
919  for( BOARD_ITEM* drawing : fp->GraphicalItems() )
920  visitItem( drawing );
921 
922  for( BOARD_ITEM* zone : fp->Zones() )
923  visitItem( zone );
924  }
925 
926  for( BOARD_ITEM* curr_item : deleteList )
927  m_board->Delete( curr_item );
928 
929  m_undefinedLayers.clear();
930  }
931 
932  return m_board;
933 }
void parseHeader()
PCB_DIMENSION_BASE * parseDIMENSION()
ZONES & Zones()
Definition: board.h:239
bool m_LegacyNetclassesLoaded
True if netclasses were loaded from the file.
Definition: board.h:272
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:49
void SetProperties(const std::map< wxString, wxString > &aProps)
Definition: board.h:259
void parseNETINFO_ITEM()
FOOTPRINT * parseFOOTPRINT(wxArrayString *aInitialComments=nullptr)
void checkpoint()
Definition: pcb_parser.cpp:112
void parseTITLE_BLOCK()
PCB_SHAPE * parsePCB_SHAPE()
PCB_ARC * parseARC()
void parseLayers()
void parsePAGE_INFO()
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT) override
Adds an item to the container.
Definition: board.cpp:608
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:164
PCB_VIA * parsePCB_VIA()
std::pair< wxString, wxString > parseProperty()
Definition: pcb_parser.cpp:387
PCB_TRACK * parsePCB_TRACK()
PCB_TEXT * parsePCB_TEXT()
FOOTPRINTS & Footprints()
Definition: board.h:233
PCB_TARGET * parsePCB_TARGET()
#define _(s)
#define BOARD_FILE_HOST_VERSION
Earlier files than this include the host tag.
void parseNETCLASS()
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
void FinalizeBulkAdd(std::vector< BOARD_ITEM * > &aNewItems)
Must be used if Add() is used using a BULK_x ADD_MODE to generate a change event for listeners.
Definition: board.cpp:698
void parseGROUP(BOARD_ITEM *aParent)
int m_requiredVersion
set to the KiCad format version this board requires
Definition: pcb_parser.h:373
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:65
BOARD * m_board
Definition: pcb_parser.h:367
void parseGeneralSection()
Definition: layer_ids.h:71
void SetGenerator(const wxString &aGenerator)
Definition: board.h:291
virtual void Delete(BOARD_ITEM *aItem)
Removes an item from the container and deletes it.
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
DRAWINGS & Drawings()
Definition: board.h:236
TRACKS & Tracks()
Definition: board.h:230
void parseSetup()
std::set< wxString > m_undefinedLayers
set of layers not defined in layers section
Definition: pcb_parser.h:370
ZONE * parseZONE(BOARD_ITEM_CONTAINER *aParent)

References _, B_Cu, BOARD_FILE_HOST_VERSION, BULK_APPEND, Cmts_User, F_Cu, Format(), PCB_VIA_T, Rescue, THROUGH, THROW_IO_ERROR, THROW_PARSE_ERROR, and via.

◆ parseBoardItemLayer()

PCB_LAYER_ID PCB_PARSER::parseBoardItemLayer ( )
private

Parse the layer definition of a BOARD_ITEM object.

Returns
The index the parsed BOARD_ITEM layer.
Exceptions
IO_ERRORif the layer is not valid.
PARSE_ERRORif the layer syntax is incorrect.

Definition at line 1736 of file pcb_parser.cpp.

1737 {
1738  wxCHECK_MSG( CurTok() == T_layer, UNDEFINED_LAYER,
1739  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as layer." ) );
1740 
1741  NextTok();
1742 
1743  PCB_LAYER_ID layerIndex = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
1744 
1745  // Handle closing ) in object parser.
1746 
1747  return layerIndex;
1748 }
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:65
LAYER_ID_MAP m_layerIndices
map layer name to it's index
Definition: pcb_parser.h:368

References UNDEFINED_LAYER.

◆ parseBoardItemLayersAsMask()

LSET PCB_PARSER::parseBoardItemLayersAsMask ( )
private

Parse the layers definition of a BOARD_ITEM object.

Returns
The mask of layers the parsed BOARD_ITEM is on.
Exceptions
IO_ERRORif any of the layers is not valid.
PARSE_ERRORif the layers syntax is incorrect.

Definition at line 1751 of file pcb_parser.cpp.

1752 {
1753  wxCHECK_MSG( CurTok() == T_layers, LSET(),
1754  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
1755  wxT( " as item layer mask." ) );
1756 
1757  LSET layerMask;
1758 
1759  for( T token = NextTok(); token != T_RIGHT; token = NextTok() )
1760  {
1761  LSET mask = lookUpLayer<LSET>( m_layerMasks );
1762  layerMask |= mask;
1763  }
1764 
1765  return layerMask;
1766 }
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:504
LSET_MAP m_layerMasks
map layer names to their masks
Definition: pcb_parser.h:369

◆ parseBoardStackup()

void PCB_PARSER::parseBoardStackup ( )
private

Definition at line 1314 of file pcb_parser.cpp.

1315 {
1316  T token;
1317  wxString name;
1318  int dielectric_idx = 1; // the index of dielectric layers
1320 
1321  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1322  {
1323  if( CurTok() != T_LEFT )
1324  Expecting( T_LEFT );
1325 
1326  token = NextTok();
1327 
1328  if( token != T_layer )
1329  {
1330  switch( token )
1331  {
1332  case T_copper_finish:
1333  NeedSYMBOL();
1334  stackup.m_FinishType = FromUTF8();
1335  NeedRIGHT();
1336  break;
1337 
1338  case T_edge_plating:
1339  token = NextTok();
1340  stackup.m_EdgePlating = token == T_yes;
1341  NeedRIGHT();
1342  break;
1343 
1344  case T_dielectric_constraints:
1345  token = NextTok();
1346  stackup.m_HasDielectricConstrains = token == T_yes;
1347  NeedRIGHT();
1348  break;
1349 
1350  case T_edge_connector:
1351  token = NextTok();
1353 
1354  if( token == T_yes )
1356  else if( token == T_bevelled )
1358 
1359  NeedRIGHT();
1360  break;
1361 
1362  case T_castellated_pads:
1363  token = NextTok();
1364  stackup.m_CastellatedPads = token == T_yes;
1365  NeedRIGHT();
1366  break;
1367 
1368  default:
1369  // Currently, skip this item if not defined, because the stackup def
1370  // is a moving target
1371  //Expecting( "copper_finish, edge_plating, dielectric_constrains, edge_connector, castellated_pads" );
1372  skipCurrent();
1373  break;
1374  }
1375 
1376  continue;
1377  }
1378 
1379  NeedSYMBOL();
1380  name = FromUTF8();
1381 
1382  // init the layer id. For dielectric, layer id = UNDEFINED_LAYER
1383  PCB_LAYER_ID layerId = m_board->GetLayerID( name );
1384 
1385  // Init the type
1387 
1388  if( layerId == F_SilkS || layerId == B_SilkS )
1389  type = BS_ITEM_TYPE_SILKSCREEN;
1390  else if( layerId == F_Mask || layerId == B_Mask )
1391  type = BS_ITEM_TYPE_SOLDERMASK;
1392  else if( layerId == F_Paste || layerId == B_Paste )
1393  type = BS_ITEM_TYPE_SOLDERPASTE;
1394  else if( layerId == UNDEFINED_LAYER )
1395  type = BS_ITEM_TYPE_DIELECTRIC;
1396  else if( layerId >= F_Cu && layerId <= B_Cu )
1397  type = BS_ITEM_TYPE_COPPER;
1398 
1399  BOARD_STACKUP_ITEM* item = nullptr;
1400 
1401  if( type != BS_ITEM_TYPE_UNDEFINED )
1402  {
1403  item = new BOARD_STACKUP_ITEM( type );
1404  item->SetBrdLayerId( layerId );
1405 
1406  if( type == BS_ITEM_TYPE_DIELECTRIC )
1407  item->SetDielectricLayerId( dielectric_idx++ );
1408 
1409  stackup.Add( item );
1410  }
1411  else
1412  {
1413  Expecting( "layer_name" );
1414  }
1415 
1416  bool has_next_sublayer = true;
1417  int sublayer_idx = 0; // the index of dielectric sub layers
1418  // sublayer 0 is always existing (main sublayer)
1419 
1420  while( has_next_sublayer )
1421  {
1422  has_next_sublayer = false;
1423 
1424  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1425  {
1426  if( token == T_addsublayer )
1427  {
1428  has_next_sublayer = true;
1429  break;
1430  }
1431 
1432  if( token == T_LEFT )
1433  {
1434  token = NextTok();
1435 
1436  switch( token )
1437  {
1438  case T_type:
1439  NeedSYMBOL();
1440  item->SetTypeName( FromUTF8() );
1441  NeedRIGHT();
1442  break;
1443 
1444  case T_thickness:
1445  item->SetThickness( parseBoardUnits( T_thickness ), sublayer_idx );
1446  token = NextTok();
1447 
1448  if( token == T_LEFT )
1449  break;
1450 
1451  if( token == T_locked )
1452  {
1453  // Dielectric thickness can be locked (for impedance controlled layers)
1454  if( type == BS_ITEM_TYPE_DIELECTRIC )
1455  item->SetThicknessLocked( true, sublayer_idx );
1456 
1457  NeedRIGHT();
1458  }
1459 
1460  break;
1461 
1462  case T_material:
1463  NeedSYMBOL();
1464  item->SetMaterial( FromUTF8(), sublayer_idx );
1465  NeedRIGHT();
1466  break;
1467 
1468  case T_epsilon_r:
1469  NextTok();
1470  item->SetEpsilonR( parseDouble(), sublayer_idx );
1471  NeedRIGHT();
1472  break;
1473 
1474  case T_loss_tangent:
1475  NextTok();
1476  item->SetLossTangent( parseDouble(), sublayer_idx );
1477  NeedRIGHT();
1478  break;
1479 
1480  case T_color:
1481  NeedSYMBOL();
1482  name = FromUTF8();
1483 
1484  // Older versions didn't store opacity with custom colors
1485  if( name.StartsWith( "#" ) && m_requiredVersion < 20210824 )
1486  {
1488 
1489  if( item->GetType() == BS_ITEM_TYPE_SOLDERMASK )
1490  color = color.WithAlpha( DEFAULT_SOLDERMASK_OPACITY );
1491  else
1492  color = color.WithAlpha( 1.0 );
1493 
1494  wxColour wx_color = color.ToColour();
1495 
1496  // Open-code wxColour::GetAsString() because 3.0 doesn't handle rgba
1497  name.Printf( wxT("#%02X%02X%02X%02X" ),
1498  wx_color.Red(),
1499  wx_color.Green(),
1500  wx_color.Blue(),
1501  wx_color.Alpha() );
1502  }
1503 
1504  item->SetColor( name );
1505  NeedRIGHT();
1506  break;
1507 
1508  default:
1509  // Currently, skip this item if not defined, because the stackup def
1510  // is a moving target
1511  //Expecting( "type, thickness, material, epsilon_r, loss_tangent, color" );
1512  skipCurrent();
1513  }
1514  }
1515  }
1516 
1517  if( has_next_sublayer ) // Prepare reading the next sublayer description
1518  {
1519  sublayer_idx++;
1520  item->AddDielectricPrms( sublayer_idx );
1521  }
1522  }
1523  }
1524 
1525  if( token != T_RIGHT )
1526  {
1527  Expecting( ")" );
1528  }
1529 
1530  // Success:
1532 }
BOARD_STACKUP_ITEM_TYPE GetType() const
const PCB_LAYER_ID GetLayerID(const wxString &aLayerName) const
Return the ID of a layer.
Definition: board.cpp:340
void SetBrdLayerId(PCB_LAYER_ID aBrdLayerId)
void SetTypeName(const wxString &aName)
BOARD_STACKUP_ITEM_TYPE
Definition: board_stackup.h:40
Manage layers needed to make a physical board.
wxString m_FinishType
The name of external copper finish.
bool m_EdgePlating
True if the edge board is plated.
int color
Definition: DXF_plotter.cpp:57
BS_EDGE_CONNECTOR_CONSTRAINTS m_EdgeConnectorConstraints
If the board has edge connector cards, some constrains can be specified in job file: BS_EDGE_CONNECTO...
bool m_CastellatedPads
True if castellated pads exist.
#define DEFAULT_SOLDERMASK_OPACITY
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:590
int parseBoardUnits()
Definition: pcb_parser.cpp:197
void skipCurrent()
Skip the current token level, i.e search for the RIGHT parenthesis which closes the current descripti...
Definition: pcb_parser.cpp:134
bool m_HasDielectricConstrains
True if some layers have impedance controlled tracks or have specific constrains for micro-wave appli...
BOARD_STACKUP & GetStackupDescriptor()
void SetDielectricLayerId(int aLayerId)
void SetMaterial(const wxString &aName, int aDielectricSubLayer=0)
Manage one layer needed to make a physical board.
Definition: board_stackup.h:89
void SetEpsilonR(double aEpsilon, int aDielectricSubLayer=0)
void AddDielectricPrms(int aDielectricPrmsIdx)
Add (insert) a DIELECTRIC_PRMS item to m_DielectricPrmsList all values are set to default.
void SetThickness(int aThickness, int aDielectricSubLayer=0)
void SetThicknessLocked(bool aLocked, int aDielectricSubLayer=0)
int m_requiredVersion
set to the KiCad format version this board requires
Definition: pcb_parser.h:373
const char * name
Definition: DXF_plotter.cpp:56
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:65
BOARD * m_board
Definition: pcb_parser.h:367
Definition: layer_ids.h:71
double parseDouble()
Parse the current token as an ASCII numeric string with possible leading whitespace into a double pre...
Definition: pcb_parser.cpp:167
void SetColor(const wxString &aColorName)
void Add(BOARD_STACKUP_ITEM *aItem)
Add a new item in stackup layer.
void SetLossTangent(double aTg, int aDielectricSubLayer=0)
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:103

References BOARD_STACKUP::Add(), BOARD_STACKUP_ITEM::AddDielectricPrms(), B_Cu, B_Mask, B_Paste, B_SilkS, BS_EDGE_CONNECTOR_BEVELLED, BS_EDGE_CONNECTOR_IN_USE, BS_EDGE_CONNECTOR_NONE, BS_ITEM_TYPE_COPPER, BS_ITEM_TYPE_DIELECTRIC, BS_ITEM_TYPE_SILKSCREEN, BS_ITEM_TYPE_SOLDERMASK, BS_ITEM_TYPE_SOLDERPASTE, BS_ITEM_TYPE_UNDEFINED, color, DEFAULT_SOLDERMASK_OPACITY, F_Cu, F_Mask, F_Paste, F_SilkS, BOARD_STACKUP_ITEM::GetType(), BOARD_STACKUP::m_CastellatedPads, BOARD_STACKUP::m_EdgeConnectorConstraints, BOARD_STACKUP::m_EdgePlating, BOARD_STACKUP::m_FinishType, BOARD_STACKUP::m_HasDielectricConstrains, name, parseDouble(), BOARD_STACKUP_ITEM::SetBrdLayerId(), BOARD_STACKUP_ITEM::SetColor(), BOARD_STACKUP_ITEM::SetDielectricLayerId(), BOARD_STACKUP_ITEM::SetEpsilonR(), BOARD_STACKUP_ITEM::SetLossTangent(), BOARD_STACKUP_ITEM::SetMaterial(), BOARD_STACKUP_ITEM::SetThickness(), BOARD_STACKUP_ITEM::SetThicknessLocked(), BOARD_STACKUP_ITEM::SetTypeName(), and UNDEFINED_LAYER.

◆ parseBoardUnits() [1/3]

int PCB_PARSER::parseBoardUnits ( )
private

Definition at line 197 of file pcb_parser.cpp.

198 {
199  // There should be no major rounding issues here, since the values in
200  // the file are in mm and get converted to nano-meters.
201  // See test program tools/test-nm-biu-to-ascii-mm-round-tripping.cpp
202  // to confirm or experiment. Use a similar strategy in both places, here
203  // and in the test program. Make that program with:
204  // $ make test-nm-biu-to-ascii-mm-round-tripping
205  auto retval = parseDouble() * IU_PER_MM;
206 
207  // N.B. we currently represent board units as integers. Any values that are
208  // larger or smaller than those board units represent undefined behavior for
209  // the system. We limit values to the largest that is visible on the screen
210  // This is the diagonal distance of the full screen ~1.5m
211  double int_limit = std::numeric_limits<int>::max() * 0.7071; // 0.7071 = roughly 1/sqrt(2)
212  return KiROUND( Clamp<double>( -int_limit, retval, int_limit ) );
213 }
static constexpr double IU_PER_MM
Mock up a conversion function.
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
double parseDouble()
Parse the current token as an ASCII numeric string with possible leading whitespace into a double pre...
Definition: pcb_parser.cpp:167

References IU_PER_MM, KiROUND(), and parseDouble().

Referenced by parseBoardUnits().

◆ parseBoardUnits() [2/3]

int PCB_PARSER::parseBoardUnits ( const char *  aExpected)
private

Definition at line 216 of file pcb_parser.cpp.

217 {
218  auto retval = parseDouble( aExpected ) * IU_PER_MM;
219 
220  // N.B. we currently represent board units as integers. Any values that are
221  // larger or smaller than those board units represent undefined behavior for
222  // the system. We limit values to the largest that is visible on the screen
223  double int_limit = std::numeric_limits<int>::max() * 0.7071;
224 
225  // Use here #KiROUND, not EKIROUND (see comments about them) when having a function as
226  // argument, because it will be called twice with #KIROUND.
227  return KiROUND( Clamp<double>( -int_limit, retval, int_limit ) );
228 }
static constexpr double IU_PER_MM
Mock up a conversion function.
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
double parseDouble()
Parse the current token as an ASCII numeric string with possible leading whitespace into a double pre...
Definition: pcb_parser.cpp:167

References IU_PER_MM, KiROUND(), and parseDouble().

◆ parseBoardUnits() [3/3]

int PCB_PARSER::parseBoardUnits ( PCB_KEYS_T::T  aToken)
inlineprivate

Definition at line 328 of file pcb_parser.h.

329  {
330  return parseBoardUnits( GetTokenText( aToken ) );
331  }
int parseBoardUnits()
Definition: pcb_parser.cpp:197
const char * GetTokenText(T aTok)
The DSN namespace and returns the C string representing a SPECCTRA_DB::keyword.
Definition: specctra.cpp:70

References DSN::GetTokenText(), and parseBoardUnits().

◆ parseBool()

bool PCB_PARSER::parseBool ( )
private

Definition at line 231 of file pcb_parser.cpp.

232 {
233  T token = NextTok();
234 
235  if( token == T_yes )
236  return true;
237  else if( token == T_no )
238  return false;
239  else
240  Expecting( "yes or no" );
241 
242  return false;
243 }

◆ parseDefaults()

void PCB_PARSER::parseDefaults ( BOARD_DESIGN_SETTINGS aSettings)
private

Definition at line 2118 of file pcb_parser.cpp.

2119 {
2120  T token;
2121 
2122  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2123  {
2124  if( token != T_LEFT )
2125  Expecting( T_LEFT );
2126 
2127  token = NextTok();
2128 
2129  switch( token )
2130  {
2131  case T_edge_clearance:
2132  designSettings.m_CopperEdgeClearance = parseBoardUnits( T_edge_clearance );
2134  NeedRIGHT();
2135  break;
2136 
2137  case T_copper_line_width:
2138  designSettings.m_LineThickness[ LAYER_CLASS_COPPER ] = parseBoardUnits( token );
2139  NeedRIGHT();
2140  break;
2141 
2142  case T_copper_text_dims:
2143  parseDefaultTextDims( designSettings, LAYER_CLASS_COPPER );
2144  break;
2145 
2146  case T_courtyard_line_width:
2147  designSettings.m_LineThickness[ LAYER_CLASS_COURTYARD ] = parseBoardUnits( token );
2148  NeedRIGHT();
2149  break;
2150 
2151  case T_edge_cuts_line_width:
2152  designSettings.m_LineThickness[ LAYER_CLASS_EDGES ] = parseBoardUnits( token );
2153  NeedRIGHT();
2154  break;
2155 
2156  case T_silk_line_width:
2157  designSettings.m_LineThickness[ LAYER_CLASS_SILK ] = parseBoardUnits( token );
2158  NeedRIGHT();
2159  break;
2160 
2161  case T_silk_text_dims:
2162  parseDefaultTextDims( designSettings, LAYER_CLASS_SILK );
2163  break;
2164 
2165  case T_fab_layers_line_width:
2166  designSettings.m_LineThickness[ LAYER_CLASS_FAB ] = parseBoardUnits( token );
2167  NeedRIGHT();
2168  break;
2169 
2170  case T_fab_layers_text_dims:
2171  parseDefaultTextDims( designSettings, LAYER_CLASS_FAB );
2172  break;
2173 
2174  case T_other_layers_line_width:
2175  designSettings.m_LineThickness[ LAYER_CLASS_OTHERS ] = parseBoardUnits( token );
2176  NeedRIGHT();
2177  break;
2178 
2179  case T_other_layers_text_dims:
2180  parseDefaultTextDims( designSettings, LAYER_CLASS_OTHERS );
2181  break;
2182 
2183  case T_dimension_units:
2184  designSettings.m_DimensionUnitsMode =
2185  static_cast<DIM_UNITS_MODE>( parseInt( "dimension units" ) );
2186  NeedRIGHT();
2187  break;
2188 
2189  case T_dimension_precision:
2190  designSettings.m_DimensionPrecision = parseInt( "dimension precision" );
2191  NeedRIGHT();
2192  break;
2193 
2194  default:
2195  Unexpected( CurText() );
2196  }
2197  }
2198 }
int parseBoardUnits()
Definition: pcb_parser.cpp:197
bool m_LegacyCopperEdgeClearanceLoaded
Definition: board.h:269
void parseDefaultTextDims(BOARD_DESIGN_SETTINGS &aSettings, int aLayer)
BOARD * m_board
Definition: pcb_parser.h:367
int parseInt()
Definition: pcb_parser.h:333

References LAYER_CLASS_COPPER, LAYER_CLASS_COURTYARD, LAYER_CLASS_EDGES, LAYER_CLASS_FAB, LAYER_CLASS_OTHERS, LAYER_CLASS_SILK, BOARD_DESIGN_SETTINGS::m_CopperEdgeClearance, BOARD_DESIGN_SETTINGS::m_DimensionPrecision, BOARD_DESIGN_SETTINGS::m_DimensionUnitsMode, BOARD_DESIGN_SETTINGS::m_LineThickness, and parseInt().

◆ parseDefaultTextDims()

void PCB_PARSER::parseDefaultTextDims ( BOARD_DESIGN_SETTINGS aSettings,
int  aLayer 
)
private

Definition at line 2201 of file pcb_parser.cpp.

2202 {
2203  T token;
2204 
2205  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2206  {
2207  if( token == T_LEFT )
2208  token = NextTok();
2209 
2210  switch( token )
2211  {
2212  case T_size:
2213  aSettings.m_TextSize[ aLayer ].x = parseBoardUnits( "default text size X" );
2214  aSettings.m_TextSize[ aLayer ].y = parseBoardUnits( "default text size Y" );
2215  NeedRIGHT();
2216  break;
2217 
2218  case T_thickness:
2219  aSettings.m_TextThickness[ aLayer ] = parseBoardUnits( "default text width" );
2220  NeedRIGHT();
2221  break;
2222 
2223  case T_italic:
2224  aSettings.m_TextItalic[ aLayer ] = true;
2225  break;
2226 
2227  case T_keep_upright:
2228  aSettings.m_TextUpright[ aLayer ] = true;
2229  break;
2230 
2231  default:
2232  Expecting( "size, thickness, italic or keep_upright" );
2233  }
2234  }
2235 }
int parseBoardUnits()
Definition: pcb_parser.cpp:197
wxSize m_TextSize[LAYER_CLASS_COUNT]
int m_TextThickness[LAYER_CLASS_COUNT]
bool m_TextItalic[LAYER_CLASS_COUNT]
bool m_TextUpright[LAYER_CLASS_COUNT]

References BOARD_DESIGN_SETTINGS::m_TextItalic, BOARD_DESIGN_SETTINGS::m_TextSize, BOARD_DESIGN_SETTINGS::m_TextThickness, and BOARD_DESIGN_SETTINGS::m_TextUpright.

◆ parseDIMENSION()

PCB_DIMENSION_BASE * PCB_PARSER::parseDIMENSION ( )
private

Definition at line 2794 of file pcb_parser.cpp.

2795 {
2796  wxCHECK_MSG( CurTok() == T_dimension, nullptr,
2797  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as DIMENSION." ) );
2798 
2799  T token;
2800  bool locked = false;
2801  std::unique_ptr<PCB_DIMENSION_BASE> dimension;
2802 
2803  token = NextTok();
2804 
2805  if( token == T_locked )
2806  {
2807  locked = true;
2808  token = NextTok();
2809  }
2810 
2811  // skip value that used to be saved
2812  if( token != T_LEFT )
2813  NeedLEFT();
2814 
2815  token = NextTok();
2816 
2817  bool isLegacyDimension = false;
2818 
2819  // Old format
2820  if( token == T_width )
2821  {
2822  isLegacyDimension = true;
2823  dimension = std::make_unique<PCB_DIM_ALIGNED>( nullptr );
2824  dimension->SetLineThickness( parseBoardUnits( "dimension width value" ) );
2825  NeedRIGHT();
2826  }
2827  else
2828  {
2829  if( token != T_type )
2830  Expecting( T_type );
2831 
2832  switch( NextTok() )
2833  {
2834  case T_aligned:
2835  dimension = std::make_unique<PCB_DIM_ALIGNED>( nullptr );
2836  break;
2837 
2838  case T_orthogonal:
2839  dimension = std::make_unique<PCB_DIM_ORTHOGONAL>( nullptr );
2840  break;
2841 
2842  case T_leader:
2843  dimension = std::make_unique<PCB_DIM_LEADER>( nullptr );
2844  break;
2845 
2846  case T_center:
2847  dimension = std::make_unique<PCB_DIM_CENTER>( nullptr );
2848  break;
2849 
2850  default:
2851  wxFAIL_MSG( wxT( "Cannot parse unknown dimension type %s" ) +
2852  GetTokenString( CurTok() ) );
2853  }
2854 
2855  NeedRIGHT();
2856  }
2857 
2858  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2859  {
2860  if( token != T_LEFT )
2861  Expecting( T_LEFT );
2862 
2863  token = NextTok();
2864 
2865  switch( token )
2866  {
2867  case T_layer:
2868  dimension->SetLayer( parseBoardItemLayer() );
2869  NeedRIGHT();
2870  break;
2871 
2872  case T_tstamp:
2873  NextTok();
2874  const_cast<KIID&>( dimension->m_Uuid ) = CurStrToKIID();
2875  NeedRIGHT();
2876  break;
2877 
2878  case T_gr_text:
2879  {
2881  dimension->Text() = *text;
2882 
2883  // The text is part of the dimension and shares its uuid
2884  const_cast<KIID&>( dimension->Text().m_Uuid ) = dimension->m_Uuid;
2885 
2886  // Fetch other dimension properties out of the text item
2887  dimension->Text().SetTextPos( text->GetTextPos() );
2888 
2889  if( isLegacyDimension )
2890  {
2891  EDA_UNITS units = EDA_UNITS::INCHES;
2892  FetchUnitsFromString( text->GetText(), units );
2893  dimension->SetUnits( units );
2894  }
2895 
2896  delete text;
2897  break;
2898  }
2899 
2900  // New format: feature points
2901  case T_pts:
2902  {
2903  wxPoint point;
2904 
2905  parseXY( &point.x, &point.y );
2906  dimension->SetStart( point );
2907  parseXY( &point.x, &point.y );
2908  dimension->SetEnd( point );
2909 
2910  NeedRIGHT();
2911  break;
2912  }
2913 
2914  case T_height:
2915  {
2916  wxCHECK_MSG( dimension->Type() == PCB_DIM_ALIGNED_T ||
2917  dimension->Type() == PCB_DIM_ORTHOGONAL_T, nullptr,
2918  wxT( "Invalid height token" ) );
2919  PCB_DIM_ALIGNED* aligned = static_cast<PCB_DIM_ALIGNED*>( dimension.get() );
2920  aligned->SetHeight( parseBoardUnits( "dimension height value" ) );
2921  NeedRIGHT();
2922  break;
2923  }
2924 
2925  case T_orientation:
2926  {
2927  wxCHECK_MSG( dimension->Type() == PCB_DIM_ORTHOGONAL_T, nullptr,
2928  wxT( "Invalid orientation token" ) );
2929  PCB_DIM_ORTHOGONAL* ortho = static_cast<PCB_DIM_ORTHOGONAL*>( dimension.get() );
2930 
2931  int orientation = parseInt( "orthogonal dimension orientation" );
2932  orientation = std::max( 0, std::min( 1, orientation ) );
2933  ortho->SetOrientation( static_cast<PCB_DIM_ORTHOGONAL::DIR>( orientation ) );
2934  NeedRIGHT();
2935  break;
2936  }
2937 
2938  case T_format:
2939  {
2940  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2941  {
2942  switch( token )
2943  {
2944  case T_LEFT:
2945  continue;
2946 
2947  case T_prefix:
2948  NeedSYMBOLorNUMBER();
2949  dimension->SetPrefix( FromUTF8() );
2950  NeedRIGHT();
2951  break;
2952 
2953  case T_suffix:
2954  NeedSYMBOLorNUMBER();
2955  dimension->SetSuffix( FromUTF8() );
2956  NeedRIGHT();
2957  break;
2958 
2959  case T_units:
2960  {
2961  int mode = parseInt( "dimension units mode" );
2962  mode = std::max( 0, std::min( 4, mode ) );
2963  dimension->SetUnitsMode( static_cast<DIM_UNITS_MODE>( mode ) );
2964  NeedRIGHT();
2965  break;
2966  }
2967 
2968  case T_units_format:
2969  {
2970  int format = parseInt( "dimension units format" );
2971  format = std::max( 0, std::min( 3, format ) );
2972  dimension->SetUnitsFormat( static_cast<DIM_UNITS_FORMAT>( format ) );
2973  NeedRIGHT();
2974  break;
2975  }
2976 
2977  case T_precision:
2978  dimension->SetPrecision( parseInt( "dimension precision" ) );
2979  NeedRIGHT();
2980  break;
2981 
2982  case T_override_value:
2983  NeedSYMBOLorNUMBER();
2984  dimension->SetOverrideTextEnabled( true );
2985  dimension->SetOverrideText( FromUTF8() );
2986  NeedRIGHT();
2987  break;
2988 
2989  case T_suppress_zeroes:
2990  dimension->SetSuppressZeroes( true );
2991  break;
2992 
2993  default:
2994  Expecting( "prefix, suffix, units, units_format, precision, override_value, "
2995  "suppress_zeroes" );
2996  }
2997  }
2998  break;
2999  }
3000 
3001  case T_style:
3002  {
3003  // new format: default to keep text aligned off unless token is present
3004  dimension->SetKeepTextAligned( false );
3005 
3006  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3007  {
3008  switch( token )
3009  {
3010  case T_LEFT:
3011  continue;
3012 
3013  case T_thickness:
3014  dimension->SetLineThickness( parseBoardUnits( "extension line thickness" ) );
3015  NeedRIGHT();
3016  break;
3017 
3018  case T_arrow_length:
3019  dimension->SetArrowLength( parseBoardUnits( "arrow length" ) );
3020  NeedRIGHT();
3021  break;
3022 
3023  case T_text_position_mode:
3024  {
3025  int mode = parseInt( "dimension text position mode" );
3026  mode = std::max( 0, std::min( 3, mode ) );
3027  dimension->SetTextPositionMode( static_cast<DIM_TEXT_POSITION>( mode ) );
3028  NeedRIGHT();
3029  break;
3030  }
3031 
3032  case T_extension_height:
3033  {
3034  PCB_DIM_ALIGNED* aligned = dynamic_cast<PCB_DIM_ALIGNED*>( dimension.get() );
3035  wxCHECK_MSG( aligned, nullptr, wxT( "Invalid extension_height token" ) );
3036  aligned->SetExtensionHeight( parseBoardUnits( "extension height" ) );
3037  NeedRIGHT();
3038  break;
3039  }
3040 
3041  case T_extension_offset:
3042  dimension->SetExtensionOffset( parseBoardUnits( "extension offset" ) );
3043  NeedRIGHT();
3044  break;
3045 
3046  case T_keep_text_aligned:
3047  dimension->SetKeepTextAligned( true );
3048  break;
3049 
3050  case T_text_frame:
3051  {
3052  wxCHECK_MSG( dimension->Type() == PCB_DIM_LEADER_T, nullptr,
3053  wxT( "Invalid text_frame token" ) );
3054  PCB_DIM_LEADER* leader = static_cast<PCB_DIM_LEADER*>( dimension.get() );
3055 
3056  int textFrame = parseInt( "dimension text frame mode" );
3057  textFrame = std::max( 0, std::min( 3, textFrame ) );
3058  leader->SetTextFrame( static_cast<DIM_TEXT_FRAME>( textFrame ) );
3059  NeedRIGHT();
3060  break;
3061  }
3062 
3063  default:
3064  Expecting( "thickness, arrow_length, text_position_mode, extension_height, "
3065  "extension_offset" );
3066  }
3067  }
3068 
3069  break;
3070  }
3071 
3072  // Old format: feature1 stores a feature line. We only care about the origin.
3073  case T_feature1:
3074  {
3075  NeedLEFT();
3076  token = NextTok();
3077 
3078  if( token != T_pts )
3079  Expecting( T_pts );
3080 
3081  wxPoint point;
3082 
3083  parseXY( &point.x, &point.y );
3084  dimension->SetStart( point );
3085 
3086  parseXY( nullptr, nullptr ); // Ignore second point
3087  NeedRIGHT();
3088  NeedRIGHT();
3089  break;
3090  }
3091 
3092  // Old format: feature2 stores a feature line. We only care about the end point.
3093  case T_feature2:
3094  {
3095  NeedLEFT();
3096  token = NextTok();
3097 
3098  if( token != T_pts )
3099  Expecting( T_pts );
3100 
3101  wxPoint point;
3102 
3103  parseXY( &point.x, &point.y );
3104  dimension->SetEnd( point );
3105 
3106  parseXY( nullptr, nullptr ); // Ignore second point
3107 
3108  NeedRIGHT();
3109  NeedRIGHT();
3110  break;
3111  }
3112 
3113  case T_crossbar:
3114  {
3115  NeedLEFT();
3116  token = NextTok();
3117 
3118  if( token == T_pts )
3119  {
3120  // If we have a crossbar, we know we're an old aligned dimension
3121  PCB_DIM_ALIGNED* aligned = static_cast<PCB_DIM_ALIGNED*>( dimension.get() );
3122 
3123  // Old style: calculate height from crossbar
3124  wxPoint point1, point2;
3125  parseXY( &point1.x, &point1.y );
3126  parseXY( &point2.x, &point2.y );
3127  aligned->UpdateHeight( point2, point1 ); // Yes, backwards intentionally
3128  NeedRIGHT();
3129  }
3130 
3131  NeedRIGHT();
3132  break;
3133  }
3134 
3135  // Arrow: no longer saved; no-op
3136  case T_arrow1a:
3137  NeedLEFT();
3138  token = NextTok();
3139 
3140  if( token != T_pts )
3141  Expecting( T_pts );
3142 
3143  parseXY( nullptr, nullptr );
3144  parseXY( nullptr, nullptr );
3145  NeedRIGHT();
3146  NeedRIGHT();
3147  break;
3148 
3149  // Arrow: no longer saved; no-op
3150  case T_arrow1b:
3151  NeedLEFT();
3152  token = NextTok();
3153 
3154  if( token != T_pts )
3155  Expecting( T_pts );
3156 
3157  parseXY( nullptr, nullptr );
3158  parseXY( nullptr, nullptr );
3159  NeedRIGHT();
3160  NeedRIGHT();
3161  break;
3162 
3163  // Arrow: no longer saved; no-op
3164  case T_arrow2a:
3165  NeedLEFT();
3166  token = NextTok();
3167 
3168  if( token != T_pts )
3169  Expecting( T_pts );
3170 
3171  parseXY( nullptr, nullptr );
3172  parseXY( nullptr, nullptr );
3173  NeedRIGHT();
3174  NeedRIGHT();
3175  break;
3176 
3177  // Arrow: no longer saved; no-op
3178  case T_arrow2b:
3179  NeedLEFT();
3180  token = NextTok();
3181 
3182  if( token != T_pts )
3183  Expecting( T_pts );
3184 
3185  parseXY( nullptr, nullptr );
3186  parseXY( nullptr, nullptr );
3187  NeedRIGHT();
3188  NeedRIGHT();
3189  break;
3190 
3191  default:
3192  Expecting( "layer, tstamp, gr_text, feature1, feature2, crossbar, arrow1a, "
3193  "arrow1b, arrow2a, or arrow2b" );
3194  }
3195  }
3196 
3197  if( locked )
3198  dimension->SetLocked( true );
3199 
3200  dimension->Update();
3201 
3202  return dimension.release();
3203 }
KIID CurStrToKIID()
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition: typeinfo.h:100
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:101
void SetHeight(int aHeight)
Set the distance from the feature points to the crossbar line.
wxPoint parseXY()
Parse a coordinate pair (xy X Y) in board units (mm).
Definition: pcb_parser.cpp:270
An orthogonal dimension is like an aligned dimension, but the extension lines are locked to the X or ...
int parseBoardUnits()
Definition: pcb_parser.cpp:197
For better understanding of the points that make a dimension:
void FetchUnitsFromString(const wxString &aTextValue, EDA_UNITS &aUnits)
Function FetchUnitsFromString writes any unit info found in the string to aUnits.
Definition: base_units.cpp:387
PCB_TEXT * parsePCB_TEXT()
void SetExtensionHeight(int aHeight)
PCB_LAYER_ID parseBoardItemLayer()
Parse the layer definition of a BOARD_ITEM object.
EDA_UNITS
Definition: eda_units.h:38
void UpdateHeight(const wxPoint &aCrossbarStart, const wxPoint &aCrossbarEnd)
Update the stored height basing on points coordinates.
A leader is a dimension-like object pointing to a specific point.
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition: typeinfo.h:103
int parseInt()
Definition: pcb_parser.h:333

References FetchUnitsFromString(), INCHES, locked, ortho, parseInt(), PCB_DIM_ALIGNED_T, PCB_DIM_LEADER_T, PCB_DIM_ORTHOGONAL_T, PCB_DIM_ALIGNED::SetExtensionHeight(), PCB_DIM_ALIGNED::SetHeight(), text, and PCB_DIM_ALIGNED::UpdateHeight().

◆ parseDouble() [1/3]

double PCB_PARSER::parseDouble ( )
private

Parse the current token as an ASCII numeric string with possible leading whitespace into a double precision floating point number.

Returns
The result of the parsed token.
Exceptions
IO_ERRORif an error occurs attempting to convert the current token.

Definition at line 167 of file pcb_parser.cpp.

168 {
169  char* tmp;
170 
171  errno = 0;
172 
173  double fval = strtod( CurText(), &tmp );
174 
175  if( errno )
176  {
177  wxString error;
178  error.Printf( _( "Invalid floating point number in\nfile: '%s'\nline: %d\noffset: %d" ),
179  CurSource(), CurLineNumber(), CurOffset() );
180 
181  THROW_IO_ERROR( error );
182  }
183 
184  if( CurText() == tmp )
185  {
186  wxString error;
187  error.Printf( _( "Missing floating point number in\nfile: '%s'\nline: %d\noffset: %d" ),
188  CurSource(), CurLineNumber(), CurOffset() );
189 
190  THROW_IO_ERROR( error );
191  }
192 
193  return fval;
194 }
#define _(s)
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38

References _, and THROW_IO_ERROR.

Referenced by parseAngle(), and parseDouble().

◆ parseDouble() [2/3]

double PCB_PARSER::parseDouble ( const char *  aExpected)
inlineprivate

Definition at line 303 of file pcb_parser.h.

304  {
305  NeedNUMBER( aExpected );
306  return parseDouble();
307  }
double parseDouble()
Parse the current token as an ASCII numeric string with possible leading whitespace into a double pre...
Definition: pcb_parser.cpp:167

References parseDouble().

◆ parseDouble() [3/3]

double PCB_PARSER::parseDouble ( PCB_KEYS_T::T  aToken)
inlineprivate

Definition at line 309 of file pcb_parser.h.

310  {
311  return parseDouble( GetTokenText( aToken ) );
312  }
double parseDouble()
Parse the current token as an ASCII numeric string with possible leading whitespace into a double pre...
Definition: pcb_parser.cpp:167
const char * GetTokenText(T aTok)
The DSN namespace and returns the C string representing a SPECCTRA_DB::keyword.
Definition: specctra.cpp:70

References DSN::GetTokenText(), and parseDouble().

◆ parseEDA_TEXT()

void PCB_PARSER::parseEDA_TEXT ( EDA_TEXT aText)
private

Parse the common settings for any object derived from EDA_TEXT.

Parameters
aTextA point to the EDA_TEXT object to save the parsed settings into.
Exceptions
PARSE_ERRORif the text syntax is not valid.

Definition at line 402 of file pcb_parser.cpp.

403 {
404  wxCHECK_RET( CurTok() == T_effects,
405  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as EDA_TEXT." ) );
406 
407  // In version 20210606 the notation for overbars was changed from `~...~` to `~{...}`.
408  // We need to convert the old syntax to the new one.
409  if( m_requiredVersion < 20210606 )
410  aText->SetText( ConvertToNewOverbarNotation( aText->GetText() ) );
411 
412  T token;
413 
414  // Prior to v5.0 text size was omitted from file format if equal to 60mils
415  // Now, it is always explicitly written to file
416  bool foundTextSize = false;
417 
418  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
419  {
420  if( token == T_LEFT )
421  token = NextTok();
422 
423  switch( token )
424  {
425  case T_font:
426  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
427  {
428  if( token == T_LEFT )
429  continue;
430 
431  switch( token )
432  {
433  case T_size:
434  {
435  wxSize sz;
436  sz.SetHeight( parseBoardUnits( "text height" ) );
437  sz.SetWidth( parseBoardUnits( "text width" ) );
438  aText->SetTextSize( sz );
439  NeedRIGHT();
440 
441  foundTextSize = true;
442  break;
443  }
444 
445  case T_thickness:
446  aText->SetTextThickness( parseBoardUnits( "text thickness" ) );
447  NeedRIGHT();
448  break;
449 
450  case T_bold:
451  aText->SetBold( true );
452  break;
453 
454  case T_italic:
455  aText->SetItalic( true );
456  break;
457 
458  default:
459  Expecting( "size, bold, or italic" );
460  }
461  }
462  break;
463 
464  case T_justify:
465  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
466  {
467  if( token == T_LEFT )
468  continue;
469 
470  switch( token )
471  {
472  case T_left:
474  break;
475 
476  case T_right:
478  break;
479 
480  case T_top:
482  break;
483 
484  case T_bottom:
486  break;
487 
488  case T_mirror:
489  aText->SetMirrored( true );
490  break;
491 
492  default:
493  Expecting( "left, right, top, bottom, or mirror" );
494  }
495 
496  }
497 
498  break;
499 
500  case T_hide:
501  aText->SetVisible( false );
502  break;
503 
504  default:
505  Expecting( "font, justify, or hide" );
506  }
507  }
508 
509  // Text size was not specified in file, force legacy default units
510  // 60mils is 1.524mm
511  if( !foundTextSize )
512  {
513  const double defaultTextSize = 1.524 * IU_PER_MM;
514 
515  aText->SetTextSize( wxSize( defaultTextSize, defaultTextSize ) );
516  }
517 }
void SetMirrored(bool isMirrored)
Definition: eda_text.h:188
wxString ConvertToNewOverbarNotation(const wxString &aOldStr)
Convert the old ~...~ overbar notation to the new ~{...} one.
static constexpr double IU_PER_MM
Mock up a conversion function.
void SetItalic(bool isItalic)
Definition: eda_text.h:179
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:237
int parseBoardUnits()
Definition: pcb_parser.cpp:197
virtual void SetVisible(bool aVisible)
Definition: eda_text.h:185
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:114
void SetVertJustify(EDA_TEXT_VJUSTIFY_T aType)
Definition: eda_text.h:202
int m_requiredVersion
set to the KiCad format version this board requires
Definition: pcb_parser.h:373
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:201
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition: eda_text.h:159
void SetBold(bool aBold)
Definition: eda_text.h:182
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:133

References ConvertToNewOverbarNotation(), EDA_TEXT::GetText(), GR_TEXT_HJUSTIFY_LEFT, GR_TEXT_HJUSTIFY_RIGHT, GR_TEXT_VJUSTIFY_BOTTOM, GR_TEXT_VJUSTIFY_TOP, IU_PER_MM, EDA_TEXT::SetBold(), EDA_TEXT::SetHorizJustify(), EDA_TEXT::SetItalic(), EDA_TEXT::SetMirrored(), EDA_TEXT::SetText(), EDA_TEXT::SetTextSize(), EDA_TEXT::SetTextThickness(), EDA_TEXT::SetVertJustify(), and EDA_TEXT::SetVisible().

◆ parseFOOTPRINT()

FOOTPRINT * PCB_PARSER::parseFOOTPRINT ( wxArrayString *  aInitialComments = nullptr)
Parameters
aInitialCommentsmay be a pointer to a heap allocated initial comment block or NULL. If not NULL, then caller has given ownership of a wxArrayString to this function and care must be taken to delete it even on exception.

Definition at line 3206 of file pcb_parser.cpp.

3207 {
3208  try
3209  {
3210  return parseFOOTPRINT_unchecked( aInitialComments );
3211  }
3212  catch( const PARSE_ERROR& parse_error )
3213  {
3214  if( m_tooRecent )
3215  throw FUTURE_FORMAT_ERROR( parse_error, GetRequiredVersion() );
3216  else
3217  throw;
3218  }
3219 }
bool m_tooRecent
true if version parses as later than supported
Definition: pcb_parser.h:372
wxString GetRequiredVersion()
Return a string representing the version of KiCad required to open this file.
Definition: pcb_parser.cpp:246
FOOTPRINT * parseFOOTPRINT_unchecked(wxArrayString *aInitialComments=nullptr)
A filename or source description, a problem input line, a line number, a byte offset,...
Definition: ki_exception.h:118
Variant of PARSE_ERROR indicating that a syntax or related error was likely caused by a file generate...
Definition: ki_exception.h:174

◆ parseFOOTPRINT_unchecked()

FOOTPRINT * PCB_PARSER::parseFOOTPRINT_unchecked ( wxArrayString *  aInitialComments = nullptr)
private

Definition at line 3222 of file pcb_parser.cpp.

3223 {
3224  wxCHECK_MSG( CurTok() == T_module || CurTok() == T_footprint, nullptr,
3225  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as FOOTPRINT." ) );
3226 
3227  wxString name;
3228  wxPoint pt;
3229  T token;
3230  LIB_ID fpid;
3231  int attributes = 0;
3232 
3233  std::unique_ptr<FOOTPRINT> footprint = std::make_unique<FOOTPRINT>( m_board );
3234 
3235  std::map<wxString, wxString> properties;
3236 
3237  footprint->SetInitialComments( aInitialComments );
3238 
3239  token = NextTok();
3240 
3241  if( !IsSymbol( token ) && token != T_NUMBER )
3242  Expecting( "symbol|number" );
3243 
3244  name = FromUTF8();
3245 
3246  if( !name.IsEmpty() && fpid.Parse( name, true ) >= 0 )
3247  {
3248  wxString error;
3249  error.Printf( _( "Invalid footprint ID in\nfile: '%s'\nline: %d\noffset: %d." ),
3250  CurSource(), CurLineNumber(), CurOffset() );
3251  THROW_IO_ERROR( error );
3252  }
3253 
3254  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3255  {
3256  if( token == T_LEFT )
3257  token = NextTok();
3258 
3259  switch( token )
3260  {
3261  case T_version:
3262  {
3263  // Theoretically a footprint nested in a PCB could declare its own version, though
3264  // as of writing this comment we don't do that. Just in case, take the greater
3265  // version.
3266  int this_version = parseInt( FromUTF8().mb_str( wxConvUTF8 ) );
3267  NeedRIGHT();
3268  m_requiredVersion = std::max( m_requiredVersion, this_version );
3270  break;
3271  }
3272 
3273  case T_generator:
3274  // We currently ignore the generator when parsing. It is included in the file for manual
3275  // indication of where the footprint came from.
3276  NeedSYMBOL();
3277  NeedRIGHT();
3278  break;
3279 
3280  case T_locked:
3281  footprint->SetLocked( true );
3282  break;
3283 
3284  case T_placed:
3285  footprint->SetIsPlaced( true );
3286  break;
3287 
3288  case T_layer:
3289  {
3290  // Footprints can be only on the front side or the back side.
3291  // but because we can find some stupid layer in file, ensure a
3292  // acceptable layer is set for the footprint
3294  footprint->SetLayer( layer == B_Cu ? B_Cu : F_Cu );
3295  NeedRIGHT();
3296  break;
3297  }
3298 
3299  case T_tedit:
3300  footprint->SetLastEditTime( parseHex() );
3301  NeedRIGHT();
3302  break;
3303 
3304  case T_tstamp:
3305  NextTok();
3306  const_cast<KIID&>( footprint->m_Uuid ) = CurStrToKIID();
3307  NeedRIGHT();
3308  break;
3309 
3310  case T_at:
3311  pt.x = parseBoardUnits( "X coordinate" );
3312  pt.y = parseBoardUnits( "Y coordinate" );
3313  footprint->SetPosition( pt );
3314  token = NextTok();
3315 
3316  if( token == T_NUMBER )
3317  {
3318  footprint->SetOrientation( parseAngle() );
3319  NeedRIGHT();
3320  }
3321  else if( token != T_RIGHT )
3322  {
3323  Expecting( T_RIGHT );
3324  }
3325 
3326  break;
3327 
3328  case T_descr:
3329  NeedSYMBOLorNUMBER(); // some symbols can be 0508, so a number is also a symbol here
3330  footprint->SetDescription( FromUTF8() );
3331  NeedRIGHT();
3332  break;
3333 
3334  case T_tags:
3335  NeedSYMBOLorNUMBER(); // some symbols can be 0508, so a number is also a symbol here
3336  footprint->SetKeywords( FromUTF8() );
3337  NeedRIGHT();
3338  break;
3339 
3340  case T_property:
3341  properties.insert( parseProperty() );
3342  break;
3343 
3344  case T_path:
3345  NeedSYMBOLorNUMBER(); // Paths can be numerical so a number is also a symbol here
3346  footprint->SetPath( KIID_PATH( FromUTF8() ) );
3347  NeedRIGHT();
3348  break;
3349 
3350  case T_autoplace_cost90:
3351  footprint->SetPlacementCost90( parseInt( "auto place cost at 90 degrees" ) );
3352  NeedRIGHT();
3353  break;
3354 
3355  case T_autoplace_cost180:
3356  footprint->SetPlacementCost180( parseInt( "auto place cost at 180 degrees" ) );
3357  NeedRIGHT();
3358  break;
3359 
3360  case T_solder_mask_margin:
3361  footprint->SetLocalSolderMaskMargin( parseBoardUnits( "local solder mask margin "
3362  "value" ) );
3363  NeedRIGHT();
3364  break;
3365 
3366  case T_solder_paste_margin:
3367  footprint->SetLocalSolderPasteMargin(
3368  parseBoardUnits( "local solder paste margin value" ) );
3369  NeedRIGHT();
3370  break;
3371 
3372  case T_solder_paste_ratio:
3373  footprint->SetLocalSolderPasteMarginRatio(
3374  parseDouble( "local solder paste margin ratio value" ) );
3375  NeedRIGHT();
3376  break;
3377 
3378  case T_clearance:
3379  footprint->SetLocalClearance( parseBoardUnits( "local clearance value" ) );
3380  NeedRIGHT();
3381  break;
3382 
3383  case T_zone_connect:
3384  footprint->SetZoneConnection((ZONE_CONNECTION) parseInt( "zone connection value" ) );
3385  NeedRIGHT();
3386  break;
3387 
3388  case T_thermal_width:
3389  footprint->SetThermalWidth( parseBoardUnits( "thermal width value" ) );
3390  NeedRIGHT();
3391  break;
3392 
3393  case T_thermal_gap:
3394  footprint->SetThermalGap( parseBoardUnits( "thermal gap value" ) );
3395  NeedRIGHT();
3396  break;
3397 
3398  case T_attr:
3399  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3400  {
3401  switch( token )
3402  {
3403  case T_virtual: // legacy token prior to version 20200826
3405  break;
3406 
3407  case T_through_hole:
3408  attributes |= FP_THROUGH_HOLE;
3409  break;
3410 
3411  case T_smd:
3412  attributes |= FP_SMD;
3413  break;
3414 
3415  case T_board_only:
3416  attributes |= FP_BOARD_ONLY;
3417  break;
3418 
3419  case T_exclude_from_pos_files:
3420  attributes |= FP_EXCLUDE_FROM_POS_FILES;
3421  break;
3422 
3423  case T_exclude_from_bom:
3424  attributes |= FP_EXCLUDE_FROM_BOM;
3425  break;
3426 
3427  default:
3428  Expecting( "through_hole, smd, virtual, board_only, exclude_from_pos_files "
3429  "or exclude_from_bom" );
3430  }
3431  }
3432 
3433  break;
3434 
3435  case T_fp_text:
3436  {
3437  FP_TEXT* text = parseFP_TEXT();
3438  text->SetParent( footprint.get() );
3439  double orientation = text->GetTextAngle();
3440  orientation -= footprint->GetOrientation();
3441  text->SetTextAngle( orientation );
3442  text->SetDrawCoord();
3443 
3444  switch( text->GetType() )
3445  {
3447  footprint->Reference() = *text;
3448  const_cast<KIID&>( footprint->Reference().m_Uuid ) = text->m_Uuid;
3449  delete text;
3450  break;
3451 
3453  footprint->Value() = *text;
3454  const_cast<KIID&>( footprint->Value().m_Uuid ) = text->m_Uuid;
3455  delete text;
3456  break;
3457 
3458  default:
3459  footprint->Add( text, ADD_MODE::APPEND );
3460  }
3461 
3462  break;
3463  }
3464 
3465  case T_fp_arc:
3466  case T_fp_circle:
3467  case T_fp_curve:
3468  case T_fp_rect:
3469  case T_fp_line:
3470  case T_fp_poly:
3471  {
3472  FP_SHAPE* shape = parseFP_SHAPE();
3473  shape->SetParent( footprint.get() );
3474  shape->SetDrawCoord();
3475  footprint->Add( shape, ADD_MODE::APPEND );
3476  break;
3477  }
3478 
3479  case T_pad:
3480  {
3481  PAD* pad = parsePAD( footprint.get() );
3482  pt = pad->GetPos0();
3483 
3484  RotatePoint( &pt, footprint->GetOrientation() );
3485  pad->SetPosition( pt + footprint->GetPosition() );
3486  footprint->Add( pad, ADD_MODE::APPEND );
3487  break;
3488  }
3489 
3490  case T_model:
3491  {
3492  FP_3DMODEL* model = parse3DModel();
3493  footprint->Add3DModel( model );
3494  delete model;
3495  break;
3496  }
3497 
3498  case T_zone:
3499  {
3500  ZONE* zone = parseZONE( footprint.get() );
3501  footprint->Add( zone, ADD_MODE::APPEND );
3502  break;
3503  }
3504 
3505  case T_group:
3506  parseGROUP( footprint.get() );
3507  break;
3508 
3509  default:
3510  Expecting( "locked, placed, tedit, tstamp, at, descr, tags, path, "
3511  "autoplace_cost90, autoplace_cost180, solder_mask_margin, "
3512  "solder_paste_margin, solder_paste_ratio, clearance, "
3513  "zone_connect, thermal_width, thermal_gap, attr, fp_text, "
3514  "fp_arc, fp_circle, fp_curve, fp_line, fp_poly, fp_rect, pad, "
3515  "zone, group, generator, version or model" );
3516  }
3517  }
3518 
3519  // In legacy files the lack of attributes indicated a through-hole component which was by
3520  // default excluded from pos files. However there was a hack to look for SMD pads and
3521  // consider those "mislabeled through-hole components" and therefore include them in place
3522  // files. We probably don't want to get into that game so we'll just include them by
3523  // default and let the user change it if required.
3524  if( m_requiredVersion < 20200826 && attributes == 0 )
3525  attributes |= FP_THROUGH_HOLE;
3526 
3527  // Legacy files controlled pad locking at the footprint level.
3528  if( m_requiredVersion < 20210108 )
3529  {
3530  for( PAD* pad : footprint->Pads() )
3531  pad->SetLocked( footprint->IsLocked() || footprint->LegacyPadsLocked() );
3532  }
3533 
3534  footprint->SetAttributes( attributes );
3535 
3536  footprint->SetFPID( fpid );
3537  footprint->SetProperties( properties );
3538 
3539  return footprint.release();
3540 }
ZONE_CONNECTION
How pads are covered by copper in zone.
Definition: zones.h:41
KIID CurStrToKIID()
double parseAngle()
Parse angles into deci-degrees.
Definition: pcb_parser.h:317
bool m_tooRecent
true if version parses as later than supported
Definition: pcb_parser.h:372
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:229
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:116
int parseBoardUnits()
Definition: pcb_parser.cpp:197
FP_SHAPE * parseFP_SHAPE()
std::pair< wxString, wxString > parseProperty()
Definition: pcb_parser.cpp:387
PCB_LAYER_ID parseBoardItemLayer()
Parse the layer definition of a BOARD_ITEM object.
#define _(s)
FP_TEXT * parseFP_TEXT()
Handle a list of polygons defining a copper zone.
Definition: zone.h:56
void SetDrawCoord()
Set draw coordinates (absolute values ) from relative coordinates.
Definition: fp_shape.cpp:81
PAD * parsePAD(FOOTPRINT *aParent=nullptr)
void parseGROUP(BOARD_ITEM *aParent)
int m_requiredVersion
set to the KiCad format version this board requires
Definition: pcb_parser.h:373
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:49
const char * name
Definition: DXF_plotter.cpp:56
#define SEXPR_BOARD_FILE_VERSION
Current s-expression file format version. 2 was the last legacy format version.
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:65
BOARD * m_board
Definition: pcb_parser.h:367
Definition: layer_ids.h:71
double parseDouble()
Parse the current token as an ASCII numeric string with possible leading whitespace into a double pre...
Definition: pcb_parser.cpp:167
long parseHex()
Definition: pcb_parser.h:344
Definition: pad.h:57
int parseInt()
Definition: pcb_parser.h:333
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
FP_3DMODEL * parse3DModel()
Definition: pcb_parser.cpp:520
ZONE * parseZONE(BOARD_ITEM_CONTAINER *aParent)

References _, APPEND, B_Cu, F_Cu, FP_BOARD_ONLY, FP_EXCLUDE_FROM_BOM, FP_EXCLUDE_FROM_POS_FILES, FP_SMD, FP_THROUGH_HOLE, name, pad, LIB_ID::Parse(), parseDouble(), parseHex(), parseInt(), RotatePoint(), FP_SHAPE::SetDrawCoord(), EDA_ITEM::SetParent(), SEXPR_BOARD_FILE_VERSION, text, FP_TEXT::TEXT_is_REFERENCE, FP_TEXT::TEXT_is_VALUE, and THROW_IO_ERROR.

◆ parseFP_SHAPE()

FP_SHAPE * PCB_PARSER::parseFP_SHAPE ( )
private

Definition at line 3652 of file pcb_parser.cpp.

3653 {
3654  wxCHECK_MSG( CurTok() == T_fp_arc || CurTok() == T_fp_circle || CurTok() == T_fp_curve ||
3655  CurTok() == T_fp_rect || CurTok() == T_fp_line || CurTok() == T_fp_poly, nullptr,
3656  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as FP_SHAPE." ) );
3657 
3658  wxPoint pt;
3659  T token;
3660 
3661  std::unique_ptr<FP_SHAPE> shape = std::make_unique<FP_SHAPE>( nullptr );
3662 
3663  switch( CurTok() )
3664  {
3665  case T_fp_arc:
3666  shape->SetShape( SHAPE_T::ARC );
3667  token = NextTok();
3668 
3669  if( token == T_locked )
3670  {
3671  shape->SetLocked( true );
3672  token = NextTok();
3673  }
3674 
3675  if( token != T_LEFT )
3676  Expecting( T_LEFT );
3677 
3678  token = NextTok();
3679 
3681  {
3682  // In legacy files the start keyword actually gives the arc center...
3683  if( token != T_start )
3684  Expecting( T_start );
3685 
3686  pt.x = parseBoardUnits( "X coordinate" );
3687  pt.y = parseBoardUnits( "Y coordinate" );
3688  shape->SetCenter0( pt );
3689  NeedRIGHT();
3690  NeedLEFT();
3691  token = NextTok();
3692 
3693  // ... and the end keyword gives the start point of the arc
3694  if( token != T_end )
3695  Expecting( T_end );
3696 
3697  pt.x = parseBoardUnits( "X coordinate" );
3698  pt.y = parseBoardUnits( "Y coordinate" );
3699  shape->SetStart0( pt );
3700  NeedRIGHT();
3701  NeedLEFT();
3702  token = NextTok();
3703 
3704  if( token != T_angle )
3705  Expecting( T_angle );
3706 
3707  shape->SetArcAngleAndEnd0( parseAngle( "segment angle" ), true );
3708  NeedRIGHT();
3709  }
3710  else
3711  {
3712  wxPoint arc_start, arc_mid, arc_end;
3713 
3714  if( token != T_start )
3715  Expecting( T_start );
3716 
3717  arc_start.x = parseBoardUnits( "X coordinate" );
3718  arc_start.y = parseBoardUnits( "Y coordinate" );
3719  NeedRIGHT();
3720  NeedLEFT();
3721  token = NextTok();
3722 
3723  if( token != T_mid )
3724  Expecting( T_mid );
3725 
3726  arc_mid.x = parseBoardUnits( "X coordinate" );
3727  arc_mid.y = parseBoardUnits( "Y coordinate" );
3728  NeedRIGHT();
3729  NeedLEFT();
3730  token = NextTok();
3731 
3732  if( token != T_end )
3733  Expecting( T_end );
3734 
3735  arc_end.x = parseBoardUnits( "X coordinate" );
3736  arc_end.y = parseBoardUnits( "Y coordinate" );
3737  NeedRIGHT();
3738 
3739  shape->SetArcGeometry0( arc_start, arc_mid, arc_end );
3740  }
3741 
3742  break;
3743 
3744  case T_fp_circle:
3745  shape->SetShape( SHAPE_T::CIRCLE );
3746  token = NextTok();
3747 
3748  if( token == T_locked )
3749  {
3750  shape->SetLocked( true );
3751  token = NextTok();
3752  }
3753 
3754  if( token != T_LEFT )
3755  Expecting( T_LEFT );
3756 
3757  token = NextTok();
3758 
3759  if( token != T_center )
3760  Expecting( T_center );
3761 
3762  pt.x = parseBoardUnits( "X coordinate" );
3763  pt.y = parseBoardUnits( "Y coordinate" );
3764  shape->SetStart0( pt );
3765  NeedRIGHT();
3766  NeedLEFT();
3767  token = NextTok();
3768 
3769  if( token != T_end )
3770  Expecting( T_end );
3771 
3772  pt.x = parseBoardUnits( "X coordinate" );
3773  pt.y = parseBoardUnits( "Y coordinate" );
3774  shape->SetEnd0( pt );
3775  NeedRIGHT();
3776  break;
3777 
3778  case T_fp_curve:
3779  shape->SetShape( SHAPE_T::BEZIER );
3780  token = NextTok();
3781 
3782  if( token == T_locked )
3783  {
3784  shape->SetLocked( true );
3785  token = NextTok();
3786  }
3787 
3788  if( token != T_LEFT )
3789  Expecting( T_LEFT );
3790 
3791  token = NextTok();
3792 
3793  if( token != T_pts )
3794  Expecting( T_pts );
3795 
3796  shape->SetStart0( parseXY() );
3797  shape->SetBezierC1_0( parseXY() );
3798  shape->SetBezierC2_0( parseXY() );
3799  shape->SetEnd0( parseXY() );
3800  NeedRIGHT();
3801  break;
3802 
3803  case T_fp_rect:
3804  shape->SetShape( SHAPE_T::RECT );
3805  token = NextTok();
3806 
3807  if( token == T_locked )
3808  {
3809  shape->SetLocked( true );
3810  token = NextTok();
3811  }
3812 
3813  if( token != T_LEFT )
3814  Expecting( T_LEFT );
3815 
3816  token = NextTok();
3817 
3818  if( token != T_start )
3819  Expecting( T_start );
3820 
3821  pt.x = parseBoardUnits( "X coordinate" );
3822  pt.y = parseBoardUnits( "Y coordinate" );
3823  shape->SetStart0( pt );
3824 
3825  NeedRIGHT();
3826  NeedLEFT();
3827  token = NextTok();
3828 
3829  if( token != T_end )
3830  Expecting( T_end );
3831 
3832  pt.x = parseBoardUnits( "X coordinate" );
3833  pt.y = parseBoardUnits( "Y coordinate" );
3834  shape->SetEnd0( pt );
3835  NeedRIGHT();
3836  break;
3837 
3838  case T_fp_line:
3839  // Default PCB_SHAPE type is S_SEGMENT.
3840  token = NextTok();
3841 
3842  if( token == T_locked )
3843  {
3844  shape->SetLocked( true );
3845  token = NextTok();
3846  }
3847 
3848  if( token != T_LEFT )
3849  Expecting( T_LEFT );
3850 
3851  token = NextTok();
3852 
3853  if( token != T_start )
3854  Expecting( T_start );
3855 
3856  pt.x = parseBoardUnits( "X coordinate" );
3857  pt.y = parseBoardUnits( "Y coordinate" );
3858  shape->SetStart0( pt );
3859 
3860  NeedRIGHT();
3861  NeedLEFT();
3862  token = NextTok();
3863 
3864  if( token != T_end )
3865  Expecting( T_end );
3866 
3867  pt.x = parseBoardUnits( "X coordinate" );
3868  pt.y = parseBoardUnits( "Y coordinate" );
3869  shape->SetEnd0( pt );
3870  NeedRIGHT();
3871  break;
3872 
3873  case T_fp_poly:
3874  {
3875  shape->SetShape( SHAPE_T::POLY );
3876  shape->SetPolyPoints( {} );
3877  SHAPE_LINE_CHAIN& outline = shape->GetPolyShape().Outline( 0 );
3878 
3879  token = NextTok();
3880 
3881  if( token == T_locked )
3882  {
3883  shape->SetLocked( true );
3884  token = NextTok();
3885  }
3886 
3887  if( token != T_LEFT )
3888  Expecting( T_LEFT );
3889 
3890  token = NextTok();
3891 
3892  if( token != T_pts )
3893  Expecting( T_pts );
3894 
3895  while( (token = NextTok() ) != T_RIGHT )
3896  parseOutlinePoints( outline );
3897 
3898  break;
3899  }
3900 
3901  default:
3902  Expecting( "fp_arc, fp_circle, fp_curve, fp_line, fp_poly, or fp_rect" );
3903  }
3904 
3905  bool foundFill = false;
3906 
3907  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3908  {
3909  if( token != T_LEFT )
3910  Expecting( T_LEFT );
3911 
3912  token = NextTok();
3913 
3914  switch( token )
3915  {
3916  case T_layer:
3917  shape->SetLayer( parseBoardItemLayer() );
3918  NeedRIGHT();
3919  break;
3920 
3921  case T_width:
3922  shape->SetWidth( parseBoardUnits( T_width ) );
3923  NeedRIGHT();
3924  break;
3925 
3926  case T_tstamp:
3927  NextTok();
3928  const_cast<KIID&>( shape->m_Uuid ) = CurStrToKIID();
3929  NeedRIGHT();
3930  break;
3931 
3932  case T_fill:
3933  foundFill = true;
3934 
3935  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3936  {
3937  if( token == T_LEFT )
3938  token = NextTok();
3939 
3940  switch( token )
3941  {
3942  // T_yes was used to indicate filling when first introduced,
3943  // so treat it like a solid fill since that was the only fill available
3944  case T_yes:
3945  case T_solid:
3946  shape->SetFilled( true );
3947  break;
3948 
3949  case T_none:
3950  shape->SetFilled( false );
3951  break;
3952 
3953  default:
3954  Expecting( "yes, none, solid" );
3955  }
3956  }
3957 
3958  break;
3959 
3960  // We continue to parse the status field but it is no longer written
3961  case T_status:
3962  shape->SetStatus( static_cast<EDA_ITEM_FLAGS>( parseHex() ) );
3963  NeedRIGHT();
3964  break;
3965 
3966  // Continue to process "(locked)" format which was output during 5.99 development
3967  case T_locked:
3968  shape->SetLocked( true );
3969  NeedRIGHT();
3970  break;
3971 
3972  default:
3973  Expecting( "layer, width, fill, tstamp, locked, or status" );
3974  }
3975  }
3976 
3977  if( !foundFill )
3978  {
3979  // Legacy versions didn't have a filled flag but allowed some shapes to indicate they
3980  // should be filled by specifying a 0 stroke-width.
3981  if( shape->GetWidth() == 0
3982  && ( shape->GetShape() == SHAPE_T::RECT || shape->GetShape() == SHAPE_T::CIRCLE ) )
3983  {
3984  shape->SetFilled( true );
3985  }
3986  // Polygons on non-Edge_Cuts layers were always filled
3987  else if( shape->GetShape() == SHAPE_T::POLY && shape->GetLayer() != Edge_Cuts )
3988  {
3989  shape->SetFilled( true );
3990  }
3991  }
3992 
3993  // Only filled shapes may have a zero line-width. This is not permitted in KiCad but some
3994  // external tools can generate invalid files.
3995  if( shape->GetWidth() <= 0 && !shape->IsFilled() )
3996  {
3997  shape->SetWidth( Millimeter2iu( DEFAULT_LINE_WIDTH ) );
3998  }
3999 
4000  return shape.release();
4001 }
KIID CurStrToKIID()
wxPoint parseXY()
Parse a coordinate pair (xy X Y) in board units (mm).
Definition: pcb_parser.cpp:270
#define DEFAULT_LINE_WIDTH
double parseAngle()
Parse angles into deci-degrees.
Definition: pcb_parser.h:317
int parseBoardUnits()
Definition: pcb_parser.cpp:197
#define LEGACY_ARC_FORMATTING
These were the last to use old arc formatting.
PCB_LAYER_ID parseBoardItemLayer()
Parse the layer definition of a BOARD_ITEM object.
void parseOutlinePoints(SHAPE_LINE_CHAIN &aPoly)
Parses possible outline points and stores them into aPoly.
Definition: pcb_parser.cpp:290
int m_requiredVersion
set to the KiCad format version this board requires
Definition: pcb_parser.h:373
Represent a polyline (an zero-thickness chain of connected line segments).
long parseHex()
Definition: pcb_parser.h:344
static constexpr int Millimeter2iu(double mm)

References ARC, BEZIER, CIRCLE, DEFAULT_LINE_WIDTH, Edge_Cuts, LEGACY_ARC_FORMATTING, Millimeter2iu(), parseHex(), POLY, and RECT.

◆ parseFP_TEXT()

FP_TEXT * PCB_PARSER::parseFP_TEXT ( )
private

Definition at line 3543 of file pcb_parser.cpp.

3544 {
3545  wxCHECK_MSG( CurTok() == T_fp_text, nullptr,
3546  wxString::Format( wxT( "Cannot parse %s as FP_TEXT at line %d, offset %d." ),
3547  GetTokenString( CurTok() ), CurLineNumber(), CurOffset() ) );
3548 
3549  T token = NextTok();
3550 
3551  std::unique_ptr<FP_TEXT> text = std::make_unique<FP_TEXT>( nullptr );
3552 
3553  switch( token )
3554  {
3555  case T_reference:
3556  text->SetType( FP_TEXT::TEXT_is_REFERENCE );
3557  break;
3558 
3559  case T_value:
3560  text->SetType( FP_TEXT::TEXT_is_VALUE );
3561  break;
3562 
3563  case T_user:
3564  break; // Default type is user text.
3565 
3566  default:
3567  THROW_IO_ERROR( wxString::Format( _( "Cannot handle footprint text type %s" ),
3568  FromUTF8() ) );
3569  }
3570 
3571  token = NextTok();
3572 
3573  if( token == T_locked )
3574  {
3575  text->SetLocked( true );
3576  token = NextTok();
3577  }
3578 
3579  if( !IsSymbol( token ) && (int) token != DSN_NUMBER )
3580  Expecting( "text value" );
3581 
3582  wxString value = FromUTF8();
3583  value.Replace( "%V", "${VALUE}" );
3584  value.Replace( "%R", "${REFERENCE}" );
3585  text->SetText( value );
3586  NeedLEFT();
3587  token = NextTok();
3588 
3589  if( token != T_at )
3590  Expecting( T_at );
3591 
3592  wxPoint pt;
3593 
3594  pt.x = parseBoardUnits( "X coordinate" );
3595  pt.y = parseBoardUnits( "Y coordinate" );
3596  text->SetPos0( pt );
3597 
3598  NextTok();
3599 
3600  if( CurTok() == T_NUMBER )
3601  {
3602  text->SetTextAngle( parseAngle() );
3603  NextTok();
3604  }
3605 
3606  if( CurTok() == T_unlocked )
3607  {
3608  text->SetKeepUpright( false );
3609  NextTok();
3610  }
3611 
3612  if( CurTok() != T_RIGHT )
3613  {
3614  Unexpected( CurText() );
3615  }
3616 
3617  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3618  {
3619  if( token == T_LEFT )
3620  token = NextTok();
3621 
3622  switch( token )
3623  {
3624  case T_layer:
3625  text->SetLayer( parseBoardItemLayer() );
3626  NeedRIGHT();
3627  break;
3628 
3629  case T_hide:
3630  text->SetVisible( false );
3631  break;
3632 
3633  case T_effects:
3634  parseEDA_TEXT( (EDA_TEXT*) text.get() );
3635  break;
3636 
3637  case T_tstamp:
3638  NextTok();
3639  const_cast<KIID&>( text->m_Uuid ) = CurStrToKIID();
3640  NeedRIGHT();
3641  break;
3642 
3643  default:
3644  Expecting( "layer, hide, effects or tstamp" );
3645  }
3646  }
3647 
3648  return text.release();
3649 }
KIID CurStrToKIID()
double parseAngle()
Parse angles into deci-degrees.
Definition: pcb_parser.h:317
void parseEDA_TEXT(EDA_TEXT *aText)
Parse the common settings for any object derived from EDA_TEXT.
Definition: pcb_parser.cpp:402
int parseBoardUnits()
Definition: pcb_parser.cpp:197
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:119
PCB_LAYER_ID parseBoardItemLayer()
Parse the layer definition of a BOARD_ITEM object.
#define _(s)
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 _, DSN_NUMBER, Format(), text, FP_TEXT::TEXT_is_REFERENCE, FP_TEXT::TEXT_is_VALUE, and THROW_IO_ERROR.

◆ parseGeneralSection()

void PCB_PARSER::parseGeneralSection ( )
private

Definition at line 1059 of file pcb_parser.cpp.

1060 {
1061  wxCHECK_RET( CurTok() == T_general,
1062  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
1063  wxT( " as a general section." ) );
1064 
1065  T token;
1066 
1067  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1068  {
1069  if( token != T_LEFT )
1070  Expecting( T_LEFT );
1071 
1072  token = NextTok();
1073 
1074  switch( token )
1075  {
1076  case T_thickness:
1078  NeedRIGHT();
1079  break;
1080 
1081  default: // Skip everything but the board thickness.
1082  while( ( token = NextTok() ) != T_RIGHT )
1083  {
1084  if( !IsSymbol( token ) && token != T_NUMBER )
1085  Expecting( "symbol or number" );
1086  }
1087  }
1088  }
1089 }
void SetBoardThickness(int aThickness)
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:590
int parseBoardUnits()
Definition: pcb_parser.cpp:197
BOARD * m_board
Definition: pcb_parser.h:367

◆ parseGROUP()

void PCB_PARSER::parseGROUP ( BOARD_ITEM aParent)
private

Definition at line 4571 of file pcb_parser.cpp.

4572 {
4573  wxCHECK_RET( CurTok() == T_group,
4574  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PCB_GROUP." ) );
4575 
4576  wxPoint pt;
4577  T token;
4578 
4579  m_groupInfos.push_back( GROUP_INFO() );
4580  GROUP_INFO& groupInfo = m_groupInfos.back();
4581  groupInfo.parent = aParent;
4582 
4583  while( ( token = NextTok() ) != T_LEFT )
4584  {
4585  if( token == T_STRING )
4586  groupInfo.name = FromUTF8();
4587  else if( token == T_locked )
4588  groupInfo.locked = true;
4589  else
4590  Expecting( "group name or locked" );
4591  }
4592 
4593  token = NextTok();
4594 
4595  if( token != T_id )
4596  Expecting( T_id );
4597 
4598  NextTok();
4599  groupInfo.uuid = CurStrToKIID();
4600  NeedRIGHT();
4601 
4602  NeedLEFT();
4603  token = NextTok();
4604 
4605  if( token != T_members )
4606  Expecting( T_members );
4607 
4608  while( ( token = NextTok() ) != T_RIGHT )
4609  {
4610  // This token is the Uuid of the item in the group.
4611  // Since groups are serialized at the end of the file/footprint, the Uuid should already
4612  // have been seen and exist in the board.
4613  KIID uuid( CurStr() );
4614  groupInfo.memberUuids.push_back( uuid );
4615  }
4616 
4617  NeedRIGHT();
4618 }
KIID CurStrToKIID()
Definition: kiid.h:44
std::vector< GROUP_INFO > m_groupInfos
Definition: pcb_parser.h:399

References PCB_PARSER::GROUP_INFO::locked, PCB_PARSER::GROUP_INFO::memberUuids, PCB_PARSER::GROUP_INFO::name, PCB_PARSER::GROUP_INFO::parent, and PCB_PARSER::GROUP_INFO::uuid.

◆ parseHeader()

void PCB_PARSER::parseHeader ( )
private

Definition at line 1033 of file pcb_parser.cpp.

1034 {
1035  wxCHECK_RET( CurTok() == T_kicad_pcb,
1036  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a header." ) );
1037 
1038  NeedLEFT();
1039 
1040  T tok = NextTok();
1041 
1042  if( tok == T_version )
1043  {
1044  m_requiredVersion = parseInt( FromUTF8().mb_str( wxConvUTF8 ) );
1046  NeedRIGHT();
1047  }
1048  else
1049  {
1050  m_requiredVersion = 20201115; // Last version before we started writing version #s
1051  // in footprint files as well as board files.
1053  }
1054 
1056 }
void SetFileFormatVersionAtLoad(int aVersion)
Definition: board.h:288
bool m_tooRecent
true if version parses as later than supported
Definition: pcb_parser.h:372
int m_requiredVersion
set to the KiCad format version this board requires
Definition: pcb_parser.h:373
#define SEXPR_BOARD_FILE_VERSION
Current s-expression file format version. 2 was the last legacy format version.
BOARD * m_board
Definition: pcb_parser.h:367
int parseInt()
Definition: pcb_parser.h:333

References parseInt(), and SEXPR_BOARD_FILE_VERSION.

◆ parseHex()

long PCB_PARSER::parseHex ( )
inlineprivate

Definition at line 344 of file pcb_parser.h.

345  {
346  NextTok();
347  return strtol( CurText(), nullptr, 16 );
348  }

◆ parseInt() [1/2]

int PCB_PARSER::parseInt ( )
inlineprivate

Definition at line 333 of file pcb_parser.h.

334  {
335  return (int)strtol( CurText(), nullptr, 10 );
336  }

Referenced by parseInt().

◆ parseInt() [2/2]

int PCB_PARSER::parseInt ( const char *  aExpected)
inlineprivate

Definition at line 338 of file pcb_parser.h.

339  {
340  NeedNUMBER( aExpected );
341  return parseInt();
342  }
int parseInt()
Definition: pcb_parser.h:333

References parseInt().

◆ parseLayer()

void PCB_PARSER::parseLayer ( LAYER aLayer)
private

Definition at line 1257 of file pcb_parser.cpp.

1258 {
1259  T token;
1260 
1261  std::string name;
1262  std::string userName;
1263  std::string type;
1264  bool isVisible = true;
1265 
1266  aLayer->clear();
1267 
1268  if( CurTok() != T_LEFT )
1269  Expecting( T_LEFT );
1270 
1271  // this layer_num is not used, we DO depend on LAYER_T however.
1272  LAYER_NUM layer_num = parseInt( "layer index" );
1273 
1274  NeedSYMBOLorNUMBER();
1275  name = CurText();
1276 
1277  NeedSYMBOL();
1278  type = CurText();
1279 
1280  token = NextTok();
1281 
1282  // @todo Figure out why we are looking for a hide token in the layer definition.
1283  if( token == T_hide )
1284  {
1285  isVisible = false;
1286  NeedRIGHT();
1287  }
1288  else if( token == T_STRING )
1289  {
1290  userName = CurText();
1291  NeedRIGHT();
1292  }
1293  else if( token != T_RIGHT )
1294  {
1295  Expecting( "hide, user defined name, or )" );
1296  }
1297 
1298  aLayer->m_name = FROM_UTF8( name.c_str() );
1299  aLayer->m_type = LAYER::ParseType( type.c_str() );
1300  aLayer->m_number = layer_num;
1301  aLayer->m_visible = isVisible;
1302 
1303  if( !userName.empty() )
1304  aLayer->m_userName = FROM_UTF8( userName.c_str() );
1305 
1306  // The canonical name will get reset back to the default for copper layer on the next
1307  // save. The user defined name is now a separate optional layer token from the canonical
1308  // name.
1309  if( aLayer->m_name != LSET::Name( static_cast<PCB_LAYER_ID>( aLayer->m_number ) ) )
1310  aLayer->m_userName = aLayer->m_name;
1311 }
static wxString FROM_UTF8(const char *cstring)
Convert a UTF8 encoded C string to a wxString for all wxWidgets build modes.
Definition: macros.h:110
wxString m_name
The canonical name of the layer.
Definition: board.h:108
LAYER_T m_type
The type of the layer.
Definition: board.h:110
int LAYER_NUM
This can be replaced with int and removed.
Definition: layer_ids.h:41
static const wxChar * Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition: lset.cpp:82
bool m_visible
Definition: board.h:111
wxString m_userName
The user defined name of the layer.
Definition: board.h:109
static LAYER_T ParseType(const char *aType)
Convert a string to a LAYER_T.
Definition: board.cpp:440
void clear()
Definition: board.h:88
const char * name
Definition: DXF_plotter.cpp:56
int m_number
The layer ID.
Definition: board.h:112
int parseInt()
Definition: pcb_parser.h:333

References LAYER::clear(), FROM_UTF8(), LAYER::m_name, LAYER::m_number, LAYER::m_type, LAYER::m_userName, LAYER::m_visible, name, LSET::Name(), parseInt(), and LAYER::ParseType().

◆ parseLayers()

void PCB_PARSER::parseLayers ( )
private

Definition at line 1585 of file pcb_parser.cpp.

1586 {
1587  wxCHECK_RET( CurTok() == T_layers,
1588  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as layers." ) );
1589 
1590  T token;
1591  LSET visibleLayers;
1592  LSET enabledLayers;
1593  int copperLayerCount = 0;
1594  LAYER layer;
1595  bool anyHidden = false;
1596 
1597  std::unordered_map< std::string, std::string > v3_layer_names;
1598  std::vector<LAYER> cu;
1599 
1600  createOldLayerMapping( v3_layer_names );
1601 
1602  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1603  {
1604  parseLayer( &layer );
1605 
1606  if( layer.m_type == LT_UNDEFINED ) // it's a non-copper layer
1607  break;
1608 
1609  cu.push_back( layer ); // it's copper
1610  }
1611 
1612  // All Cu layers are parsed, but not the non-cu layers here.
1613 
1614  // The original *.kicad_pcb file format and the inverted
1615  // Cu stack format both have all the Cu layers first, so use this
1616  // trick to handle either. The layer number in the (layers ..)
1617  // s-expression element are ignored.
1618  if( cu.size() )
1619  {
1620  // Rework the layer numbers, which changed when the Cu stack
1621  // was flipped. So we instead use position in the list.
1622  cu[cu.size()-1].m_number = B_Cu;
1623 
1624  for( unsigned i=0; i < cu.size()-1; ++i )
1625  {
1626  cu[i].m_number = i;
1627  }
1628 
1629  for( std::vector<LAYER>::const_iterator it = cu.begin(); it<cu.end(); ++it )
1630  {
1631  enabledLayers.set( it->m_number );
1632 
1633  if( it->m_visible )
1634  visibleLayers.set( it->m_number );
1635  else
1636  anyHidden = true;
1637 
1638  m_board->SetLayerDescr( PCB_LAYER_ID( it->m_number ), *it );
1639 
1640  UTF8 name = it->m_name;
1641 
1642  m_layerIndices[ name ] = PCB_LAYER_ID( it->m_number );
1643  m_layerMasks[ name ] = LSET( PCB_LAYER_ID( it->m_number ) );
1644  }
1645 
1646  copperLayerCount = cu.size();
1647  }
1648 
1649  // process non-copper layers
1650  while( token != T_RIGHT )
1651  {
1652  LAYER_ID_MAP::const_iterator it = m_layerIndices.find( UTF8( layer.m_name ) );
1653 
1654  if( it == m_layerIndices.end() )
1655  {
1656  auto new_layer_it = v3_layer_names.find( layer.m_name.ToStdString() );
1657 
1658  if( new_layer_it != v3_layer_names.end() )
1659  it = m_layerIndices.find( new_layer_it->second );
1660 
1661  if( it == m_layerIndices.end() )
1662  {
1663  wxString error;
1664  error.Printf( _( "Layer '%s' in file '%s' at line %d is not in fixed layer hash." ),
1665  layer.m_name,
1666  CurSource(),
1667  CurLineNumber(),
1668  CurOffset() );
1669 
1670  THROW_IO_ERROR( error );
1671  }
1672 
1673  // If we are here, then we have found a translated layer name. Put it in the maps
1674  // so that items on this layer get the appropriate layer ID number.
1675  m_layerIndices[ UTF8( layer.m_name ) ] = it->second;
1676  m_layerMasks[ UTF8( layer.m_name ) ] = it->second;
1677  layer.m_name = it->first;
1678  }
1679 
1680  layer.m_number = it->second;
1681  enabledLayers.set( layer.m_number );
1682 
1683  if( layer.m_visible )
1684  visibleLayers.set( layer.m_number );
1685  else
1686  anyHidden = true;
1687 
1688  m_board->SetLayerDescr( it->second, layer );
1689 
1690  token = NextTok();
1691 
1692  if( token != T_LEFT )
1693  break;
1694 
1695  parseLayer( &layer );
1696  }
1697 
1698  // We need at least 2 copper layers and there must be an even number of them.
1699  if( copperLayerCount < 2 || (copperLayerCount % 2) != 0 )
1700  {
1701  wxString err = wxString::Format( _( "%d is not a valid layer count" ), copperLayerCount );
1702 
1703  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
1704  }
1705 
1706  m_board->SetCopperLayerCount( copperLayerCount );
1707  m_board->SetEnabledLayers( enabledLayers );
1708 
1709  // Only set this if any layers were explicitly marked as hidden. Otherwise, we want to leave
1710  // this alone; default visibility will show everything
1711  if( anyHidden )
1712  m_board->m_LegacyVisibleLayers = visibleLayers;
1713 }
An 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to and fro...
Definition: utf8.h:70
wxString m_name
The canonical name of the layer.
Definition: board.h:108
LAYER_T m_type
The type of the layer.
Definition: board.h:110
void createOldLayerMapping(std::unordered_map< std::string, std::string > &aMap)
Create a mapping from the (short-lived) bug where layer names were translated.
void SetCopperLayerCount(int aCount)
Definition: board.cpp:461
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
bool SetLayerDescr(PCB_LAYER_ID aIndex, const LAYER &aLayer)
Return the type of the copper layer given by aLayer.
Definition: board.cpp:328
bool m_visible
Definition: board.h:111
#define _(s)
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
void parseLayer(LAYER *aLayer)
const char * name
Definition: DXF_plotter.cpp:56
Container to hold information pertinent to a layer of a BOARD.
Definition: board.h:81
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:65
BOARD * m_board
Definition: pcb_parser.h:367
LAYER_ID_MAP m_layerIndices
map layer name to it's index
Definition: pcb_parser.h:368
int m_number
The layer ID.
Definition: board.h:112
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
LSET m_LegacyVisibleLayers
Visibility settings stored in board prior to 6.0, only used for loading legacy files.
Definition: board.h:264
void SetEnabledLayers(LSET aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:487
LSET_MAP m_layerMasks
map layer names to their masks
Definition: pcb_parser.h:369

References _, B_Cu, Format(), LT_UNDEFINED, LAYER::m_name, LAYER::m_number, LAYER::m_type, LAYER::m_visible, name, THROW_IO_ERROR, and THROW_PARSE_ERROR.

◆ parseNETCLASS()

void PCB_PARSER::parseNETCLASS ( )
private

Definition at line 2269 of file pcb_parser.cpp.

2270 {
2271  wxCHECK_RET( CurTok() == T_net_class,
2272  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as net class." ) );
2273 
2274  T token;
2275 
2276  NETCLASSPTR nc = std::make_shared<NETCLASS>( wxEmptyString );
2277 
2278  // Read netclass name (can be a name or just a number like track width)
2279  NeedSYMBOLorNUMBER();
2280  nc->SetName( FromUTF8() );
2281  NeedSYMBOL();
2282  nc->SetDescription( FromUTF8() );
2283 
2284  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2285  {
2286  if( token != T_LEFT )
2287  Expecting( T_LEFT );
2288 
2289  token = NextTok();
2290 
2291  switch( token )
2292  {
2293  case T_clearance:
2294  nc->SetClearance( parseBoardUnits( T_clearance ) );
2295  break;
2296 
2297  case T_trace_width:
2298  nc->SetTrackWidth( parseBoardUnits( T_trace_width ) );
2299  break;
2300 
2301  case T_via_dia:
2302  nc->SetViaDiameter( parseBoardUnits( T_via_dia ) );
2303  break;
2304 
2305  case T_via_drill:
2306  nc->SetViaDrill( parseBoardUnits( T_via_drill ) );
2307  break;
2308 
2309  case T_uvia_dia:
2310  nc->SetuViaDiameter( parseBoardUnits( T_uvia_dia ) );
2311  break;
2312 
2313  case T_uvia_drill:
2314  nc->SetuViaDrill( parseBoardUnits( T_uvia_drill ) );
2315  break;
2316 
2317  case T_diff_pair_width:
2318  nc->SetDiffPairWidth( parseBoardUnits( T_diff_pair_width ) );
2319  break;
2320 
2321  case T_diff_pair_gap:
2322  nc->SetDiffPairGap( parseBoardUnits( T_diff_pair_gap ) );
2323  break;
2324 
2325  case T_add_net:
2326  NeedSYMBOLorNUMBER();
2327 
2328  // Convert overbar syntax from `~...~` to `~{...}`. These were left out of the
2329  // first merge so the version is a bit later.
2330  if( m_requiredVersion < 20210606 )
2331  nc->Add( ConvertToNewOverbarNotation( FromUTF8() ) );
2332  else
2333  nc->Add( FromUTF8() );
2334 
2335  break;
2336 
2337  default:
2338  Expecting( "clearance, trace_width, via_dia, via_drill, uvia_dia, uvia_drill, "
2339  "diff_pair_width, diff_pair_gap or add_net" );
2340  }
2341 
2342  NeedRIGHT();
2343  }
2344 
2345  if( !m_board->GetDesignSettings().GetNetClasses().Add( nc ) )
2346  {
2347  // Must have been a name conflict, this is a bad board file.
2348  // User may have done a hand edit to the file.
2349 
2350  // unique_ptr will delete nc on this code path
2351 
2352  wxString error;
2353  error.Printf( _( "Duplicate NETCLASS name '%s' in file '%s' at line %d, offset %d." ),
2354  nc->GetName().GetData(), CurSource().GetData(), CurLineNumber(),
2355  CurOffset() );
2356  THROW_IO_ERROR( error );
2357  }
2358 }
wxString ConvertToNewOverbarNotation(const wxString &aOldStr)
Convert the old ~...~ overbar notation to the new ~{...} one.
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:590
int parseBoardUnits()
Definition: pcb_parser.cpp:197
#define _(s)
NETCLASSES & GetNetClasses() const
bool Add(const NETCLASSPTR &aNetclass)
Add aNetclass and puts it into this NETCLASSES container.
Definition: netclass.cpp:90
int m_requiredVersion
set to the KiCad format version this board requires
Definition: pcb_parser.h:373
BOARD * m_board
Definition: pcb_parser.h:367
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38

References _, ConvertToNewOverbarNotation(), and THROW_IO_ERROR.

◆ parseNETINFO_ITEM()

void PCB_PARSER::parseNETINFO_ITEM ( )
private

Definition at line 2238 of file pcb_parser.cpp.

2239 {
2240  wxCHECK_RET( CurTok() == T_net,
2241  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as net." ) );
2242 
2243  int netCode = parseInt( "net number" );
2244 
2245  NeedSYMBOLorNUMBER();
2246  wxString name = FromUTF8();
2247 
2248  // Convert overbar syntax from `~...~` to `~{...}`. These were left out of the first merge
2249  // so the version is a bit later.
2250  if( m_requiredVersion < 20210606 )
2252 
2253  NeedRIGHT();
2254 
2255  // net 0 should be already in list, so store this net
2256  // if it is not the net 0, or if the net 0 does not exists.
2257  // (TODO: a better test.)
2259  {
2260  NETINFO_ITEM* net = new NETINFO_ITEM( m_board, name, netCode );
2261  m_board->Add( net );
2262 
2263  // Store the new code mapping
2264  pushValueIntoMap( netCode, net->GetNetCode() );
2265  }
2266 }
wxString ConvertToNewOverbarNotation(const wxString &aOldStr)
Convert the old ~...~ overbar notation to the new ~{...} one.
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1325
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT) override
Adds an item to the container.
Definition: board.cpp:608
int m_requiredVersion
set to the KiCad format version this board requires
Definition: pcb_parser.h:373
Handle the data for a net.
Definition: netinfo.h:66
const char * name
Definition: DXF_plotter.cpp:56
BOARD * m_board
Definition: pcb_parser.h:367
void pushValueIntoMap(int aIndex, int aValue)
Add aValue value in netcode mapping (m_netCodes) at aIndex.
Definition: pcb_parser.cpp:155
int parseInt()
Definition: pcb_parser.h:333
static const int UNCONNECTED
Constant that forces initialization of a netinfo item to the NETINFO_ITEM ORPHANED (typically -1) whe...
Definition: netinfo.h:367
int GetNetCode() const
Definition: netinfo.h:115

References ConvertToNewOverbarNotation(), NETINFO_ITEM::GetNetCode(), name, parseInt(), and NETINFO_LIST::UNCONNECTED.

◆ parseOutlinePoints()

void PCB_PARSER::parseOutlinePoints ( SHAPE_LINE_CHAIN aPoly)
private

Parses possible outline points and stores them into aPoly.

This accepts points for DRAWSEGMENT polygons, EDGEMODULE polygons and ZONE_CONTAINER polygons. Points and arcs are added to the most recent outline

Parameters
aPolypolygon container to add points and arcs

Definition at line 290 of file pcb_parser.cpp.

291 {
292  if( CurTok() != T_LEFT )
293  NeedLEFT();
294 
295  T token = NextTok();
296 
297  switch( token )
298  {
299  case T_xy:
300  {
301  int x = parseBoardUnits( "X coordinate" );
302  int y = parseBoardUnits( "Y coordinate" );
303 
304  NeedRIGHT();
305 
306  aPoly.Append( x, y );
307  break;
308  }
309  case T_arc:
310  {
311  bool has_start = false;
312  bool has_mid = false;
313  bool has_end = false;
314 
315  VECTOR2I arc_start, arc_mid, arc_end;
316 
317  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
318  {
319  if( token != T_LEFT )
320  Expecting( T_LEFT );
321 
322  token = NextTok();
323 
324  switch( token )
325  {
326  case T_start:
327  arc_start.x = parseBoardUnits( "start x" );
328  arc_start.y = parseBoardUnits( "start y" );
329  has_start = true;
330  break;
331 
332  case T_mid:
333  arc_mid.x = parseBoardUnits( "mid x" );
334  arc_mid.y = parseBoardUnits( "mid y" );
335  has_mid = true;
336  break;
337 
338  case T_end:
339  arc_end.x = parseBoardUnits( "end x" );
340  arc_end.y = parseBoardUnits( "end y" );
341  has_end = true;
342  break;
343 
344  default:
345  Expecting( "start, mid or end" );
346  }
347 
348  NeedRIGHT();
349  }
350 
351  if( !has_start )
352  Expecting( "start" );
353 
354  if( !has_mid )
355  Expecting( "mid" );
356 
357  if( !has_end )
358  Expecting( "end" );
359 
360  SHAPE_ARC arc( arc_start, arc_mid, arc_end, 0 );
361 
362  aPoly.Append( arc );
363 
364  if( token != T_RIGHT )
365  Expecting( T_RIGHT );
366 
367  break;
368  }
369  default:
370  Expecting( "xy or arc" );
371  }
372 }
int parseBoardUnits()
Definition: pcb_parser.cpp:197
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.

References SHAPE_LINE_CHAIN::Append(), VECTOR2< T >::x, and VECTOR2< T >::y.

◆ parsePAD()

PAD * PCB_PARSER::parsePAD ( FOOTPRINT aParent = nullptr)
private

Definition at line 4004 of file pcb_parser.cpp.

4005 {
4006  wxCHECK_MSG( CurTok() == T_pad, nullptr,
4007  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PAD." ) );
4008 
4009  wxSize sz;
4010  wxPoint pt;
4011 
4012  std::unique_ptr<PAD> pad = std::make_unique<PAD>( aParent );
4013 
4014  // File only contains a token if KeepTopBottom is true
4015  pad->SetKeepTopBottom( false );
4016 
4017  NeedSYMBOLorNUMBER();
4018  pad->SetNumber( FromUTF8() );
4019 
4020  T token = NextTok();
4021 
4022  switch( token )
4023  {
4024  case T_thru_hole:
4025  pad->SetAttribute( PAD_ATTRIB::PTH );
4026  break;
4027 
4028  case T_smd:
4029  pad->SetAttribute( PAD_ATTRIB::SMD );
4030 
4031  // Default PAD object is thru hole with drill.
4032  // SMD pads have no hole
4033  pad->SetDrillSize( wxSize( 0, 0 ) );
4034  break;
4035 
4036  case T_connect:
4037  pad->SetAttribute( PAD_ATTRIB::CONN );
4038 
4039  // Default PAD object is thru hole with drill.
4040  // CONN pads have no hole
4041  pad->SetDrillSize( wxSize( 0, 0 ) );
4042  break;
4043 
4044  case T_np_thru_hole:
4045  pad->SetAttribute( PAD_ATTRIB::NPTH );
4046  break;
4047 
4048  default:
4049  Expecting( "thru_hole, smd, connect, or np_thru_hole" );
4050  }
4051 
4052  token = NextTok();
4053 
4054  switch( token )
4055  {
4056  case T_circle:
4057  pad->SetShape( PAD_SHAPE::CIRCLE );
4058  break;
4059 
4060  case T_rect:
4061  pad->SetShape( PAD_SHAPE::RECT );
4062  break;
4063 
4064  case T_oval:
4065  pad->SetShape( PAD_SHAPE::OVAL );
4066  break;
4067 
4068  case T_trapezoid:
4069  pad->SetShape( PAD_SHAPE::TRAPEZOID );
4070  break;
4071 
4072  case T_roundrect:
4073  // Note: the shape can be PAD_SHAPE::ROUNDRECT or PAD_SHAPE::CHAMFERED_RECT
4074  // (if chamfer parameters are found later in pad descr.)
4075  pad->SetShape( PAD_SHAPE::ROUNDRECT );
4076  break;
4077 
4078  case T_custom:
4079  pad->SetShape( PAD_SHAPE::CUSTOM );
4080  break;
4081 
4082  default:
4083  Expecting( "circle, rectangle, roundrect, oval, trapezoid or custom" );
4084  }
4085 
4086  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4087  {
4088  if( token == T_locked )
4089  {
4090  pad->SetLocked( true );
4091  token = NextTok();
4092  }
4093 
4094  if( token != T_LEFT )
4095  Expecting( T_LEFT );
4096 
4097  token = NextTok();
4098 
4099  switch( token )
4100  {
4101  case T_size:
4102  sz.SetWidth( parseBoardUnits( "width value" ) );
4103  sz.SetHeight( parseBoardUnits( "height value" ) );
4104  pad->SetSize( sz );
4105  NeedRIGHT();
4106  break;
4107 
4108  case T_at:
4109  pt.x = parseBoardUnits( "X coordinate" );
4110  pt.y = parseBoardUnits( "Y coordinate" );
4111  pad->SetPos0( pt );
4112  token = NextTok();
4113 
4114  if( token == T_NUMBER )
4115  {
4116  pad->SetOrientation( parseAngle() );
4117  NeedRIGHT();
4118  }
4119  else if( token != T_RIGHT )
4120  {
4121  Expecting( ") or angle value" );
4122  }
4123 
4124  break;
4125 
4126  case T_rect_delta:
4127  {
4128  wxSize delta;
4129  delta.SetWidth( parseBoardUnits( "rectangle delta width" ) );
4130  delta.SetHeight( parseBoardUnits( "rectangle delta height" ) );
4131  pad->SetDelta( delta );
4132  NeedRIGHT();
4133  break;
4134  }
4135 
4136  case T_drill:
4137  {
4138  bool haveWidth = false;
4139  wxSize drillSize = pad->GetDrillSize();
4140 
4141  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4142  {
4143  if( token == T_LEFT )
4144  token = NextTok();
4145 
4146  switch( token )
4147  {
4148  case T_oval: pad->SetDrillShape( PAD_DRILL_SHAPE_OBLONG ); break;
4149 
4150  case T_NUMBER:
4151  {
4152  if( !haveWidth )
4153  {
4154  drillSize.SetWidth( parseBoardUnits() );
4155 
4156  // If height is not defined the width and height are the same.
4157  drillSize.SetHeight( drillSize.GetWidth() );
4158  haveWidth = true;
4159  }
4160  else
4161  {
4162  drillSize.SetHeight( parseBoardUnits() );
4163  }
4164  }
4165 
4166  break;
4167 
4168  case T_offset:
4169  pt.x = parseBoardUnits( "drill offset x" );
4170  pt.y = parseBoardUnits( "drill offset y" );
4171  pad->SetOffset( pt );
4172  NeedRIGHT();
4173  break;
4174 
4175  default:
4176  Expecting( "oval, size, or offset" );
4177  }
4178  }
4179 
4180  // This fixes a bug caused by setting the default PAD drill size to a value other
4181  // than 0 used to fix a bunch of debug assertions even though it is defined as a
4182  // through hole pad. Wouldn't a though hole pad with no drill be a surface mount
4183  // pad (or a conn pad which is a smd pad with no solder paste)?
4184  if( ( pad->GetAttribute() != PAD_ATTRIB::SMD )
4185  && ( pad->GetAttribute() != PAD_ATTRIB::CONN ) )
4186  pad->SetDrillSize( drillSize );
4187  else
4188  pad->SetDrillSize( wxSize( 0, 0 ) );
4189 
4190  break;
4191  }
4192 
4193  case T_layers:
4194  {
4195  LSET layerMask = parseBoardItemLayersAsMask();
4196  pad->SetLayerSet( layerMask );
4197  break;
4198  }
4199 
4200  case T_net:
4201  if( ! pad->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
4202  {
4203  wxLogError( _( "Invalid net ID in\nfile: %s\nline: %d offset: %d" ), CurSource(),
4204  CurLineNumber(), CurOffset() );
4205  }
4206 
4207  NeedSYMBOLorNUMBER();
4208 
4209  // Test validity of the netname in file for netcodes expected having a net name
4210  if( m_board && pad->GetNetCode() > 0 )
4211  {
4212  wxString netName( FromUTF8() );
4213 
4214  // Convert overbar syntax from `~...~` to `~{...}`. These were left out of the
4215  // first merge so the version is a bit later.
4216  if( m_requiredVersion < 20210606 )
4217  netName = ConvertToNewOverbarNotation( netName );
4218 
4219  if( netName != m_board->FindNet( pad->GetNetCode() )->GetNetname() )
4220  {
4221  pad->SetNetCode( NETINFO_LIST::ORPHANED, /* aNoAssert */ true );
4222  wxLogError( _( "Net name doesn't match ID in\nfile: %s\nline: %d offset: %d" ),
4223  CurSource(), CurLineNumber(), CurOffset() );
4224  }
4225  }
4226 
4227  NeedRIGHT();
4228  break;
4229 
4230  case T_pinfunction:
4231  NeedSYMBOLorNUMBER();
4232  pad->SetPinFunction( FromUTF8() );
4233  NeedRIGHT();
4234  break;
4235 
4236  case T_pintype:
4237  NeedSYMBOLorNUMBER();
4238  pad->SetPinType( FromUTF8() );
4239  NeedRIGHT();
4240  break;
4241 
4242  case T_die_length:
4243  pad->SetPadToDieLength( parseBoardUnits( T_die_length ) );
4244  NeedRIGHT();
4245  break;
4246 
4247  case T_solder_mask_margin:
4248  pad->SetLocalSolderMaskMargin( parseBoardUnits( T_solder_mask_margin ) );
4249  NeedRIGHT();
4250  break;
4251 
4252  case T_solder_paste_margin:
4253  pad->SetLocalSolderPasteMargin( parseBoardUnits( T_solder_paste_margin ) );
4254  NeedRIGHT();
4255  break;
4256 
4257  case T_solder_paste_margin_ratio:
4258  pad->SetLocalSolderPasteMarginRatio(
4259  parseDouble( "pad local solder paste margin ratio value" ) );
4260  NeedRIGHT();
4261  break;
4262 
4263  case T_clearance:
4264  pad->SetLocalClearance( parseBoardUnits( "local clearance value" ) );
4265  NeedRIGHT();
4266  break;
4267 
4268  case T_zone_connect:
4269  pad->SetZoneConnection( (ZONE_CONNECTION) parseInt( "zone connection value" ) );
4270  NeedRIGHT();
4271  break;
4272 
4273  case T_thermal_width:
4274  pad->SetThermalSpokeWidth( parseBoardUnits( T_thermal_width ) );
4275  NeedRIGHT();
4276  break;
4277 
4278  case T_thermal_gap:
4279  pad->SetThermalGap( parseBoardUnits( T_thermal_gap ) );
4280  NeedRIGHT();
4281  break;
4282 
4283  case T_roundrect_rratio:
4284  pad->SetRoundRectRadiusRatio( parseDouble( "roundrect radius ratio" ) );
4285  NeedRIGHT();
4286  break;
4287 
4288  case T_chamfer_ratio:
4289  pad->SetChamferRectRatio( parseDouble( "chamfer ratio" ) );
4290 
4291  if( pad->GetChamferRectRatio() > 0 )
4292  pad->SetShape( PAD_SHAPE::CHAMFERED_RECT );
4293 
4294  NeedRIGHT();
4295  break;
4296 
4297  case T_chamfer:
4298  {
4299  int chamfers = 0;
4300  bool end_list = false;
4301 
4302  while( !end_list )
4303  {
4304  token = NextTok();
4305 
4306  switch( token )
4307  {
4308  case T_top_left:
4309  chamfers |= RECT_CHAMFER_TOP_LEFT;
4310  break;
4311 
4312  case T_top_right:
4313  chamfers |= RECT_CHAMFER_TOP_RIGHT;
4314  break;
4315 
4316  case T_bottom_left:
4317  chamfers |= RECT_CHAMFER_BOTTOM_LEFT;
4318  break;
4319 
4320  case T_bottom_right:
4321  chamfers |= RECT_CHAMFER_BOTTOM_RIGHT;
4322  break;
4323 
4324  case T_RIGHT:
4325  pad->SetChamferPositions( chamfers );
4326  end_list = true;
4327  break;
4328 
4329  default:
4330  Expecting( "chamfer_top_left chamfer_top_right chamfer_bottom_left or "
4331  "chamfer_bottom_right" );
4332  }
4333  }
4334 
4335  if( pad->GetChamferPositions() != RECT_NO_CHAMFER )
4336  pad->SetShape( PAD_SHAPE::CHAMFERED_RECT );
4337 
4338  break;
4339  }
4340 
4341  case T_property:
4342  {
4343  while( token != T_RIGHT )
4344  {
4345  token = NextTok();
4346 
4347  switch( token )
4348  {
4349  case T_pad_prop_bga:
4350  pad->SetProperty( PAD_PROP::BGA );
4351  break;
4352 
4353  case T_pad_prop_fiducial_glob:
4354  pad->SetProperty( PAD_PROP::FIDUCIAL_GLBL );
4355  break;
4356 
4357  case T_pad_prop_fiducial_loc:
4358  pad->SetProperty( PAD_PROP::FIDUCIAL_LOCAL );
4359  break;
4360 
4361  case T_pad_prop_testpoint:
4362  pad->SetProperty( PAD_PROP::TESTPOINT );
4363  break;
4364 
4365  case T_pad_prop_castellated:
4366  pad->SetProperty( PAD_PROP::CASTELLATED );
4367  break;
4368 
4369  case T_pad_prop_heatsink:
4370  pad->SetProperty( PAD_PROP::HEATSINK );
4371  break;
4372 
4373  case T_none:
4374  pad->SetProperty( PAD_PROP::NONE );
4375  break;
4376 
4377  case T_RIGHT:
4378  break;
4379 
4380  default:
4381 #if 0 // Currently: skip unknown property
4382  Expecting( "pad_prop_bga pad_prop_fiducial_glob pad_prop_fiducial_loc"
4383  " pad_prop_heatsink or pad_prop_castellated" );
4384 #endif
4385  break;
4386  }
4387  }
4388 
4389  break;
4390  }
4391 
4392  case T_options:
4393  parsePAD_option( pad.get() );
4394  break;
4395 
4396  case T_primitives:
4397  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4398  {
4399  if( token == T_LEFT )
4400  token = NextTok();
4401 
4402  // Currently, I am using parsePCB_SHAPE() to read basic shapes parameters,
4403  // because they are the same as a PCB_SHAPE.
4404  // However it could be better to write a specific parser, to avoid possible issues
4405  // if the PCB_SHAPE parser is modified.
4406  PCB_SHAPE* dummyShape = nullptr;
4407 
4408  switch( token )
4409  {
4410  case T_gr_arc:
4411  dummyShape = parsePCB_SHAPE();
4412  pad->AddPrimitiveArc( dummyShape->GetCenter(), dummyShape->GetStart(),
4413  dummyShape->GetArcAngle(), dummyShape->GetWidth() );
4414  break;
4415 
4416  case T_gr_line:
4417  dummyShape = parsePCB_SHAPE();
4418  pad->AddPrimitiveSegment( dummyShape->GetStart(), dummyShape->GetEnd(),
4419  dummyShape->GetWidth() );
4420  break;
4421 
4422  case T_gr_circle:
4423  dummyShape = parsePCB_SHAPE();
4424  pad->AddPrimitiveCircle( dummyShape->GetCenter(), dummyShape->GetRadius(),
4425  dummyShape->GetWidth(), dummyShape->IsFilled() );
4426  break;
4427 
4428  case T_gr_rect:
4429  dummyShape = parsePCB_SHAPE();
4430  pad->AddPrimitiveRect( dummyShape->GetStart(), dummyShape->GetEnd(),
4431  dummyShape->GetWidth(), dummyShape->IsFilled() );
4432  break;
4433 
4434 
4435  case T_gr_poly:
4436  dummyShape = parsePCB_SHAPE();
4437  pad->AddPrimitivePoly( dummyShape->GetPolyShape(), dummyShape->GetWidth(),
4438  dummyShape->IsFilled() );
4439  break;
4440 
4441  case T_gr_curve:
4442  dummyShape = parsePCB_SHAPE();
4443  pad->AddPrimitiveCurve( dummyShape->GetStart(), dummyShape->GetEnd(),
4444  dummyShape->GetBezierC1(),
4445  dummyShape->GetBezierC2(), dummyShape->GetWidth() );
4446  break;
4447 
4448  default:
4449  Expecting( "gr_line, gr_arc, gr_circle, gr_curve, gr_rect or gr_poly" );
4450  break;
4451  }
4452 
4453  delete dummyShape;
4454  }
4455 
4456  break;
4457 
4458  case T_remove_unused_layers:
4459  pad->SetRemoveUnconnected( true );
4460  NeedRIGHT();
4461  break;
4462 
4463  case T_keep_end_layers:
4464  pad->SetKeepTopBottom( true );
4465  NeedRIGHT();
4466  break;
4467 
4468  // Continue to process "(locked)" format which was output during 5.99 development
4469  case T_locked:
4470  pad->SetLocked( true );
4471  NeedRIGHT();
4472  break;
4473 
4474  case T_tstamp:
4475  NextTok();
4476  const_cast<KIID&>( pad->m_Uuid ) = CurStrToKIID();
4477  NeedRIGHT();
4478  break;
4479 
4480  default:
4481  Expecting( "at, locked, drill, layers, net, die_length, roundrect_rratio, "
4482  "solder_mask_margin, solder_paste_margin, solder_paste_margin_ratio, "
4483  "clearance, tstamp, primitives, remove_unused_layers, keep_end_layers, "
4484  "pinfunction, pintype, zone_connect, thermal_width, or thermal_gap" );
4485  }
4486  }
4487 
4488  if( !pad->CanHaveNumber() )
4489  {
4490  // At some point it was possible to assign a number to aperture pads so we need to clean
4491  // those out here.
4492  pad->SetNumber( wxEmptyString );
4493  }
4494 
4495  return pad.release();
4496 }
wxString ConvertToNewOverbarNotation(const wxString &aOldStr)
Convert the old ~...~ overbar notation to the new ~{...} one.
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1325
ZONE_CONNECTION
How pads are covered by copper in zone.
Definition: zones.h:41
int GetWidth() const
Definition: eda_shape.h:89
KIID CurStrToKIID()
LSET parseBoardItemLayersAsMask()
Parse the layers definition of a BOARD_ITEM object.
const wxPoint & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:97
Like smd, does not appear on the solder paste layer (default)
Smd pad, appears on the solder paste layer (default)
double GetArcAngle() const
Definition: eda_shape.cpp:495
double parseAngle()
Parse angles into deci-degrees.
Definition: pcb_parser.h:317
PCB_SHAPE * parsePCB_SHAPE()
a test point pad
int parseBoardUnits()
Definition: pcb_parser.cpp:197
Plated through hole pad.
bool IsFilled() const
Definition: eda_shape.h:81
a pad used as heat sink, usually in SMD footprints
const wxPoint & GetBezierC1() const
Definition: eda_shape.h:145
bool parsePAD_option(PAD *aPad)
like PAD_PTH, but not plated
const wxPoint & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:122
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:504
wxPoint GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_shape.h:79
Smd pad, used in BGA footprints.
const wxPoint & GetBezierC2() const
Definition: eda_shape.h:148
a fiducial (usually a smd) local to the parent footprint
#define _(s)
SHAPE_POLY_SET & GetPolyShape()
Definition: eda_shape.h:207
static const int ORPHANED
NETINFO_ITEM meaning that there was no net assigned for an item, as there was no board storing net li...
Definition: netinfo.h:371
int m_requiredVersion
set to the KiCad format version this board requires
Definition: pcb_parser.h:373
a fiducial (usually a smd) for the full board
no special fabrication property
int getNetCode(int aNetCode)
< Convert net code using the mapping table if available, otherwise returns unchanged net code if < 0 ...
Definition: pcb_parser.h:146
BOARD * m_board
Definition: pcb_parser.h:367
double parseDouble()
Parse the current token as an ASCII numeric string with possible leading whitespace into a double pre...
Definition: pcb_parser.cpp:167
constexpr int delta
a pad with a castellated through hole
int GetRadius() const
Definition: eda_shape.cpp:463
int parseInt()
Definition: pcb_parser.h:333

References _, BGA, CASTELLATED, CHAMFERED_RECT, CIRCLE, CONN, ConvertToNewOverbarNotation(), CUSTOM, delta, FIDUCIAL_GLBL, FIDUCIAL_LOCAL, EDA_SHAPE::GetArcAngle(), EDA_SHAPE::GetBezierC1(), EDA_SHAPE::GetBezierC2(), PCB_SHAPE::GetCenter(), EDA_SHAPE::GetEnd(), EDA_SHAPE::GetPolyShape(), EDA_SHAPE::GetRadius(), EDA_SHAPE::GetStart(), EDA_SHAPE::GetWidth(), HEATSINK, EDA_SHAPE::IsFilled(), NONE, NPTH, NETINFO_LIST::ORPHANED, OVAL, pad, PAD_DRILL_SHAPE_OBLONG, parseDouble(), parseInt(), PTH, RECT, RECT_CHAMFER_BOTTOM_LEFT, RECT_CHAMFER_BOTTOM_RIGHT, RECT_CHAMFER_TOP_LEFT, RECT_CHAMFER_TOP_RIGHT, RECT_NO_CHAMFER, ROUNDRECT, SMD, TESTPOINT, and TRAPEZOID.

◆ parsePAD_option()

bool PCB_PARSER::parsePAD_option ( PAD aPad)
private

Definition at line 4499 of file pcb_parser.cpp.

4500 {
4501  // Parse only the (option ...) inside a pad description
4502  for( T token = NextTok(); token != T_RIGHT; token = NextTok() )
4503  {
4504  if( token != T_LEFT )
4505  Expecting( T_LEFT );
4506 
4507  token = NextTok();
4508 
4509  switch( token )
4510  {
4511  case T_anchor:
4512  token = NextTok();
4513  // Custom shaped pads have a "anchor pad", which is the reference
4514  // for connection calculations.
4515  // Because this is an anchor, only the 2 very basic shapes are managed:
4516  // circle and rect. The default is circle
4517  switch( token )
4518  {
4519  case T_circle: // default
4520  break;
4521 
4522  case T_rect:
4524  break;
4525 
4526  default:
4527  // Currently, because pad options is a moving target
4528  // just skip unknown keywords
4529  break;
4530  }
4531  NeedRIGHT();
4532  break;
4533 
4534  case T_clearance:
4535  token = NextTok();
4536  // Custom shaped pads have a clearance area that is the pad shape
4537  // (like usual pads) or the convex hull of the pad shape.
4538  switch( token )
4539  {
4540  case T_outline:
4542  break;
4543 
4544  case T_convexhull:
4546  break;
4547 
4548  default:
4549  // Currently, because pad options is a moving target
4550  // just skip unknown keywords
4551  break;
4552  }
4553 
4554  NeedRIGHT();
4555  break;
4556 
4557  default:
4558  // Currently, because pad options is a moving target
4559  // just skip unknown keywords
4560  while( (token = NextTok() ) != T_RIGHT )
4561  {}
4562 
4563  break;
4564  }
4565  }
4566 
4567  return true;
4568 }
void SetCustomShapeInZoneOpt(CUST_PAD_SHAPE_IN_ZONE aOption)
Set the option for the custom pad shape to use as clearance area in copper zones.
Definition: pad.h:198
void SetAnchorPadShape(PAD_SHAPE aShape)
Set the shape of the anchor pad for custom shaped pads.
Definition: pad.h:209

References CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL, CUST_PAD_SHAPE_IN_ZONE_OUTLINE, RECT, PAD::SetAnchorPadShape(), and PAD::SetCustomShapeInZoneOpt().

◆ parsePAGE_INFO()

void PCB_PARSER::parsePAGE_INFO ( )
private

Definition at line 1092 of file pcb_parser.cpp.

1093 {
1094  wxCHECK_RET( ( CurTok() == T_page && m_requiredVersion <= 20200119 ) || CurTok() == T_paper,
1095  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a PAGE_INFO." ) );
1096 
1097  T token;
1098  PAGE_INFO pageInfo;
1099 
1100  NeedSYMBOL();
1101 
1102  wxString pageType = FromUTF8();
1103 
1104  if( !pageInfo.SetType( pageType ) )
1105  {
1106  wxString err;
1107  err.Printf( _( "Page type '%s' is not valid." ), FromUTF8() );
1108  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
1109  }
1110 
1111  if( pageType == PAGE_INFO::Custom )
1112  {
1113  double width = parseDouble( "width" ); // width in mm
1114 
1115  // Perform some controls to avoid crashes if the size is edited by hands
1116  if( width < 100.0 )
1117  width = 100.0;
1118  else if( width > 1200.0 )
1119  width = 1200.0;
1120 
1121  double height = parseDouble( "height" ); // height in mm
1122 
1123  if( height < 100.0 )
1124  height = 100.0;
1125  else if( height > 1200.0 )
1126  height = 1200.0;
1127 
1128  pageInfo.SetWidthMils( Mm2mils( width ) );
1129  pageInfo.SetHeightMils( Mm2mils( height ) );
1130  }
1131 
1132  token = NextTok();
1133 
1134  if( token == T_portrait )
1135  {
1136  pageInfo.SetPortrait( true );
1137  NeedRIGHT();
1138  }
1139  else if( token != T_RIGHT )
1140  {
1141  Expecting( "portrait|)" );
1142  }
1143 
1144  m_board->SetPageSettings( pageInfo );
1145 }
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition: board.h:536
bool SetType(const wxString &aStandardPageDescriptionName, bool aIsPortrait=false)
Set the name of the page type and also the sizes and margins commonly associated with that type name.
Definition: page_info.cpp:119
static const wxChar Custom[]
"User" defined page type
Definition: page_info.h:77
int Mm2mils(double x)
Convert mm to mils.
Definition: base_units.cpp:56
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:164
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition: page_info.h:53
#define _(s)
void SetHeightMils(int aHeightInMils)
Definition: page_info.cpp:257
int m_requiredVersion
set to the KiCad format version this board requires
Definition: pcb_parser.h:373
BOARD * m_board
Definition: pcb_parser.h:367
void SetWidthMils(int aWidthInMils)
Definition: page_info.cpp:243
double parseDouble()
Parse the current token as an ASCII numeric string with possible leading whitespace into a double pre...
Definition: pcb_parser.cpp:167
void SetPortrait(bool aIsPortrait)
Rotate the paper page 90 degrees.
Definition: page_info.cpp:186

References _, PAGE_INFO::Custom, Mm2mils(), parseDouble(), PAGE_INFO::SetHeightMils(), PAGE_INFO::SetPortrait(), PAGE_INFO::SetType(), PAGE_INFO::SetWidthMils(), and THROW_PARSE_ERROR.

◆ parsePCB_SHAPE()

PCB_SHAPE * PCB_PARSER::parsePCB_SHAPE ( )
private

Definition at line 2361 of file pcb_parser.cpp.

2362 {
2363  wxCHECK_MSG( CurTok() == T_gr_arc || CurTok() == T_gr_circle || CurTok() == T_gr_curve ||
2364  CurTok() == T_gr_rect || CurTok() == T_gr_line || CurTok() == T_gr_poly, nullptr,
2365  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PCB_SHAPE." ) );
2366 
2367  T token;
2368  wxPoint pt;
2369  std::unique_ptr<PCB_SHAPE> shape = std::make_unique<PCB_SHAPE>( nullptr );
2370 
2371  switch( CurTok() )
2372  {
2373  case T_gr_arc:
2374  shape->SetShape( SHAPE_T::ARC );
2375  token = NextTok();
2376 
2377  if( token == T_locked )
2378  {
2379  shape->SetLocked( true );
2380  token = NextTok();
2381  }
2382 
2383  if( token != T_LEFT )
2384  Expecting( T_LEFT );
2385 
2386  token = NextTok();
2387 
2389  {
2390  // In legacy files the start keyword actually gives the arc center...
2391  if( token != T_start )
2392  Expecting( T_start );
2393 
2394  pt.x = parseBoardUnits( "X coordinate" );
2395  pt.y = parseBoardUnits( "Y coordinate" );
2396  shape->SetCenter( pt );
2397  NeedRIGHT();
2398  NeedLEFT();
2399  token = NextTok();
2400 
2401  // ... and the end keyword gives the start point of the arc
2402  if( token != T_end )
2403  Expecting( T_end );
2404 
2405  pt.x = parseBoardUnits( "X coordinate" );
2406  pt.y = parseBoardUnits( "Y coordinate" );
2407  shape->SetStart( pt );
2408  NeedRIGHT();
2409  }
2410  else
2411  {
2412  wxPoint arc_start, arc_mid, arc_end;
2413 
2414  if( token != T_start )
2415  Expecting( T_start );
2416 
2417  arc_start.x = parseBoardUnits( "X coordinate" );
2418  arc_start.y = parseBoardUnits( "Y coordinate" );
2419  NeedRIGHT();
2420  NeedLEFT();
2421  token = NextTok();
2422 
2423  if( token != T_mid )
2424  Expecting( T_mid );
2425 
2426  arc_mid.x = parseBoardUnits( "X coordinate" );
2427  arc_mid.y = parseBoardUnits( "Y coordinate" );
2428  NeedRIGHT();
2429  NeedLEFT();
2430  token = NextTok();
2431 
2432  if( token != T_end )
2433  Expecting( T_end );
2434 
2435  arc_end.x = parseBoardUnits( "X coordinate" );
2436  arc_end.y = parseBoardUnits( "Y coordinate" );
2437  NeedRIGHT();
2438 
2439  shape->SetArcGeometry( arc_start, arc_mid, arc_end );
2440  }
2441 
2442  break;
2443 
2444  case T_gr_circle:
2445  shape->SetShape( SHAPE_T::CIRCLE );
2446  token = NextTok();
2447 
2448  if( token == T_locked )
2449  {
2450  shape->SetLocked( true );
2451  token = NextTok();
2452  }
2453 
2454  if( token != T_LEFT )
2455  Expecting( T_LEFT );
2456 
2457  token = NextTok();
2458 
2459  if( token != T_center )
2460  Expecting( T_center );
2461 
2462  pt.x = parseBoardUnits( "X coordinate" );
2463  pt.y = parseBoardUnits( "Y coordinate" );
2464  shape->SetStart( pt );
2465  NeedRIGHT();
2466  NeedLEFT();
2467 
2468  token = NextTok();
2469 
2470  if( token != T_end )
2471  Expecting( T_end );
2472 
2473  pt.x = parseBoardUnits( "X coordinate" );
2474  pt.y = parseBoardUnits( "Y coordinate" );
2475  shape->SetEnd( pt );
2476  NeedRIGHT();
2477  break;
2478 
2479  case T_gr_curve:
2480  shape->SetShape( SHAPE_T::BEZIER );
2481  token = NextTok();
2482 
2483  if( token == T_locked )
2484  {
2485  shape->SetLocked( true );
2486  token = NextTok();
2487  }
2488 
2489  if( token != T_LEFT )
2490  Expecting( T_LEFT );
2491 
2492  token = NextTok();
2493 
2494  if( token != T_pts )
2495  Expecting( T_pts );
2496 
2497  shape->SetStart( parseXY() );
2498  shape->SetBezierC1( parseXY());
2499  shape->SetBezierC2( parseXY());
2500  shape->SetEnd( parseXY() );
2501  NeedRIGHT();
2502  break;
2503 
2504  case T_gr_rect:
2505  shape->SetShape( SHAPE_T::RECT );
2506  token = NextTok();
2507 
2508  if( token == T_locked )
2509  {
2510  shape->SetLocked( true );
2511  token = NextTok();
2512  }
2513 
2514  if( token != T_LEFT )
2515  Expecting( T_LEFT );
2516 
2517  token = NextTok();
2518 
2519  if( token != T_start )
2520  Expecting( T_start );
2521 
2522  pt.x = parseBoardUnits( "X coordinate" );
2523  pt.y = parseBoardUnits( "Y coordinate" );
2524  shape->SetStart( pt );
2525  NeedRIGHT();
2526  NeedLEFT();
2527  token = NextTok();
2528 
2529  if( token != T_end )
2530  Expecting( T_end );
2531 
2532  pt.x = parseBoardUnits( "X coordinate" );
2533  pt.y = parseBoardUnits( "Y coordinate" );
2534  shape->SetEnd( pt );
2535  NeedRIGHT();
2536  break;
2537 
2538  case T_gr_line:
2539  // Default PCB_SHAPE type is S_SEGMENT.
2540  token = NextTok();
2541 
2542  if( token == T_locked )
2543  {
2544  shape->SetLocked( true );
2545  token = NextTok();
2546  }
2547 
2548  if( token != T_LEFT )
2549  Expecting( T_LEFT );
2550 
2551  token = NextTok();
2552 
2553  if( token != T_start )
2554  Expecting( T_start );
2555 
2556  pt.x = parseBoardUnits( "X coordinate" );
2557  pt.y = parseBoardUnits( "Y coordinate" );
2558  shape->SetStart( pt );
2559  NeedRIGHT();
2560  NeedLEFT();
2561  token = NextTok();
2562 
2563  if( token != T_end )
2564  Expecting( T_end );
2565 
2566  pt.x = parseBoardUnits( "X coordinate" );
2567  pt.y = parseBoardUnits( "Y coordinate" );
2568  shape->SetEnd( pt );
2569  NeedRIGHT();
2570  break;
2571 
2572  case T_gr_poly:
2573  {
2574  shape->SetShape( SHAPE_T::POLY );
2575  shape->SetWidth( 0 ); // this is the default value. will be (perhaps) modified later
2576  shape->SetPolyPoints( {} );
2577 
2578  SHAPE_LINE_CHAIN& outline = shape->GetPolyShape().Outline( 0 );
2579 
2580  token = NextTok();
2581 
2582  if( token == T_locked )
2583  {
2584  shape->SetLocked( true );
2585  token = NextTok();
2586  }
2587 
2588  if( token != T_LEFT )
2589  Expecting( T_LEFT );
2590 
2591  token = NextTok();
2592 
2593  if( token != T_pts )
2594  Expecting( T_pts );
2595 
2596  while( (token = NextTok() ) != T_RIGHT )
2597  {
2598  parseOutlinePoints( outline );
2599  }
2600 
2601  break;
2602  }
2603 
2604  default:
2605  Expecting( "gr_arc, gr_circle, gr_curve, gr_line, gr_poly, or gp_rect" );
2606  }
2607 
2608  bool foundFill = false;
2609  double angle;
2610 
2611  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2612  {
2613  if( token != T_LEFT )
2614  Expecting( T_LEFT );
2615 
2616  token = NextTok();
2617 
2618  switch( token )
2619  {
2620  case T_angle:
2622  {
2623  angle = parseAngle( "arc angle" );
2624 
2625  if( shape->GetShape() == SHAPE_T::ARC )
2626  shape->SetArcAngleAndEnd( angle, true );
2627 
2628  NeedRIGHT();
2629  }
2630  else
2631  {
2632  Unexpected( T_angle );
2633  }
2634 
2635  break;
2636 
2637  case T_layer:
2638  shape->SetLayer( parseBoardItemLayer() );
2639  NeedRIGHT();
2640  break;
2641 
2642  case T_width:
2643  shape->SetWidth( parseBoardUnits( T_width ) );
2644  NeedRIGHT();
2645  break;
2646 
2647  case T_tstamp:
2648  NextTok();
2649  const_cast<KIID&>( shape->m_Uuid ) = CurStrToKIID();
2650  NeedRIGHT();
2651  break;
2652 
2653  case T_fill:
2654  foundFill = true;
2655 
2656  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2657  {
2658  if( token == T_LEFT )
2659  token = NextTok();
2660 
2661  switch( token )
2662  {
2663  // T_yes was used to indicate filling when first introduced,
2664  // so treat it like a solid fill since that was the only fill available
2665  case T_yes:
2666  case T_solid:
2667  shape->SetFilled( true );
2668  break;
2669 
2670  case T_none:
2671  shape->SetFilled( false );
2672  break;
2673 
2674  default:
2675  Expecting( "yes, none, solid" );
2676  }
2677  }
2678 
2679  break;
2680 
2681  // We continue to parse the status field but it is no longer written
2682  case T_status:
2683  shape->SetStatus( static_cast<EDA_ITEM_FLAGS>( parseHex() ) );
2684  NeedRIGHT();
2685  break;
2686 
2687  // Continue to process "(locked)" format which was output during 5.99 development
2688  case T_locked:
2689  shape->SetLocked( true );
2690  NeedRIGHT();
2691  break;
2692 
2693  default:
2694  Expecting( "layer, width, fill, tstamp, locked or status" );
2695  }
2696  }
2697 
2698  if( !foundFill )
2699  {
2700  // Legacy versions didn't have a filled flag but allowed some shapes to indicate they
2701  // should be filled by specifying a 0 stroke-width.
2702  if( shape->GetWidth() == 0
2703  && ( shape->GetShape() == SHAPE_T::RECT || shape->GetShape() == SHAPE_T::CIRCLE ) )
2704  {
2705  shape->SetFilled( true );
2706  }
2707  else if( shape->GetShape() == SHAPE_T::POLY && shape->GetLayer() != Edge_Cuts )
2708  {
2709  // Polygons on non-Edge_Cuts layers were always filled.
2710  shape->SetFilled( true );
2711  }
2712  }
2713 
2714  // Only filled shapes may have a zero line-width. This is not permitted in KiCad but some
2715  // external tools can generate invalid files.
2716  if( shape->GetWidth() <= 0 && !shape->IsFilled() )
2717  {
2718  shape->SetWidth( Millimeter2iu( DEFAULT_LINE_WIDTH ) );
2719  }
2720 
2721  return shape.release();
2722 }
KIID CurStrToKIID()
wxPoint parseXY()
Parse a coordinate pair (xy X Y) in board units (mm).
Definition: pcb_parser.cpp:270
#define DEFAULT_LINE_WIDTH
double parseAngle()
Parse angles into deci-degrees.
Definition: pcb_parser.h:317
int parseBoardUnits()
Definition: pcb_parser.cpp:197
#define LEGACY_ARC_FORMATTING
These were the last to use old arc formatting.
PCB_LAYER_ID parseBoardItemLayer()
Parse the layer definition of a BOARD_ITEM object.
void parseOutlinePoints(SHAPE_LINE_CHAIN &aPoly)
Parses possible outline points and stores them into aPoly.
Definition: pcb_parser.cpp:290
int m_requiredVersion
set to the KiCad format version this board requires
Definition: pcb_parser.h:373
Represent a polyline (an zero-thickness chain of connected line segments).
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
long parseHex()
Definition: pcb_parser.h:344
static constexpr int Millimeter2iu(double mm)

References PNS::angle(), ARC, BEZIER, CIRCLE, DEFAULT_LINE_WIDTH, Edge_Cuts, LEGACY_ARC_FORMATTING, Millimeter2iu(), parseHex(), POLY, and RECT.

◆ parsePCB_TARGET()

PCB_TARGET * PCB_PARSER::parsePCB_TARGET ( )
private

Definition at line 5475 of file pcb_parser.cpp.

5476 {
5477  wxCHECK_MSG( CurTok() == T_target, nullptr,
5478  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PCB_TARGET." ) );
5479 
5480  wxPoint pt;
5481  T token;
5482 
5483  std::unique_ptr<PCB_TARGET> target = std::make_unique<PCB_TARGET>( nullptr );
5484 
5485  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
5486  {
5487  if( token == T_LEFT )
5488  token = NextTok();
5489 
5490  switch( token )
5491  {
5492  case T_x:
5493  target->SetShape( 1 );
5494  break;
5495 
5496  case T_plus:
5497  target->SetShape( 0 );
5498  break;
5499 
5500  case T_at:
5501  pt.x = parseBoardUnits( "target x position" );
5502  pt.y = parseBoardUnits( "target y position" );
5503  target->SetPosition( pt );
5504  NeedRIGHT();
5505  break;
5506 
5507  case T_size:
5508  target->SetSize( parseBoardUnits( "target size" ) );
5509  NeedRIGHT();
5510  break;
5511 
5512  case T_width:
5513  target->SetWidth( parseBoardUnits( "target thickness" ) );
5514  NeedRIGHT();
5515  break;
5516 
5517  case T_layer:
5518  target->SetLayer( parseBoardItemLayer() );
5519  NeedRIGHT();
5520  break;
5521 
5522  case T_tstamp:
5523  NextTok();
5524  const_cast<KIID&>( target->m_Uuid ) = CurStrToKIID();
5525  NeedRIGHT();
5526  break;
5527 
5528  default:
5529  Expecting( "x, plus, at, size, width, layer or tstamp" );
5530  }
5531  }
5532 
5533  return target.release();
5534 }
KIID CurStrToKIID()
int parseBoardUnits()
Definition: pcb_parser.cpp:197
PCB_LAYER_ID parseBoardItemLayer()
Parse the layer definition of a BOARD_ITEM object.

◆ parsePCB_TEXT()

PCB_TEXT * PCB_PARSER::parsePCB_TEXT ( )
private

Definition at line 2725 of file pcb_parser.cpp.

2726 {
2727  wxCHECK_MSG( CurTok() == T_gr_text, nullptr,
2728  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PCB_TEXT." ) );
2729 
2730  T token;
2731 
2732  std::unique_ptr<PCB_TEXT> text = std::make_unique<PCB_TEXT>( m_board );
2733  NeedSYMBOLorNUMBER();
2734 
2735  text->SetText( FromUTF8() );
2736  NeedLEFT();
2737  token = NextTok();
2738 
2739  if( token != T_at )
2740  Expecting( T_at );
2741 
2742  wxPoint pt;
2743 
2744  pt.x = parseBoardUnits( "X coordinate" );
2745  pt.y = parseBoardUnits( "Y coordinate" );
2746  text->SetTextPos( pt );
2747 
2748  // If there is no orientation defined, then it is the default value of 0 degrees.
2749  token = NextTok();
2750 
2751  if( token == T_NUMBER )
2752  {
2753  text->SetTextAngle( parseAngle() );
2754  NeedRIGHT();
2755  }
2756  else if( token != T_RIGHT )
2757  {
2758  Unexpected( CurText() );
2759  }
2760 
2761  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2762  {
2763  if( token != T_LEFT )
2764  Expecting( T_LEFT );
2765 
2766  token = NextTok();
2767 
2768  switch( token )
2769  {
2770  case T_layer:
2771  text->SetLayer( parseBoardItemLayer() );
2772  NeedRIGHT();
2773  break;
2774 
2775  case T_tstamp:
2776  NextTok();
2777  const_cast<KIID&>( text->m_Uuid ) = CurStrToKIID();
2778  NeedRIGHT();
2779  break;
2780 
2781  case T_effects:
2782  parseEDA_TEXT( (EDA_TEXT*) text.get() );
2783  break;
2784 
2785  default:
2786  Expecting( "layer, tstamp or effects" );
2787  }
2788  }
2789 
2790  return text.release();
2791 }
KIID CurStrToKIID()
double parseAngle()
Parse angles into deci-degrees.
Definition: pcb_parser.h:317
void parseEDA_TEXT(EDA_TEXT *aText)
Parse the common settings for any object derived from EDA_TEXT.
Definition: pcb_parser.cpp:402
int parseBoardUnits()
Definition: pcb_parser.cpp:197
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:119
PCB_LAYER_ID parseBoardItemLayer()
Parse the layer definition of a BOARD_ITEM object.
BOARD * m_board
Definition: pcb_parser.h:367

References text.

◆ parsePCB_TRACK()

PCB_TRACK * PCB_PARSER::parsePCB_TRACK ( )
private

Definition at line 4705 of file pcb_parser.cpp.

4706 {
4707  wxCHECK_MSG( CurTok() == T_segment, nullptr,
4708  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PCB_TRACK." ) );
4709 
4710  wxPoint pt;
4711  T token;
4712 
4713  std::unique_ptr<PCB_TRACK> track = std::make_unique<PCB_TRACK>( m_board );
4714 
4715  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4716  {
4717  if( token == T_locked )
4718  {
4719  track->SetLocked( true );
4720  token = NextTok();
4721  }
4722 
4723  if( token != T_LEFT )
4724  Expecting( T_LEFT );
4725 
4726  token = NextTok();
4727 
4728  switch( token )
4729  {
4730  case T_start:
4731  pt.x = parseBoardUnits( "start x" );
4732  pt.y = parseBoardUnits( "start y" );
4733  track->SetStart( pt );
4734  break;
4735 
4736  case T_end:
4737  pt.x = parseBoardUnits( "end x" );
4738  pt.y = parseBoardUnits( "end y" );
4739  track->SetEnd( pt );
4740  break;
4741 
4742  case T_width:
4743  track->SetWidth( parseBoardUnits( "width" ) );
4744  break;
4745 
4746  case T_layer:
4747  track->SetLayer( parseBoardItemLayer() );
4748  break;
4749 
4750  case T_net:
4751  if( !track->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
4753  _( "Invalid net ID in\nfile: '%s'\nline: %d\noffset: %d." ), CurSource(),
4754  CurLineNumber(), CurOffset() ) );
4755  break;
4756 
4757  case T_tstamp:
4758  NextTok();
4759  const_cast<KIID&>( track->m_Uuid ) = CurStrToKIID();
4760  break;
4761 
4762  // We continue to parse the status field but it is no longer written
4763  case T_status:
4764  track->SetStatus( static_cast<EDA_ITEM_FLAGS>( parseHex() ) );
4765  break;
4766 
4767  // Continue to process "(locked)" format which was output during 5.99 development
4768  case T_locked:
4769  track->SetLocked( true );
4770  break;
4771 
4772  default:
4773  Expecting( "start, end, width, layer, net, tstamp, or locked" );
4774  }
4775 
4776  NeedRIGHT();
4777  }
4778 
4779  return track.release();
4780 }
KIID CurStrToKIID()
int parseBoardUnits()
Definition: pcb_parser.cpp:197
PCB_LAYER_ID parseBoardItemLayer()
Parse the layer definition of a BOARD_ITEM object.
#define _(s)
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
int getNetCode(int aNetCode)
< Convert net code using the mapping table if available, otherwise returns unchanged net code if < 0 ...
Definition: pcb_parser.h:146
BOARD * m_board
Definition: pcb_parser.h:367
long parseHex()
Definition: pcb_parser.h:344
int parseInt()
Definition: pcb_parser.h:333
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38

References _, Format(), parseHex(), parseInt(), and THROW_IO_ERROR.

◆ parsePCB_VIA()

PCB_VIA * PCB_PARSER::parsePCB_VIA ( )
private

Definition at line 4783 of file pcb_parser.cpp.

4784 {
4785  wxCHECK_MSG( CurTok() == T_via, nullptr,
4786  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PCB_VIA." ) );
4787 
4788  wxPoint pt;
4789  T token;
4790 
4791  std::unique_ptr<PCB_VIA> via = std::make_unique<PCB_VIA>( m_board );
4792 
4793  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4794  {
4795  if( token == T_locked )
4796  {
4797  via->SetLocked( true );
4798  token = NextTok();
4799  }
4800 
4801  if( token == T_LEFT )
4802  token = NextTok();
4803 
4804  switch( token )
4805  {
4806  case T_blind:
4807  via->SetViaType( VIATYPE::BLIND_BURIED );
4808  break;
4809 
4810  case T_micro:
4811  via->SetViaType( VIATYPE::MICROVIA );
4812  break;
4813 
4814  case T_at:
4815  pt.x = parseBoardUnits( "start x" );
4816  pt.y = parseBoardUnits( "start y" );
4817  via->SetStart( pt );
4818  via->SetEnd( pt );
4819  NeedRIGHT();
4820  break;
4821 
4822  case T_size:
4823  via->SetWidth( parseBoardUnits( "via width" ) );
4824  NeedRIGHT();
4825  break;
4826 
4827  case T_drill:
4828  via->SetDrill( parseBoardUnits( "drill diameter" ) );
4829  NeedRIGHT();
4830  break;
4831 
4832  case T_layers:
4833  {
4834  PCB_LAYER_ID layer1, layer2;
4835  NextTok();
4836  layer1 = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
4837  NextTok();
4838  layer2 = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
4839  via->SetLayerPair( layer1, layer2 );
4840  NeedRIGHT();
4841  break;
4842  }
4843 
4844  case T_net:
4845  if( !via->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
4846  {
4847  THROW_IO_ERROR( wxString::Format( _( "Invalid net ID in\n"
4848  "file: '%s'\n"
4849  "line: %d\n"
4850  "offset: %d" ),
4851  CurSource(),
4852  CurLineNumber(),
4853  CurOffset() ) );
4854  }
4855 
4856  NeedRIGHT();
4857  break;
4858 
4859  case T_remove_unused_layers:
4860  via->SetRemoveUnconnected( true );
4861  NeedRIGHT();
4862  break;
4863 
4864  case T_keep_end_layers:
4865  via->SetKeepTopBottom( true );
4866  NeedRIGHT();
4867  break;
4868 
4869  case T_tstamp:
4870  NextTok();
4871  const_cast<KIID&>( via->m_Uuid ) = CurStrToKIID();
4872  NeedRIGHT();
4873  break;
4874 
4875  // We continue to parse the status field but it is no longer written
4876  case T_status:
4877  via->SetStatus( static_cast<EDA_ITEM_FLAGS>( parseHex() ) );
4878  NeedRIGHT();
4879  break;
4880 
4881  // Continue to process "(locked)" format which was output during 5.99 development
4882  case T_locked:
4883  via->SetLocked( true );
4884  NeedRIGHT();
4885  break;
4886 
4887  case T_free:
4888  via->SetIsFree();
4889  NeedRIGHT();
4890  break;
4891 
4892  default:
4893  Expecting( "blind, micro, at, size, drill, layers, net, free, tstamp, or status" );
4894  }
4895  }
4896 
4897  return via.release();
4898 }
KIID CurStrToKIID()
int parseBoardUnits()
Definition: pcb_parser.cpp:197
#define _(s)
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
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:65
int getNetCode(int aNetCode)
< Convert net code using the mapping table if available, otherwise returns unchanged net code if < 0 ...
Definition: pcb_parser.h:146
BOARD * m_board
Definition: pcb_parser.h:367
LAYER_ID_MAP m_layerIndices
map layer name to it's index
Definition: pcb_parser.h:368
long parseHex()
Definition: pcb_parser.h:344
int parseInt()
Definition: pcb_parser.h:333
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38

References _, BLIND_BURIED, Format(), MICROVIA, parseHex(), parseInt(), THROW_IO_ERROR, and via.

◆ parseProperty()

std::pair< wxString, wxString > PCB_PARSER::parseProperty ( )
private

Definition at line 387 of file pcb_parser.cpp.

388 {
389  wxString pName;
390  wxString pValue;
391 
392  NeedSYMBOL();
393  pName = FromUTF8();
394  NeedSYMBOL();
395  pValue = FromUTF8();
396  NeedRIGHT();
397 
398  return { pName, pValue };
399 }

◆ parseSetup()

void PCB_PARSER::parseSetup ( )
private

Definition at line 1769 of file pcb_parser.cpp.

1770 {
1771  wxCHECK_RET( CurTok() == T_setup,
1772  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as setup." ) );
1773 
1774  T token;
1775  NETCLASS* defaultNetClass = m_board->GetDesignSettings().GetDefault();
1776  BOARD_DESIGN_SETTINGS& designSettings = m_board->GetDesignSettings();
1777  ZONE_SETTINGS& zoneSettings = designSettings.GetDefaultZoneSettings();
1778 
1779  // Missing soldermask min width value means that the user has set the value to 0 and
1780  // not the default value (0.25mm)
1781  designSettings.m_SolderMaskMinWidth = 0;
1782 
1783  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1784  {
1785  if( token != T_LEFT )
1786  Expecting( T_LEFT );
1787 
1788  token = NextTok();
1789 
1790  switch( token )
1791  {
1792  case T_stackup:
1794  break;
1795 
1796  case T_last_trace_width: // not used now
1797  /* lastTraceWidth =*/ parseBoardUnits( T_last_trace_width );
1798  NeedRIGHT();
1799  break;
1800 
1801  case T_user_trace_width:
1802  {
1803  // Make room for the netclass value
1804  if( designSettings.m_TrackWidthList.empty() )
1805  designSettings.m_TrackWidthList.emplace_back( 0 );
1806 
1807  designSettings.m_TrackWidthList.push_back( parseBoardUnits( T_user_trace_width ) );
1809  NeedRIGHT();
1810  break;
1811  }
1812 
1813  case T_trace_clearance:
1814  defaultNetClass->SetClearance( parseBoardUnits( T_trace_clearance ) );
1816  NeedRIGHT();
1817  break;
1818 
1819  case T_zone_clearance:
1820  zoneSettings.m_ZoneClearance = parseBoardUnits( T_zone_clearance );
1822  NeedRIGHT();
1823  break;
1824 
1825  case T_zone_45_only:
1826  zoneSettings.m_Zone_45_Only = parseBool();
1828  NeedRIGHT();
1829  break;
1830 
1831  case T_clearance_min:
1832  designSettings.m_MinClearance = parseBoardUnits( T_clearance_min );
1834  NeedRIGHT();
1835  break;
1836 
1837  case T_trace_min:
1838  designSettings.m_TrackMinWidth = parseBoardUnits( T_trace_min );
1840  NeedRIGHT();
1841  break;
1842 
1843  case T_via_size:
1844  defaultNetClass->SetViaDiameter( parseBoardUnits( T_via_size ) );
1846  NeedRIGHT();
1847  break;
1848 
1849  case T_via_drill:
1850  defaultNetClass->SetViaDrill( parseBoardUnits( T_via_drill ) );
1852  NeedRIGHT();
1853  break;
1854 
1855  case T_via_min_annulus:
1856  designSettings.m_ViasMinAnnularWidth = parseBoardUnits( T_via_min_annulus );
1858  NeedRIGHT();
1859  break;
1860 
1861  case T_via_min_size:
1862  designSettings.m_ViasMinSize = parseBoardUnits( T_via_min_size );
1864  NeedRIGHT();
1865  break;
1866 
1867  case T_through_hole_min:
1868  designSettings.m_MinThroughDrill = parseBoardUnits( T_through_hole_min );
1870  NeedRIGHT();
1871  break;
1872 
1873  // Legacy token for T_through_hole_min
1874  case T_via_min_drill:
1875  designSettings.m_MinThroughDrill = parseBoardUnits( T_via_min_drill );
1877  NeedRIGHT();
1878  break;
1879 
1880  case T_hole_to_hole_min:
1881  designSettings.m_HoleToHoleMin = parseBoardUnits( T_hole_to_hole_min );
1883  NeedRIGHT();
1884  break;
1885 
1886  case T_user_via:
1887  {
1888  int viaSize = parseBoardUnits( "user via size" );
1889  int viaDrill = parseBoardUnits( "user via drill" );
1890 
1891  // Make room for the netclass value
1892  if( designSettings.m_ViasDimensionsList.empty() )
1893  designSettings.m_ViasDimensionsList.emplace_back( VIA_DIMENSION( 0, 0 ) );
1894 
1895  designSettings.m_ViasDimensionsList.emplace_back( VIA_DIMENSION( viaSize, viaDrill ) );
1897  NeedRIGHT();
1898  break;
1899  }
1900 
1901  case T_uvia_size:
1902  defaultNetClass->SetuViaDiameter( parseBoardUnits( T_uvia_size ) );
1904  NeedRIGHT();
1905  break;
1906 
1907  case T_uvia_drill:
1908  defaultNetClass->SetuViaDrill( parseBoardUnits( T_uvia_drill ) );
1910  NeedRIGHT();
1911  break;
1912 
1913  case T_uvias_allowed:
1914  designSettings.m_MicroViasAllowed = parseBool();
1916  NeedRIGHT();
1917  break;
1918 
1919  case T_blind_buried_vias_allowed:
1920  designSettings.m_BlindBuriedViaAllowed = parseBool();
1922  NeedRIGHT();
1923  break;
1924 
1925  case T_uvia_min_size:
1926  designSettings.m_MicroViasMinSize = parseBoardUnits( T_uvia_min_size );
1928  NeedRIGHT();
1929  break;
1930 
1931  case T_uvia_min_drill:
1932  designSettings.m_MicroViasMinDrill = parseBoardUnits( T_uvia_min_drill );
1934  NeedRIGHT();
1935  break;
1936 
1937  case T_user_diff_pair:
1938  {
1939  int width = parseBoardUnits( "user diff-pair width" );
1940  int gap = parseBoardUnits( "user diff-pair gap" );
1941  int viaGap = parseBoardUnits( "user diff-pair via gap" );
1942  designSettings.m_DiffPairDimensionsList.emplace_back(
1943  DIFF_PAIR_DIMENSION( width, gap, viaGap ) );
1945  NeedRIGHT();
1946  }
1947 
1948  break;
1949 
1950  case T_segment_width: // note: legacy (pre-6.0) token
1951  designSettings.m_LineThickness[ LAYER_CLASS_COPPER ] =
1952  parseBoardUnits( T_segment_width );
1954  NeedRIGHT();
1955  break;
1956 
1957  case T_edge_width: // note: legacy (pre-6.0) token
1958  designSettings.m_LineThickness[ LAYER_CLASS_EDGES ] = parseBoardUnits( T_edge_width );
1960  NeedRIGHT();
1961  break;
1962 
1963  case T_mod_edge_width: // note: legacy (pre-6.0) token
1964  designSettings.m_LineThickness[ LAYER_CLASS_SILK ] =
1965  parseBoardUnits( T_mod_edge_width );
1967  NeedRIGHT();
1968  break;
1969 
1970  case T_pcb_text_width: // note: legacy (pre-6.0) token
1971  designSettings.m_TextThickness[ LAYER_CLASS_COPPER ] =
1972  parseBoardUnits( T_pcb_text_width );
1974  NeedRIGHT();
1975  break;
1976 
1977  case T_mod_text_width: // note: legacy (pre-6.0) token
1978  designSettings.m_TextThickness[ LAYER_CLASS_SILK ] =
1979  parseBoardUnits( T_mod_text_width );
1981  NeedRIGHT();
1982  break;
1983 
1984  case T_pcb_text_size: // note: legacy (pre-6.0) token
1985  designSettings.m_TextSize[ LAYER_CLASS_COPPER ].x = parseBoardUnits( "pcb text width" );
1986  designSettings.m_TextSize[ LAYER_CLASS_COPPER ].y =
1987  parseBoardUnits( "pcb text height" );
1989  NeedRIGHT();
1990  break;
1991 
1992  case T_mod_text_size: // note: legacy (pre-6.0) token
1993  designSettings.m_TextSize[ LAYER_CLASS_SILK ].x =
1994  parseBoardUnits( "footprint text width" );
1995  designSettings.m_TextSize[ LAYER_CLASS_SILK ].y =
1996  parseBoardUnits( "footprint text height" );
1998  NeedRIGHT();
1999  break;
2000 
2001  case T_defaults:
2002  parseDefaults( designSettings );
2004  break;
2005 
2006  case T_pad_size:
2007  {
2008  wxSize sz;
2009  sz.SetWidth( parseBoardUnits( "master pad width" ) );
2010  sz.SetHeight( parseBoardUnits( "master pad height" ) );
2011  designSettings.m_Pad_Master->SetSize( sz );
2013  NeedRIGHT();
2014  break;
2015  }
2016 
2017  case T_pad_drill:
2018  {
2019  int drillSize = parseBoardUnits( T_pad_drill );
2020  designSettings.m_Pad_Master->SetDrillSize( wxSize( drillSize, drillSize ) );
2022  NeedRIGHT();
2023  break;
2024  }
2025 
2026  case T_pad_to_mask_clearance:
2027  designSettings.m_SolderMaskMargin = parseBoardUnits( T_pad_to_mask_clearance );
2028  NeedRIGHT();
2029  break;
2030 
2031  case T_solder_mask_min_width:
2032  designSettings.m_SolderMaskMinWidth = parseBoardUnits( T_solder_mask_min_width );
2033  NeedRIGHT();
2034  break;
2035 
2036  case T_pad_to_paste_clearance:
2037  designSettings.m_SolderPasteMargin = parseBoardUnits( T_pad_to_paste_clearance );
2038  NeedRIGHT();
2039  break;
2040 
2041  case T_pad_to_paste_clearance_ratio:
2042  designSettings.m_SolderPasteMarginRatio = parseDouble( T_pad_to_paste_clearance_ratio );
2043  NeedRIGHT();
2044  break;
2045 
2046  case T_aux_axis_origin:
2047  {
2048  int x = parseBoardUnits( "auxiliary origin X" );
2049  int y = parseBoardUnits( "auxiliary origin Y" );
2050  designSettings.m_AuxOrigin = wxPoint( x, y );
2051 
2052  // Aux origin still stored in board for the moment
2053  //m_board->m_LegacyDesignSettingsLoaded = true;