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=NULL)
 
LINE_READERSetLineReader (LINE_READER *aReader)
 Set aLineReader into the parser, and returns the previous one, if any. More...
 
void SetBoard (BOARD *aBoard)
 
BOARD_ITEMParse ()
 
FOOTPRINTparseFOOTPRINT (wxArrayString *aInitialComments=0)
 
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 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 ()
 
DIMENSION_BASEparseDIMENSION ()
 
FOOTPRINTparseFOOTPRINT_unchecked (wxArrayString *aInitialComments=0)
 
FP_TEXTparseFP_TEXT ()
 
FP_SHAPEparseFP_SHAPE ()
 
PADparsePAD (FOOTPRINT *aParent=NULL)
 
bool parsePAD_option (PAD *aPad)
 
ARCparseARC ()
 
TRACKparseTRACK ()
 
VIAparseVIA ()
 
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 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)
 
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
 
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 68 of file pcb_parser.h.

Member Typedef Documentation

◆ KIID_MAP

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

Definition at line 356 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 354 of file pcb_parser.h.

◆ LSET_MAP

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

Definition at line 355 of file pcb_parser.h.

Constructor & Destructor Documentation

◆ PCB_PARSER()

PCB_PARSER::PCB_PARSER ( LINE_READER aReader = NULL)
inline

Definition at line 71 of file pcb_parser.h.

71  :
72  PCB_LEXER( aReader ),
73  m_board( nullptr ),
74  m_resetKIIDs( false )
75  {
76  init();
77  }
BOARD * m_board
Definition: pcb_parser.h:358
void init()
Clear and re-establish m_layerMap with the default layer names.
Definition: pcb_parser.cpp:61
bool m_resetKIIDs
reading into an existing board; reset UUIDs
Definition: pcb_parser.h:365

References init().

Member Function Documentation

◆ 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 1340 of file pcb_parser.cpp.

1341 {
1342  // N.B. This mapping only includes Italian, Polish and French as they were the only languages that
1343  // mapped the layer names as of cc2022b1ac739aa673d2a0b7a2047638aa7a47b3 (kicad-i18n) when the
1344  // bug was fixed in KiCad source.
1345 
1346  // Italian
1347  aMap["Adesivo.Retro"] = "B.Adhes";
1348  aMap["Adesivo.Fronte"] = "F.Adhes";
1349  aMap["Pasta.Retro"] = "B.Paste";
1350  aMap["Pasta.Fronte"] = "F.Paste";
1351  aMap["Serigrafia.Retro"] = "B.SilkS";
1352  aMap["Serigrafia.Fronte"] = "F.SilkS";
1353  aMap["Maschera.Retro"] = "B.Mask";
1354  aMap["Maschera.Fronte"] = "F.Mask";
1355  aMap["Grafica"] = "Dwgs.User";
1356  aMap["Commenti"] = "Cmts.User";
1357  aMap["Eco1"] = "Eco1.User";
1358  aMap["Eco2"] = "Eco2.User";
1359  aMap["Contorno.scheda"] = "Edge.Cuts";
1360 
1361  // Polish
1362  aMap["Kleju_Dolna"] = "B.Adhes";
1363  aMap["Kleju_Gorna"] = "F.Adhes";
1364  aMap["Pasty_Dolna"] = "B.Paste";
1365  aMap["Pasty_Gorna"] = "F.Paste";
1366  aMap["Opisowa_Dolna"] = "B.SilkS";
1367  aMap["Opisowa_Gorna"] = "F.SilkS";
1368  aMap["Maski_Dolna"] = "B.Mask";
1369  aMap["Maski_Gorna"] = "F.Mask";
1370  aMap["Rysunkowa"] = "Dwgs.User";
1371  aMap["Komentarzy"] = "Cmts.User";
1372  aMap["ECO1"] = "Eco1.User";
1373  aMap["ECO2"] = "Eco2.User";
1374  aMap["Krawedziowa"] = "Edge.Cuts";
1375 
1376  // French
1377  aMap["Dessous.Adhes"] = "B.Adhes";
1378  aMap["Dessus.Adhes"] = "F.Adhes";
1379  aMap["Dessous.Pate"] = "B.Paste";
1380  aMap["Dessus.Pate"] = "F.Paste";
1381  aMap["Dessous.SilkS"] = "B.SilkS";
1382  aMap["Dessus.SilkS"] = "F.SilkS";
1383  aMap["Dessous.Masque"] = "B.Mask";
1384  aMap["Dessus.Masque"] = "F.Mask";
1385  aMap["Dessin.User"] = "Dwgs.User";
1386  aMap["Contours.Ci"] = "Edge.Cuts";
1387 }

◆ CurStrToKIID()

KIID PCB_PARSER::CurStrToKIID ( )
private

Definition at line 5067 of file pcb_parser.cpp.

5068 {
5069  KIID aId;
5070 
5071  if( m_resetKIIDs )
5072  {
5073  aId = KIID();
5074  m_resetKIIDMap.insert( std::make_pair( CurStr(), aId ) );
5075  }
5076  else
5077  {
5078  aId = KIID( CurStr() );
5079  }
5080 
5081  return aId;
5082 }
KIID_MAP m_resetKIIDMap
Definition: pcb_parser.h:368
Definition: kiid.h:44
bool m_resetKIIDs
reading into an existing board; reset UUIDs
Definition: pcb_parser.h:365

◆ 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 130 of file pcb_parser.h.

131  {
132  if( ( aNetCode >= 0 ) && ( aNetCode < (int) m_netCodes.size() ) )
133  return m_netCodes[aNetCode];
134 
135  return aNetCode;
136  }
std::vector< int > m_netCodes
net codes mapping for boards being loaded
Definition: pcb_parser.h:362

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 184 of file pcb_parser.cpp.

185 {
186  int year, month, day;
187 
188  year = m_requiredVersion / 10000;
189  month = ( m_requiredVersion / 100 ) - ( year * 100 );
190  day = m_requiredVersion - ( year * 10000 ) - ( month * 100 );
191 
192  // wx throws an assertion, not a catchable exception, when the date is invalid.
193  // User input shouldn't give wx asserts, so check manually and throw a proper
194  // error instead
195  if( day <= 0 || month <= 0 || month > 12 ||
196  day > wxDateTime::GetNumberOfDays( (wxDateTime::Month)( month - 1 ), year ) )
197  {
198  wxString err;
199  err.Printf( _( "Cannot interpret date code %d" ), m_requiredVersion );
200  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
201  }
202 
203  wxDateTime date( day, (wxDateTime::Month)( month - 1 ), year, 0, 0, 0, 0 );
204  return date.FormatDate();
205 }
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:164
int m_requiredVersion
set to the KiCad format version this board requires
Definition: pcb_parser.h:364
#define _(s)
Definition: 3d_actions.cpp:33

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 61 of file pcb_parser.cpp.

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

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 116 of file pcb_parser.h.

117  {
118  return m_tooRecent;
119  }
bool m_tooRecent
true if version parses as later than supported
Definition: pcb_parser.h:363

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 1524 of file pcb_parser.cpp.

1525 {
1526  // avoid constructing another std::string, use lexer's directly
1527  typename M::const_iterator it = aMap.find( curText );
1528 
1529  if( it == aMap.end() )
1530  {
1531  m_undefinedLayers.insert( curText );
1532  return Rescue;
1533  }
1534 
1535  // Some files may have saved items to the Rescue Layer due to an issue in v5
1536  if( it->second == Rescue )
1537  m_undefinedLayers.insert( curText );
1538 
1539  return it->second;
1540 }
std::set< wxString > m_undefinedLayers
set of layers not defined in layers section
Definition: pcb_parser.h:361

References Rescue.

◆ Parse()

BOARD_ITEM * PCB_PARSER::Parse ( )

Definition at line 473 of file pcb_parser.cpp.

474 {
475  T token;
476  BOARD_ITEM* item;
477  LOCALE_IO toggle;
478 
479  m_groupInfos.clear();
480 
481  // FOOTPRINTS can be prefixed with an initial block of single line comments and these are
482  // kept for Format() so they round trip in s-expression form. BOARDs might eventually do
483  // the same, but currently do not.
484  std::unique_ptr<wxArrayString> initial_comments( ReadCommentLines() );
485 
486  token = CurTok();
487 
488  if( token != T_LEFT )
489  Expecting( T_LEFT );
490 
491  switch( NextTok() )
492  {
493  case T_kicad_pcb:
494  if( m_board == NULL )
495  m_board = new BOARD();
496 
497  item = (BOARD_ITEM*) parseBOARD();
498  break;
499 
500  case T_module: // legacy token
501  case T_footprint:
502  item = (BOARD_ITEM*) parseFOOTPRINT( initial_comments.release() );
503  break;
504 
505  default:
506  wxString err;
507  err.Printf( _( "Unknown token \"%s\"" ), FromUTF8() );
508  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
509  }
510 
511  resolveGroups( item );
512 
513  return item;
514 }
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:82
BOARD * parseBOARD()
Definition: pcb_parser.cpp:517
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:164
#define NULL
FOOTPRINT * parseFOOTPRINT(wxArrayString *aInitialComments=0)
std::vector< GROUP_INFO > m_groupInfos
Definition: pcb_parser.h:384
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:190
#define _(s)
Definition: 3d_actions.cpp:33
BOARD * m_board
Definition: pcb_parser.h:358
void resolveGroups(BOARD_ITEM *aParent)
Called after parsing a footprint definition or board to build the group membership lists.
Definition: pcb_parser.cpp:756

References _, NULL, 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 367 of file pcb_parser.cpp.

368 {
369  wxCHECK_MSG( CurTok() == T_model, NULL,
370  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as FP_3DMODEL." ) );
371 
372  T token;
373 
374  FP_3DMODEL* n3D = new FP_3DMODEL;
375  NeedSYMBOLorNUMBER();
376  n3D->m_Filename = FromUTF8();
377 
378  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
379  {
380  if( token == T_LEFT )
381  token = NextTok();
382 
383  switch( token )
384  {
385  case T_at:
386  NeedLEFT();
387  token = NextTok();
388 
389  if( token != T_xyz )
390  Expecting( T_xyz );
391 
392  /* Note:
393  * Prior to KiCad v5, model offset was designated by "at",
394  * and the units were in inches.
395  * Now we use mm, but support reading of legacy files
396  */
397 
398  n3D->m_Offset.x = parseDouble( "x value" ) * 25.4f;
399  n3D->m_Offset.y = parseDouble( "y value" ) * 25.4f;
400  n3D->m_Offset.z = parseDouble( "z value" ) * 25.4f;
401 
402  NeedRIGHT(); // xyz
403  NeedRIGHT(); // at
404  break;
405 
406  case T_hide:
407  n3D->m_Show = false;
408  break;
409 
410  case T_opacity:
411  n3D->m_Opacity = parseDouble( "opacity value" );
412  NeedRIGHT();
413  break;
414 
415  case T_offset:
416  NeedLEFT();
417  token = NextTok();
418 
419  if( token != T_xyz )
420  Expecting( T_xyz );
421 
422  /*
423  * 3D model offset is in mm
424  */
425  n3D->m_Offset.x = parseDouble( "x value" );
426  n3D->m_Offset.y = parseDouble( "y value" );
427  n3D->m_Offset.z = parseDouble( "z value" );
428 
429  NeedRIGHT(); // xyz
430  NeedRIGHT(); // offset
431  break;
432 
433  case T_scale:
434  NeedLEFT();
435  token = NextTok();
436 
437  if( token != T_xyz )
438  Expecting( T_xyz );
439 
440  n3D->m_Scale.x = parseDouble( "x value" );
441  n3D->m_Scale.y = parseDouble( "y value" );
442  n3D->m_Scale.z = parseDouble( "z value" );
443 
444  NeedRIGHT(); // xyz
445  NeedRIGHT(); // scale
446  break;
447 
448  case T_rotate:
449  NeedLEFT();
450  token = NextTok();
451 
452  if( token != T_xyz )
453  Expecting( T_xyz );
454 
455  n3D->m_Rotation.x = parseDouble( "x value" );
456  n3D->m_Rotation.y = parseDouble( "y value" );
457  n3D->m_Rotation.z = parseDouble( "z value" );
458 
459  NeedRIGHT(); // xyz
460  NeedRIGHT(); // rotate
461  break;
462 
463  default:
464  Expecting( "at, hide, opacity, offset, scale, or rotate" );
465  }
466 
467  }
468 
469  return n3D;
470 }
VECTOR3D m_Offset
3D model offset (mm)
Definition: footprint.h:95
bool m_Show
Include model in rendering.
Definition: footprint.h:98
#define NULL
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:139

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, NULL, parseDouble(), FP_3DMODEL::VECTOR3D::x, FP_3DMODEL::VECTOR3D::y, and FP_3DMODEL::VECTOR3D::z.

◆ parseARC()

ARC * PCB_PARSER::parseARC ( )
private

We continue to parse the status field but it is no longer written

Definition at line 4183 of file pcb_parser.cpp.

4184 {
4185  wxCHECK_MSG( CurTok() == T_arc, NULL,
4186  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as ARC." ) );
4187 
4188  wxPoint pt;
4189  T token;
4190 
4191  std::unique_ptr<ARC> arc = std::make_unique<ARC>( m_board );
4192 
4193  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4194  {
4195  if( token != T_LEFT )
4196  Expecting( T_LEFT );
4197 
4198  token = NextTok();
4199 
4200  switch( token )
4201  {
4202  case T_start:
4203  pt.x = parseBoardUnits( "start x" );
4204  pt.y = parseBoardUnits( "start y" );
4205  arc->SetStart( pt );
4206  break;
4207 
4208  case T_mid:
4209  pt.x = parseBoardUnits( "mid x" );
4210  pt.y = parseBoardUnits( "mid y" );
4211  arc->SetMid( pt );
4212  break;
4213 
4214  case T_end:
4215  pt.x = parseBoardUnits( "end x" );
4216  pt.y = parseBoardUnits( "end y" );
4217  arc->SetEnd( pt );
4218  break;
4219 
4220  case T_width:
4221  arc->SetWidth( parseBoardUnits( "width" ) );
4222  break;
4223 
4224  case T_layer:
4225  arc->SetLayer( parseBoardItemLayer() );
4226  break;
4227 
4228  case T_net:
4229  if( !arc->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
4231  _( "Invalid net ID in\nfile: \"%s\"\nline: %d\noffset: %d" ), CurSource(),
4232  CurLineNumber(), CurOffset() ) );
4233  break;
4234 
4235  case T_tstamp:
4236  NextTok();
4237  const_cast<KIID&>( arc->m_Uuid ) = CurStrToKIID();
4238  break;
4239 
4241  case T_status:
4242  arc->SetStatus( static_cast<STATUS_FLAGS>( parseHex() ) );
4243  break;
4244 
4245  case T_locked:
4246  arc->SetLocked( true );
4247  break;
4248 
4249  default:
4250  Expecting( "start, mid, end, width, layer, net, tstamp, or status" );
4251  }
4252 
4253  NeedRIGHT();
4254  }
4255 
4256  return arc.release();
4257 }
KIID CurStrToKIID()
int parseBoardUnits()
Definition: pcb_parser.h:287
#define NULL
PCB_LAYER_ID parseBoardItemLayer()
Parse the layer definition of a BOARD_ITEM object.
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 _(s)
Definition: 3d_actions.cpp:33
int getNetCode(int aNetCode)
< Convert net code using the mapping table if available, otherwise returns unchanged net code if < 0 ...
Definition: pcb_parser.h:130
BOARD * m_board
Definition: pcb_parser.h:358
long parseHex()
Definition: pcb_parser.h:335
int parseInt()
Definition: pcb_parser.h:324
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38

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

◆ parseBOARD()

BOARD * PCB_PARSER::parseBOARD ( )
private

Definition at line 517 of file pcb_parser.cpp.

518 {
519  try
520  {
521  return parseBOARD_unchecked();
522  }
523  catch( const PARSE_ERROR& parse_error )
524  {
525  if( m_tooRecent )
526  throw FUTURE_FORMAT_ERROR( parse_error, GetRequiredVersion() );
527  else
528  throw;
529  }
530 }
bool m_tooRecent
true if version parses as later than supported
Definition: pcb_parser.h:363
wxString GetRequiredVersion()
Return a string representing the version of KiCad required to open this file.
Definition: pcb_parser.cpp:184
BOARD * parseBOARD_unchecked()
Definition: pcb_parser.cpp:533
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 533 of file pcb_parser.cpp.

534 {
535  T token;
536  std::map<wxString, wxString> properties;
537 
538  parseHeader();
539 
540  std::vector<BOARD_ITEM*> bulkAddedItems;
541  BOARD_ITEM* item = nullptr;
542 
543  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
544  {
545  if( token != T_LEFT )
546  Expecting( T_LEFT );
547 
548  token = NextTok();
549 
550  if( token == T_page && m_requiredVersion <= 20200119 )
551  token = T_paper;
552 
553  switch( token )
554  {
555  case T_general:
557  break;
558 
559  case T_paper:
560  parsePAGE_INFO();
561  break;
562 
563  case T_title_block:
565  break;
566 
567  case T_layers:
568  parseLayers();
569  break;
570 
571  case T_setup:
572  parseSetup();
573  break;
574 
575  case T_property:
576  properties.insert( parseProperty() );
577  break;
578 
579  case T_net:
581  break;
582 
583  case T_net_class:
584  parseNETCLASS();
586  break;
587 
588  case T_gr_arc:
589  case T_gr_curve:
590  case T_gr_line:
591  case T_gr_poly:
592  case T_gr_circle:
593  case T_gr_rect:
594  item = parsePCB_SHAPE();
596  bulkAddedItems.push_back( item );
597  break;
598 
599  case T_gr_text:
600  item = parsePCB_TEXT();
602  bulkAddedItems.push_back( item );
603  break;
604 
605  case T_dimension:
606  item = parseDIMENSION();
608  bulkAddedItems.push_back( item );
609  break;
610 
611  case T_module: // legacy token
612  case T_footprint:
613  item = parseFOOTPRINT();
615  bulkAddedItems.push_back( item );
616  break;
617 
618  case T_segment:
619  item = parseTRACK();
621  bulkAddedItems.push_back( item );
622  break;
623 
624  case T_arc:
625  item = parseARC();
627  bulkAddedItems.push_back( item );
628  break;
629 
630  case T_group:
631  parseGROUP( m_board );
632  break;
633 
634  case T_via:
635  item = parseVIA();
637  bulkAddedItems.push_back( item );
638  break;
639 
640  case T_zone:
641  item = parseZONE( m_board );
643  bulkAddedItems.push_back( item );
644  break;
645 
646  case T_target:
647  item = parsePCB_TARGET();
649  bulkAddedItems.push_back( item );
650  break;
651 
652  default:
653  wxString err;
654  err.Printf( _( "Unknown token \"%s\"" ), FromUTF8() );
655  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
656  }
657  }
658 
659  if( bulkAddedItems.size() > 0 )
660  m_board->FinalizeBulkAdd( bulkAddedItems );
661 
662  m_board->SetProperties( properties );
663 
664  if( m_undefinedLayers.size() > 0 )
665  {
666  bool deleteItems;
667  std::vector<BOARD_ITEM*> deleteList;
668  wxString msg = wxString::Format( _( "Items found on undefined layers. Do you wish to\n"
669  "rescue them to the User.Comments layer?" ) );
670  wxString details = wxString::Format( _( "Undefined layers:" ) );
671 
672  for( const wxString& undefinedLayer : m_undefinedLayers )
673  details += wxT( "\n " ) + undefinedLayer;
674 
675  wxRichMessageDialog dlg( nullptr, msg, _( "Warning" ),
676  wxYES_NO | wxCANCEL | wxCENTRE | wxICON_WARNING | wxSTAY_ON_TOP );
677  dlg.ShowDetailedText( details );
678  dlg.SetYesNoCancelLabels( _( "Rescue" ), _( "Delete" ), _( "Cancel" ) );
679 
680  switch( dlg.ShowModal() )
681  {
682  case wxID_YES: deleteItems = false; break;
683  case wxID_NO: deleteItems = true; break;
684  case wxID_CANCEL:
685  default: THROW_IO_ERROR( wxT( "CANCEL" ) );
686  }
687 
688  auto visitItem = [&]( BOARD_ITEM* curr_item )
689  {
690  if( curr_item->GetLayer() == Rescue )
691  {
692  if( deleteItems )
693  deleteList.push_back( curr_item );
694  else
695  curr_item->SetLayer( Cmts_User );
696  }
697  };
698 
699  for( auto segm : m_board->Tracks() )
700  {
701  if( segm->Type() == PCB_VIA_T )
702  {
703  VIA* via = (VIA*) segm;
704  PCB_LAYER_ID top_layer, bottom_layer;
705 
706  if( via->GetViaType() == VIATYPE::THROUGH )
707  continue;
708 
709  via->LayerPair( &top_layer, &bottom_layer );
710 
711  if( top_layer == Rescue || bottom_layer == Rescue )
712  {
713  if( deleteItems )
714  deleteList.push_back( via );
715  else
716  {
717  if( top_layer == Rescue )
718  top_layer = F_Cu;
719 
720  if( bottom_layer == Rescue )
721  bottom_layer = B_Cu;
722 
723  via->SetLayerPair( top_layer, bottom_layer );
724  }
725  }
726  }
727  else
728  visitItem( segm );
729  }
730 
731  for( BOARD_ITEM* zone : m_board->Zones() )
732  visitItem( zone );
733 
734  for( BOARD_ITEM* drawing : m_board->Drawings() )
735  visitItem( drawing );
736 
737  for( FOOTPRINT* fp : m_board->Footprints() )
738  {
739  for( BOARD_ITEM* drawing : fp->GraphicalItems() )
740  visitItem( drawing );
741 
742  for( BOARD_ITEM* zone : fp->Zones() )
743  visitItem( zone );
744  }
745 
746  for( BOARD_ITEM* curr_item : deleteList )
747  m_board->Delete( curr_item );
748 
749  m_undefinedLayers.clear();
750  }
751 
752  return m_board;
753 }
void parseHeader()
Definition: pcb_parser.cpp:849
void LayerPair(PCB_LAYER_ID *top_layer, PCB_LAYER_ID *bottom_layer) const
Function LayerPair Return the 2 layers used by the via (the via actually uses all layers between thes...
Definition: track.cpp:435
Definition: track.h:343
ZONES & Zones()
Definition: board.h:309
bool m_LegacyNetclassesLoaded
True if netclasses were loaded from the file.
Definition: board.h:342
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:82
void SetProperties(const std::map< wxString, wxString > &aProps)
Definition: board.h:329
TRACK * parseTRACK()
VIA * parseVIA()
void parseNETINFO_ITEM()
ARC * parseARC()
void parseTITLE_BLOCK()
Definition: pcb_parser.cpp:979
PCB_SHAPE * parsePCB_SHAPE()
void parseLayers()
void parsePAGE_INFO()
Definition: pcb_parser.cpp:923
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT) override
Adds an item to the container.
Definition: board.cpp:563
PCB_LAYER_ID
A quick note on layer IDs:
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:164
std::pair< wxString, wxString > parseProperty()
Definition: pcb_parser.cpp:240
PCB_TEXT * parsePCB_TEXT()
FOOTPRINTS & Footprints()
Definition: board.h:303
PCB_TARGET * parsePCB_TARGET()
FOOTPRINT * parseFOOTPRINT(wxArrayString *aInitialComments=0)
void SetLayerPair(PCB_LAYER_ID aTopLayer, PCB_LAYER_ID aBottomLayer)
Function SetLayerPair For a via m_layer contains the top layer, the other layer is in m_bottomLayer.
Definition: track.cpp:414
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:653
void parseGROUP(BOARD_ITEM *aParent)
int m_requiredVersion
set to the KiCad format version this board requires
Definition: pcb_parser.h:364
#define _(s)
Definition: 3d_actions.cpp:33
BOARD * m_board
Definition: pcb_parser.h:358
void parseGeneralSection()
Definition: pcb_parser.cpp:890
VIATYPE GetViaType() const
Definition: track.h:373
virtual void Delete(BOARD_ITEM *aItem)
Removes an item from the container and deletes it.
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
DIMENSION_BASE * parseDIMENSION()
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
DRAWINGS & Drawings()
Definition: board.h:306
TRACKS & Tracks()
Definition: board.h:300
void parseSetup()
std::set< wxString > m_undefinedLayers
set of layers not defined in layers section
Definition: pcb_parser.h:361
ZONE * parseZONE(BOARD_ITEM_CONTAINER *aParent)

References _, B_Cu, BULK_APPEND, Cmts_User, F_Cu, Format(), VIA::GetViaType(), VIA::LayerPair(), PCB_VIA_T, Rescue, VIA::SetLayerPair(), THROUGH, THROW_IO_ERROR, and THROW_PARSE_ERROR.

◆ 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 1543 of file pcb_parser.cpp.

1544 {
1545  wxCHECK_MSG( CurTok() == T_layer, UNDEFINED_LAYER,
1546  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as layer." ) );
1547 
1548  NextTok();
1549 
1550  PCB_LAYER_ID layerIndex = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
1551 
1552  // Handle closing ) in object parser.
1553 
1554  return layerIndex;
1555 }
PCB_LAYER_ID
A quick note on layer IDs:
LAYER_ID_MAP m_layerIndices
map layer name to it's index
Definition: pcb_parser.h:359

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 1558 of file pcb_parser.cpp.

1559 {
1560  wxCHECK_MSG( CurTok() == T_layers, LSET(),
1561  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
1562  wxT( " as item layer mask." ) );
1563 
1564  LSET layerMask;
1565 
1566  for( T token = NextTok(); token != T_RIGHT; token = NextTok() )
1567  {
1568  LSET mask = lookUpLayer<LSET>( m_layerMasks );
1569  layerMask |= mask;
1570  }
1571 
1572  return layerMask;
1573 }
LSET is a set of PCB_LAYER_IDs.
LSET_MAP m_layerMasks
map layer names to their masks
Definition: pcb_parser.h:360

◆ parseBoardStackup()

void PCB_PARSER::parseBoardStackup ( )
private

Definition at line 1144 of file pcb_parser.cpp.

1145 {
1146  T token;
1147  wxString name;
1148  int dielectric_idx = 1; // the index of dielectric layers
1150 
1151  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1152  {
1153  if( CurTok() != T_LEFT )
1154  Expecting( T_LEFT );
1155 
1156  token = NextTok();
1157 
1158  if( token != T_layer )
1159  {
1160  switch( token )
1161  {
1162  case T_copper_finish:
1163  NeedSYMBOL();
1164  stackup.m_FinishType = FromUTF8();
1165  NeedRIGHT();
1166  break;
1167 
1168  case T_edge_plating:
1169  token = NextTok();
1170  stackup.m_EdgePlating = token == T_yes;
1171  NeedRIGHT();
1172  break;
1173 
1174  case T_dielectric_constraints:
1175  token = NextTok();
1176  stackup.m_HasDielectricConstrains = token == T_yes;
1177  NeedRIGHT();
1178  break;
1179 
1180  case T_edge_connector:
1181  token = NextTok();
1183 
1184  if( token == T_yes )
1186  else if( token == T_bevelled )
1188 
1189  NeedRIGHT();
1190  break;
1191 
1192  case T_castellated_pads:
1193  token = NextTok();
1194  stackup.m_CastellatedPads = token == T_yes;
1195  NeedRIGHT();
1196  break;
1197 
1198  default:
1199  // Currently, skip this item if not defined, because the stackup def
1200  // is a moving target
1201  //Expecting( "copper_finish, edge_plating, dielectric_constrains, edge_connector, castellated_pads" );
1202  skipCurrent();
1203  break;
1204  }
1205 
1206  continue;
1207  }
1208 
1209  NeedSYMBOL();
1210  name = FromUTF8();
1211 
1212  // init the layer id. For dielectric, layer id = UNDEFINED_LAYER
1213  PCB_LAYER_ID layerId = m_board->GetLayerID( name );
1214 
1215  // Init the type
1217 
1218  if( layerId == F_SilkS || layerId == B_SilkS )
1219  type = BS_ITEM_TYPE_SILKSCREEN;
1220  else if( layerId == F_Mask || layerId == B_Mask )
1221  type = BS_ITEM_TYPE_SOLDERMASK;
1222  else if( layerId == F_Paste || layerId == B_Paste )
1223  type = BS_ITEM_TYPE_SOLDERPASTE;
1224  else if( layerId == UNDEFINED_LAYER )
1225  type = BS_ITEM_TYPE_DIELECTRIC;
1226  else if( layerId >= F_Cu && layerId <= B_Cu )
1227  type = BS_ITEM_TYPE_COPPER;
1228 
1229  BOARD_STACKUP_ITEM* item = nullptr;
1230 
1231  if( type != BS_ITEM_TYPE_UNDEFINED )
1232  {
1233  item = new BOARD_STACKUP_ITEM( type );
1234  item->SetBrdLayerId( layerId );
1235 
1236  if( type == BS_ITEM_TYPE_DIELECTRIC )
1237  item->SetDielectricLayerId( dielectric_idx++ );
1238 
1239  stackup.Add( item );
1240  }
1241  else
1242  Expecting( "layer_name" );
1243 
1244  bool has_next_sublayer = true;
1245  int sublayer_idx = 0; // the index of dielectric sub layers
1246  // sublayer 0 is always existing (main sublayer)
1247 
1248  while( has_next_sublayer )
1249  {
1250  has_next_sublayer = false;
1251 
1252  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1253  {
1254  if( token == T_addsublayer )
1255  {
1256  has_next_sublayer = true;
1257  break;
1258  }
1259 
1260  if( token == T_LEFT )
1261  {
1262  token = NextTok();
1263 
1264  switch( token )
1265  {
1266  case T_type:
1267  NeedSYMBOL();
1268  item->SetTypeName( FromUTF8() );
1269  NeedRIGHT();
1270  break;
1271 
1272  case T_thickness:
1273  item->SetThickness( parseBoardUnits( T_thickness ), sublayer_idx );
1274  token = NextTok();
1275 
1276  if( token == T_LEFT )
1277  break;
1278 
1279  if( token == T_locked )
1280  {
1281  // Dielectric thickness can be locked (for impedance controlled layers)
1282  if( type == BS_ITEM_TYPE_DIELECTRIC )
1283  item->SetThicknessLocked( true, sublayer_idx );
1284 
1285  NeedRIGHT();
1286  }
1287  break;
1288 
1289  case T_material:
1290  NeedSYMBOL();
1291  item->SetMaterial( FromUTF8(), sublayer_idx );
1292  NeedRIGHT();
1293  break;
1294 
1295  case T_epsilon_r:
1296  NextTok();
1297  item->SetEpsilonR( parseDouble(), sublayer_idx );
1298  NeedRIGHT();
1299  break;
1300 
1301  case T_loss_tangent:
1302  NextTok();
1303  item->SetLossTangent( parseDouble(), sublayer_idx );
1304  NeedRIGHT();
1305  break;
1306 
1307  case T_color:
1308  NeedSYMBOL();
1309  item->SetColor( FromUTF8() );
1310  NeedRIGHT();
1311  break;
1312 
1313  default:
1314  // Currently, skip this item if not defined, because the stackup def
1315  // is a moving target
1316  //Expecting( "type, thickness, material, epsilon_r, loss_tangent, color" );
1317  skipCurrent();
1318  }
1319  }
1320  }
1321 
1322  if( has_next_sublayer ) // Prepare reading the next sublayer description
1323  {
1324  sublayer_idx++;
1325  item->AddDielectricPrms( sublayer_idx );
1326  }
1327  }
1328  }
1329 
1330  if( token != T_RIGHT )
1331  {
1332  Expecting( ")" );
1333  }
1334 
1335  // Success:
1337 }
const PCB_LAYER_ID GetLayerID(const wxString &aLayerName) const
Return the ID of a layer.
Definition: board.cpp:320
void SetBrdLayerId(PCB_LAYER_ID aBrdLayerId)
void SetTypeName(const wxString &aName)
this class manage the layers needed to make a physical board they are solder mask,...
wxString m_FinishType
The name of external copper finish.
bool m_EdgePlating
True if the edge board is plated.
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.
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.h:591
int parseBoardUnits()
Definition: pcb_parser.h:287
void skipCurrent()
Skip the current token level, i.e search for the RIGHT parenthesis which closes the current descripti...
Definition: pcb_parser.cpp:106
bool m_HasDielectricConstrains
True if some layers have impedance controlled tracks or have specific constrains for micro-wave appli...
BOARD_STACKUP & GetStackupDescriptor()
PCB_LAYER_ID
A quick note on layer IDs:
void SetDielectricLayerId(int aLayerId)
void SetMaterial(const wxString &aName, int aDielectricSubLayer=0)
this class manage one layer needed to make a physical board it can be a solder mask,...
void SetEpsilonR(double aEpsilon, int aDielectricSubLayer=0)
void AddDielectricPrms(int aDielectricPrmsIdx)
true if this stackup item must be taken in account, false to ignore it.
void SetThickness(int aThickness, int aDielectricSubLayer=0)
void SetThicknessLocked(bool aLocked, int aDielectricSubLayer=0)
const char * name
Definition: DXF_plotter.cpp:59
BOARD * m_board
Definition: pcb_parser.h:358
BOARD_STACKUP_ITEM_TYPE
double parseDouble()
Parse the current token as an ASCII numeric string with possible leading whitespace into a double pre...
Definition: pcb_parser.cpp:139
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)

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, F_Cu, F_Mask, F_Paste, F_SilkS, 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 ( )
inlineprivate

Definition at line 287 of file pcb_parser.h.

288  {
289  // There should be no major rounding issues here, since the values in
290  // the file are in mm and get converted to nano-meters.
291  // See test program tools/test-nm-biu-to-ascii-mm-round-tripping.cpp
292  // to confirm or experiment. Use a similar strategy in both places, here
293  // and in the test program. Make that program with:
294  // $ make test-nm-biu-to-ascii-mm-round-tripping
295  auto retval = parseDouble() * IU_PER_MM;
296 
297  // N.B. we currently represent board units as integers. Any values that are
298  // larger or smaller than those board units represent undefined behavior for
299  // the system. We limit values to the largest that is visible on the screen
300  // This is the diagonal distance of the full screen ~1.5m
301  double int_limit = std::numeric_limits<int>::max() * 0.7071; // 0.7071 = roughly 1/sqrt(2)
302  return KiROUND( Clamp<double>( -int_limit, retval, int_limit ) );
303  }
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:68
double parseDouble()
Parse the current token as an ASCII numeric string with possible leading whitespace into a double pre...
Definition: pcb_parser.cpp:139

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

Referenced by parseBoardUnits().

◆ parseBoardUnits() [2/3]

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

Definition at line 305 of file pcb_parser.h.

306  {
307  auto retval = parseDouble( aExpected ) * IU_PER_MM;
308 
309  // N.B. we currently represent board units as integers. Any values that are
310  // larger or smaller than those board units represent undefined behavior for
311  // the system. We limit values to the largest that is visible on the screen
312  double int_limit = std::numeric_limits<int>::max() * 0.7071;
313 
314  // Use here #KiROUND, not EKIROUND (see comments about them) when having a function as
315  // argument, because it will be called twice with #KIROUND.
316  return KiROUND( Clamp<double>( -int_limit, retval, int_limit ) );
317  }
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:68
double parseDouble()
Parse the current token as an ASCII numeric string with possible leading whitespace into a double pre...
Definition: pcb_parser.cpp:139

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

◆ parseBoardUnits() [3/3]

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

Definition at line 319 of file pcb_parser.h.

320  {
321  return parseBoardUnits( GetTokenText( aToken ) );
322  }
int parseBoardUnits()
Definition: pcb_parser.h:287
const char * GetTokenText(T aTok)
Function GetTokenText is in the DSN namespace and returns the C string representing a SPECCTRA_DB::ke...
Definition: specctra.cpp:69

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

◆ parseBool()

bool PCB_PARSER::parseBool ( )
private

Definition at line 169 of file pcb_parser.cpp.

170 {
171  T token = NextTok();
172 
173  if( token == T_yes )
174  return true;
175  else if( token == T_no )
176  return false;
177  else
178  Expecting( "yes or no" );
179 
180  return false;
181 }

◆ parseDefaults()

void PCB_PARSER::parseDefaults ( BOARD_DESIGN_SETTINGS aSettings)
private

Definition at line 1915 of file pcb_parser.cpp.

1916 {
1917  T token;
1918 
1919  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1920  {
1921  if( token != T_LEFT )
1922  Expecting( T_LEFT );
1923 
1924  token = NextTok();
1925 
1926  switch( token )
1927  {
1928  case T_edge_clearance:
1929  designSettings.m_CopperEdgeClearance = parseBoardUnits( T_edge_clearance );
1931  NeedRIGHT();
1932  break;
1933 
1934  case T_copper_line_width:
1935  designSettings.m_LineThickness[ LAYER_CLASS_COPPER ] = parseBoardUnits( token );
1936  NeedRIGHT();
1937  break;
1938 
1939  case T_copper_text_dims:
1940  parseDefaultTextDims( designSettings, LAYER_CLASS_COPPER );
1941  break;
1942 
1943  case T_courtyard_line_width:
1944  designSettings.m_LineThickness[ LAYER_CLASS_COURTYARD ] = parseBoardUnits( token );
1945  NeedRIGHT();
1946  break;
1947 
1948  case T_edge_cuts_line_width:
1949  designSettings.m_LineThickness[ LAYER_CLASS_EDGES ] = parseBoardUnits( token );
1950  NeedRIGHT();
1951  break;
1952 
1953  case T_silk_line_width:
1954  designSettings.m_LineThickness[ LAYER_CLASS_SILK ] = parseBoardUnits( token );
1955  NeedRIGHT();
1956  break;
1957 
1958  case T_silk_text_dims:
1959  parseDefaultTextDims( designSettings, LAYER_CLASS_SILK );
1960  break;
1961 
1962  case T_fab_layers_line_width:
1963  designSettings.m_LineThickness[ LAYER_CLASS_FAB ] = parseBoardUnits( token );
1964  NeedRIGHT();
1965  break;
1966 
1967  case T_fab_layers_text_dims:
1968  parseDefaultTextDims( designSettings, LAYER_CLASS_FAB );
1969  break;
1970 
1971  case T_other_layers_line_width:
1972  designSettings.m_LineThickness[ LAYER_CLASS_OTHERS ] = parseBoardUnits( token );
1973  NeedRIGHT();
1974  break;
1975 
1976  case T_other_layers_text_dims:
1977  parseDefaultTextDims( designSettings, LAYER_CLASS_OTHERS );
1978  break;
1979 
1980  case T_dimension_units:
1981  designSettings.m_DimensionUnitsMode =
1982  static_cast<DIM_UNITS_MODE>( parseInt( "dimension units" ) );
1983  NeedRIGHT();
1984  break;
1985 
1986  case T_dimension_precision:
1987  designSettings.m_DimensionPrecision = parseInt( "dimension precision" );
1988  NeedRIGHT();
1989  break;
1990 
1991  default:
1992  Unexpected( CurText() );
1993  }
1994  }
1995 }
int parseBoardUnits()
Definition: pcb_parser.h:287
bool m_LegacyCopperEdgeClearanceLoaded
Definition: board.h:339
void parseDefaultTextDims(BOARD_DESIGN_SETTINGS &aSettings, int aLayer)
BOARD * m_board
Definition: pcb_parser.h:358
int parseInt()
Definition: pcb_parser.h:324

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 1998 of file pcb_parser.cpp.

1999 {
2000  T token;
2001 
2002  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2003  {
2004  if( token == T_LEFT )
2005  token = NextTok();
2006 
2007  switch( token )
2008  {
2009  case T_size:
2010  aSettings.m_TextSize[ aLayer ].x = parseBoardUnits( "default text size X" );
2011  aSettings.m_TextSize[ aLayer ].y = parseBoardUnits( "default text size Y" );
2012  NeedRIGHT();
2013  break;
2014 
2015  case T_thickness:
2016  aSettings.m_TextThickness[ aLayer ] = parseBoardUnits( "default text width" );
2017  NeedRIGHT();
2018  break;
2019 
2020  case T_italic:
2021  aSettings.m_TextItalic[ aLayer ] = true;
2022  break;
2023 
2024  case T_keep_upright:
2025  aSettings.m_TextUpright[ aLayer ] = true;
2026  break;
2027 
2028  default:
2029  Expecting( "size, thickness, italic or keep_upright" );
2030  }
2031  }
2032 }
int parseBoardUnits()
Definition: pcb_parser.h:287
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()

DIMENSION_BASE * PCB_PARSER::parseDIMENSION ( )
private

Definition at line 2465 of file pcb_parser.cpp.

2466 {
2467  wxCHECK_MSG( CurTok() == T_dimension, NULL,
2468  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as DIMENSION." ) );
2469 
2470  T token;
2471 
2472  std::unique_ptr<DIMENSION_BASE> dimension;
2473 
2474  // skip value that used to be saved
2475  if( NextTok() != T_LEFT )
2476  NeedLEFT();
2477 
2478  token = NextTok();
2479 
2480  bool isLegacyDimension = false;
2481 
2482  // Old format
2483  if( token == T_width )
2484  {
2485  isLegacyDimension = true;
2486  dimension = std::make_unique<ALIGNED_DIMENSION>( nullptr );
2487  dimension->SetLineThickness( parseBoardUnits( "dimension width value" ) );
2488  NeedRIGHT();
2489  }
2490  else
2491  {
2492  if( token != T_type )
2493  Expecting( T_type );
2494 
2495  switch( NextTok() )
2496  {
2497  case T_aligned:
2498  dimension = std::make_unique<ALIGNED_DIMENSION>( nullptr );
2499  break;
2500 
2501  case T_orthogonal:
2502  dimension = std::make_unique<ORTHOGONAL_DIMENSION>( nullptr );
2503  break;
2504 
2505  case T_leader:
2506  dimension = std::make_unique<LEADER>( nullptr );
2507  break;
2508 
2509  case T_center:
2510  dimension = std::make_unique<CENTER_DIMENSION>( nullptr );
2511  break;
2512 
2513  default:
2514  wxFAIL_MSG( wxT( "Cannot parse unknown dimension type %s" ) +
2515  GetTokenString( CurTok() ) );
2516  }
2517 
2518  NeedRIGHT();
2519  }
2520 
2521  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2522  {
2523  if( token != T_LEFT )
2524  Expecting( T_LEFT );
2525 
2526  token = NextTok();
2527 
2528  switch( token )
2529  {
2530  case T_layer:
2531  dimension->SetLayer( parseBoardItemLayer() );
2532  NeedRIGHT();
2533  break;
2534 
2535  case T_tstamp:
2536  NextTok();
2537  const_cast<KIID&>( dimension->m_Uuid ) = CurStrToKIID();
2538  NeedRIGHT();
2539  break;
2540 
2541  case T_gr_text:
2542  {
2543  PCB_TEXT* text = parsePCB_TEXT();
2544  dimension->Text() = *text;
2545 
2546  // The text is part of the dimension and shares its uuid
2547  const_cast<KIID&>( dimension->Text().m_Uuid ) = dimension->m_Uuid;
2548 
2549  // Fetch other dimension properties out of the text item
2550  dimension->Text().SetTextPos( text->GetTextPos() );
2551 
2552  if( isLegacyDimension )
2553  {
2554  EDA_UNITS units = EDA_UNITS::INCHES;
2555  FetchUnitsFromString( text->GetText(), units );
2556  dimension->SetUnits( units );
2557  }
2558 
2559  delete text;
2560  break;
2561  }
2562 
2563  // New format: feature points
2564  case T_pts:
2565  {
2566  wxPoint point;
2567 
2568  parseXY( &point.x, &point.y );
2569  dimension->SetStart( point );
2570  parseXY( &point.x, &point.y );
2571  dimension->SetEnd( point );
2572 
2573  NeedRIGHT();
2574  break;
2575  }
2576 
2577  case T_height:
2578  {
2579  wxCHECK_MSG( dimension->Type() == PCB_DIM_ALIGNED_T ||
2580  dimension->Type() == PCB_DIM_ORTHOGONAL_T, nullptr,
2581  wxT( "Invalid height token" ) );
2582  ALIGNED_DIMENSION* aligned = static_cast<ALIGNED_DIMENSION*>( dimension.get() );
2583  aligned->SetHeight( parseBoardUnits( "dimension height value" ) );
2584  NeedRIGHT();
2585  break;
2586  }
2587 
2588  case T_orientation:
2589  {
2590  wxCHECK_MSG( dimension->Type() == PCB_DIM_ORTHOGONAL_T, nullptr,
2591  wxT( "Invalid orientation token" ) );
2592  ORTHOGONAL_DIMENSION* ortho = static_cast<ORTHOGONAL_DIMENSION*>( dimension.get() );
2593 
2594  int orientation = parseInt( "orthogonal dimension orientation" );
2595  orientation = std::max( 0, std::min( 1, orientation ) );
2596  ortho->SetOrientation( static_cast<ORTHOGONAL_DIMENSION::DIR>( orientation ) );
2597  NeedRIGHT();
2598  break;
2599  }
2600 
2601  case T_format:
2602  {
2603  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2604  {
2605  switch( token )
2606  {
2607  case T_LEFT:
2608  continue;
2609 
2610  case T_prefix:
2611  NeedSYMBOLorNUMBER();
2612  dimension->SetPrefix( FromUTF8() );
2613  NeedRIGHT();
2614  break;
2615 
2616  case T_suffix:
2617  NeedSYMBOLorNUMBER();
2618  dimension->SetSuffix( FromUTF8() );
2619  NeedRIGHT();
2620  break;
2621 
2622  case T_units:
2623  {
2624  int mode = parseInt( "dimension units mode" );
2625  mode = std::max( 0, std::min( 4, mode ) );
2626  dimension->SetUnitsMode( static_cast<DIM_UNITS_MODE>( mode ) );
2627  NeedRIGHT();
2628  break;
2629  }
2630 
2631  case T_units_format:
2632  {
2633  int format = parseInt( "dimension units format" );
2634  format = std::max( 0, std::min( 3, format ) );
2635  dimension->SetUnitsFormat( static_cast<DIM_UNITS_FORMAT>( format ) );
2636  NeedRIGHT();
2637  break;
2638  }
2639 
2640  case T_precision:
2641  dimension->SetPrecision( parseInt( "dimension precision" ) );
2642  NeedRIGHT();
2643  break;
2644 
2645  case T_override_value:
2646  NeedSYMBOLorNUMBER();
2647  dimension->SetOverrideTextEnabled( true );
2648  dimension->SetOverrideText( FromUTF8() );
2649  NeedRIGHT();
2650  break;
2651 
2652  case T_suppress_zeroes:
2653  dimension->SetSuppressZeroes( true );
2654  break;
2655 
2656  default:
2657  Expecting( "prefix, suffix, units, units_format, precision, override_value, "
2658  "suppress_zeroes" );
2659  }
2660  }
2661  break;
2662  }
2663 
2664  case T_style:
2665  {
2666  // new format: default to keep text aligned off unless token is present
2667  dimension->SetKeepTextAligned( false );
2668 
2669  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2670  {
2671  switch( token )
2672  {
2673  case T_LEFT:
2674  continue;
2675 
2676  case T_thickness:
2677  dimension->SetLineThickness( parseBoardUnits( "extension line thickness" ) );
2678  NeedRIGHT();
2679  break;
2680 
2681  case T_arrow_length:
2682  dimension->SetArrowLength( parseBoardUnits( "arrow length" ) );
2683  NeedRIGHT();
2684  break;
2685 
2686  case T_text_position_mode:
2687  {
2688  int mode = parseInt( "dimension text position mode" );
2689  mode = std::max( 0, std::min( 3, mode ) );
2690  dimension->SetTextPositionMode( static_cast<DIM_TEXT_POSITION>( mode ) );
2691  NeedRIGHT();
2692  break;
2693  }
2694 
2695  case T_extension_height:
2696  {
2697  ALIGNED_DIMENSION* aligned = dynamic_cast<ALIGNED_DIMENSION*>( dimension.get() );
2698  wxCHECK_MSG( aligned, nullptr, wxT( "Invalid extension_height token" ) );
2699  aligned->SetExtensionHeight( parseBoardUnits( "extension height" ) );
2700  NeedRIGHT();
2701  break;
2702  }
2703 
2704  case T_extension_offset:
2705  dimension->SetExtensionOffset( parseBoardUnits( "extension offset" ) );
2706  NeedRIGHT();
2707  break;
2708 
2709  case T_keep_text_aligned:
2710  dimension->SetKeepTextAligned( true );
2711  break;
2712 
2713  case T_text_frame:
2714  {
2715  wxCHECK_MSG( dimension->Type() == PCB_DIM_LEADER_T, nullptr,
2716  wxT( "Invalid text_frame token" ) );
2717  LEADER* leader = static_cast<LEADER*>( dimension.get() );
2718 
2719  int textFrame = parseInt( "dimension text frame mode" );
2720  textFrame = std::max( 0, std::min( 3, textFrame ) );
2721  leader->SetTextFrame( static_cast<DIM_TEXT_FRAME>( textFrame ) );
2722  NeedRIGHT();
2723  break;
2724  }
2725 
2726  default:
2727  Expecting( "thickness, arrow_length, text_position_mode, extension_height, "
2728  "extension_offset" );
2729  }
2730  }
2731 
2732  break;
2733  }
2734 
2735  // Old format: feature1 stores a feature line. We only care about the origin.
2736  case T_feature1:
2737  {
2738  NeedLEFT();
2739  token = NextTok();
2740 
2741  if( token != T_pts )
2742  Expecting( T_pts );
2743 
2744  wxPoint point;
2745 
2746  parseXY( &point.x, &point.y );
2747  dimension->SetStart( point );
2748 
2749  parseXY( nullptr, nullptr ); // Ignore second point
2750  NeedRIGHT();
2751  NeedRIGHT();
2752  break;
2753  }
2754 
2755  // Old format: feature2 stores a feature line. We only care about the end point.
2756  case T_feature2:
2757  {
2758  NeedLEFT();
2759  token = NextTok();
2760 
2761  if( token != T_pts )
2762  Expecting( T_pts );
2763 
2764  wxPoint point;
2765 
2766  parseXY( &point.x, &point.y );
2767  dimension->SetEnd( point );
2768 
2769  parseXY( nullptr, nullptr ); // Ignore second point
2770 
2771  NeedRIGHT();
2772  NeedRIGHT();
2773  break;
2774  }
2775 
2776  case T_crossbar:
2777  {
2778  NeedLEFT();
2779  token = NextTok();
2780 
2781  if( token == T_pts )
2782  {
2783  // If we have a crossbar, we know we're an old aligned dimension
2784  ALIGNED_DIMENSION* aligned = static_cast<ALIGNED_DIMENSION*>( dimension.get() );
2785 
2786  // Old style: calculate height from crossbar
2787  wxPoint point1, point2;
2788  parseXY( &point1.x, &point1.y );
2789  parseXY( &point2.x, &point2.y );
2790  aligned->UpdateHeight( point2, point1 ); // Yes, backwards intentionally
2791  NeedRIGHT();
2792  }
2793 
2794  NeedRIGHT();
2795  break;
2796  }
2797 
2798  // Arrow: no longer saved; no-op
2799  case T_arrow1a:
2800  NeedLEFT();
2801  token = NextTok();
2802 
2803  if( token != T_pts )
2804  Expecting( T_pts );
2805 
2806  parseXY( nullptr, nullptr );
2807  parseXY( nullptr, nullptr );
2808  NeedRIGHT();
2809  NeedRIGHT();
2810  break;
2811 
2812  // Arrow: no longer saved; no-op
2813  case T_arrow1b:
2814  NeedLEFT();
2815  token = NextTok();
2816 
2817  if( token != T_pts )
2818  Expecting( T_pts );
2819 
2820  parseXY( nullptr, nullptr );
2821  parseXY( nullptr, nullptr );
2822  NeedRIGHT();
2823  NeedRIGHT();
2824  break;
2825 
2826  // Arrow: no longer saved; no-op
2827  case T_arrow2a:
2828  NeedLEFT();
2829  token = NextTok();
2830 
2831  if( token != T_pts )
2832  Expecting( T_pts );
2833 
2834  parseXY( nullptr, nullptr );
2835  parseXY( nullptr, nullptr );
2836  NeedRIGHT();
2837  NeedRIGHT();
2838  break;
2839 
2840  // Arrow: no longer saved; no-op
2841  case T_arrow2b:
2842  NeedLEFT();
2843  token = NextTok();
2844 
2845  if( token != T_pts )
2846  Expecting( T_pts );
2847 
2848  parseXY( nullptr, nullptr );
2849  parseXY( nullptr, nullptr );
2850  NeedRIGHT();
2851  NeedRIGHT();
2852  break;
2853 
2854  default:
2855  Expecting( "layer, tstamp, gr_text, feature1, feature2, crossbar, arrow1a, "
2856  "arrow1b, arrow2a, or arrow2b" );
2857  }
2858  }
2859 
2860  dimension->Update();
2861 
2862  return dimension.release();
2863 }
KIID CurStrToKIID()
class ALIGNED_DIMENSION, a linear dimension (graphic item)
Definition: typeinfo.h:100
class LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:101
wxPoint parseXY()
Parse a coordinate pair (xy X Y) in board units (mm).
Definition: pcb_parser.cpp:208
int parseBoardUnits()
Definition: pcb_parser.h:287
void SetExtensionHeight(int aHeight)
Definition: dimension.h:379
void SetHeight(int aHeight)
Sets the distance from the feature points to the crossbar line.
Definition: dimension.h:370
void FetchUnitsFromString(const wxString &aTextValue, EDA_UNITS &aUnits)
Function FetchUnitsFromString writes any unit info found in the string to aUnits.
Definition: base_units.cpp:422
#define NULL
A leader is a dimension-like object pointing to a specific point.
Definition: dimension.h:476
PCB_TEXT * parsePCB_TEXT()
An orthogonal dimension is like an aligned dimension, but the extension lines are locked to the X or ...
Definition: dimension.h:413
PCB_LAYER_ID parseBoardItemLayer()
Parse the layer definition of a BOARD_ITEM object.
void UpdateHeight(const wxPoint &aCrossbarStart, const wxPoint &aCrossbarEnd)
Updates stored height basing on points coordinates.
Definition: dimension.cpp:513
const KIID m_Uuid
Definition: eda_item.h:524
EDA_UNITS
Definition: eda_units.h:38
const wxPoint & GetTextPos() const
Definition: eda_text.h:254
class ORTHOGONAL_DIMENSION, a linear dimension constrained to x/y
Definition: typeinfo.h:103
int parseInt()
Definition: pcb_parser.h:324
For better understanding of the points that make a dimension:
Definition: dimension.h:333
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:133

References FetchUnitsFromString(), EDA_TEXT::GetText(), EDA_TEXT::GetTextPos(), INCHES, EDA_ITEM::m_Uuid, NULL, parseInt(), PCB_DIM_ALIGNED_T, PCB_DIM_LEADER_T, PCB_DIM_ORTHOGONAL_T, ALIGNED_DIMENSION::SetExtensionHeight(), ALIGNED_DIMENSION::SetHeight(), and ALIGNED_DIMENSION::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 139 of file pcb_parser.cpp.

140 {
141  char* tmp;
142 
143  errno = 0;
144 
145  double fval = strtod( CurText(), &tmp );
146 
147  if( errno )
148  {
149  wxString error;
150  error.Printf( _( "Invalid floating point number in\nfile: \"%s\"\nline: %d\noffset: %d" ),
151  CurSource(), CurLineNumber(), CurOffset() );
152 
153  THROW_IO_ERROR( error );
154  }
155 
156  if( CurText() == tmp )
157  {
158  wxString error;
159  error.Printf( _( "Missing floating point number in\nfile: \"%s\"\nline: %d\noffset: %d" ),
160  CurSource(), CurLineNumber(), CurOffset() );
161 
162  THROW_IO_ERROR( error );
163  }
164 
165  return fval;
166 }
#define _(s)
Definition: 3d_actions.cpp:33
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38

References _, and THROW_IO_ERROR.

Referenced by parseBoardUnits(), and parseDouble().

◆ parseDouble() [2/3]

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

Definition at line 276 of file pcb_parser.h.

277  {
278  NeedNUMBER( aExpected );
279  return parseDouble();
280  }
double parseDouble()
Parse the current token as an ASCII numeric string with possible leading whitespace into a double pre...
Definition: pcb_parser.cpp:139

References parseDouble().

◆ parseDouble() [3/3]

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

Definition at line 282 of file pcb_parser.h.

283  {
284  return parseDouble( GetTokenText( aToken ) );
285  }
double parseDouble()
Parse the current token as an ASCII numeric string with possible leading whitespace into a double pre...
Definition: pcb_parser.cpp:139
const char * GetTokenText(T aTok)
Function GetTokenText is in the DSN namespace and returns the C string representing a SPECCTRA_DB::ke...
Definition: specctra.cpp:69

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 255 of file pcb_parser.cpp.

256 {
257  wxCHECK_RET( CurTok() == T_effects,
258  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as EDA_TEXT." ) );
259 
260  T token;
261 
262  // Prior to v5.0 text size was omitted from file format if equal to 60mils
263  // Now, it is always explicitly written to file
264  bool foundTextSize = false;
265 
266  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
267  {
268  if( token == T_LEFT )
269  token = NextTok();
270 
271  switch( token )
272  {
273  case T_font:
274  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
275  {
276  if( token == T_LEFT )
277  continue;
278 
279  switch( token )
280  {
281  case T_size:
282  {
283  wxSize sz;
284  sz.SetHeight( parseBoardUnits( "text height" ) );
285  sz.SetWidth( parseBoardUnits( "text width" ) );
286  aText->SetTextSize( sz );
287  NeedRIGHT();
288 
289  foundTextSize = true;
290  }
291  break;
292 
293  case T_thickness:
294  aText->SetTextThickness( parseBoardUnits( "text thickness" ) );
295  NeedRIGHT();
296  break;
297 
298  case T_bold:
299  aText->SetBold( true );
300  break;
301 
302  case T_italic:
303  aText->SetItalic( true );
304  break;
305 
306  default:
307  Expecting( "size, bold, or italic" );
308  }
309  }
310  break;
311 
312  case T_justify:
313  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
314  {
315  if( token == T_LEFT )
316  continue;
317 
318  switch( token )
319  {
320  case T_left:
322  break;
323 
324  case T_right:
326  break;
327 
328  case T_top:
330  break;
331 
332  case T_bottom:
334  break;
335 
336  case T_mirror:
337  aText->SetMirrored( true );
338  break;
339 
340  default:
341  Expecting( "left, right, top, bottom, or mirror" );
342  }
343 
344  }
345  break;
346 
347  case T_hide:
348  aText->SetVisible( false );
349  break;
350 
351  default:
352  Expecting( "font, justify, or hide" );
353  }
354  }
355 
356  // Text size was not specified in file, force legacy default units
357  // 60mils is 1.524mm
358  if( !foundTextSize )
359  {
360  const double defaultTextSize = 1.524 * IU_PER_MM;
361 
362  aText->SetTextSize( wxSize( defaultTextSize, defaultTextSize ) );
363  }
364 }
void SetMirrored(bool isMirrored)
Definition: eda_text.h:195
static constexpr double IU_PER_MM
Mock up a conversion function.
void SetItalic(bool isItalic)
Definition: eda_text.h:186
void SetVisible(bool aVisible)
Definition: eda_text.h:192
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:244
int parseBoardUnits()
Definition: pcb_parser.h:287
void SetVertJustify(EDA_TEXT_VJUSTIFY_T aType)
Definition: eda_text.h:209
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:208
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition: eda_text.h:166
void SetBold(bool aBold)
Definition: eda_text.h:189

References 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::SetTextSize(), EDA_TEXT::SetTextThickness(), EDA_TEXT::SetVertJustify(), and EDA_TEXT::SetVisible().

◆ parseFOOTPRINT()

FOOTPRINT * PCB_PARSER::parseFOOTPRINT ( wxArrayString *  aInitialComments = 0)
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 2866 of file pcb_parser.cpp.

2867 {
2868  try
2869  {
2870  return parseFOOTPRINT_unchecked( aInitialComments );
2871  }
2872  catch( const PARSE_ERROR& parse_error )
2873  {
2874  if( m_tooRecent )
2875  throw FUTURE_FORMAT_ERROR( parse_error, GetRequiredVersion() );
2876  else
2877  throw;
2878  }
2879 }
bool m_tooRecent
true if version parses as later than supported
Definition: pcb_parser.h:363
wxString GetRequiredVersion()
Return a string representing the version of KiCad required to open this file.
Definition: pcb_parser.cpp:184
FOOTPRINT * parseFOOTPRINT_unchecked(wxArrayString *aInitialComments=0)
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 = 0)
private

Definition at line 2882 of file pcb_parser.cpp.

2883 {
2884  wxCHECK_MSG( CurTok() == T_module || CurTok() == T_footprint, NULL,
2885  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as FOOTPRINT." ) );
2886 
2887  wxString name;
2888  wxPoint pt;
2889  T token;
2890  LIB_ID fpid;
2891  int attributes = 0;
2892 
2893  std::unique_ptr<FOOTPRINT> footprint = std::make_unique<FOOTPRINT>( m_board );
2894 
2895  std::map<wxString, wxString> properties;
2896 
2897  footprint->SetInitialComments( aInitialComments );
2898 
2899  token = NextTok();
2900 
2901  if( !IsSymbol( token ) && token != T_NUMBER )
2902  Expecting( "symbol|number" );
2903 
2904  name = FromUTF8();
2905 
2906  if( !name.IsEmpty() && fpid.Parse( name, true ) >= 0 )
2907  {
2908  wxString error;
2909  error.Printf( _( "Invalid footprint ID in\nfile: \"%s\"\nline: %d\noffset: %d" ),
2910  CurSource(), CurLineNumber(), CurOffset() );
2911  THROW_IO_ERROR( error );
2912  }
2913 
2914  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2915  {
2916  if( token == T_LEFT )
2917  token = NextTok();
2918 
2919  switch( token )
2920  {
2921  case T_version:
2922  {
2923  // Theoretically a footprint nested in a PCB could declare its own version, though
2924  // as of writing this comment we don't do that. Just in case, take the greater
2925  // version.
2926  int this_version = parseInt( FromUTF8().mb_str( wxConvUTF8 ) );
2927  NeedRIGHT();
2928  m_requiredVersion = std::max( m_requiredVersion, this_version );
2930  break;
2931  }
2932 
2933  case T_generator:
2934  // We currently ignore the generator when parsing. It is included in the file for manual
2935  // indication of where the footprint came from.
2936  NeedSYMBOL();
2937  NeedRIGHT();
2938  break;
2939 
2940  case T_locked:
2941  footprint->SetLocked( true );
2942  break;
2943 
2944  case T_placed:
2945  footprint->SetIsPlaced( true );
2946  break;
2947 
2948  case T_layer:
2949  {
2950  // Footprints can be only on the front side or the back side.
2951  // but because we can find some stupid layer in file, ensure a
2952  // acceptable layer is set for the footprint
2954  footprint->SetLayer( layer == B_Cu ? B_Cu : F_Cu );
2955  }
2956  NeedRIGHT();
2957  break;
2958 
2959  case T_tedit:
2960  footprint->SetLastEditTime( parseHex() );
2961  NeedRIGHT();
2962  break;
2963 
2964  case T_tstamp:
2965  NextTok();
2966  const_cast<KIID&>( footprint->m_Uuid ) = CurStrToKIID();
2967  NeedRIGHT();
2968  break;
2969 
2970  case T_at:
2971  pt.x = parseBoardUnits( "X coordinate" );
2972  pt.y = parseBoardUnits( "Y coordinate" );
2973  footprint->SetPosition( pt );
2974  token = NextTok();
2975 
2976  if( token == T_NUMBER )
2977  {
2978  footprint->SetOrientation( parseDouble() * 10.0 );
2979  NeedRIGHT();
2980  }
2981  else if( token != T_RIGHT )
2982  {
2983  Expecting( T_RIGHT );
2984  }
2985 
2986  break;
2987 
2988  case T_descr:
2989  NeedSYMBOLorNUMBER(); // some symbols can be 0508, so a number is also a symbol here
2990  footprint->SetDescription( FromUTF8() );
2991  NeedRIGHT();
2992  break;
2993 
2994  case T_tags:
2995  NeedSYMBOLorNUMBER(); // some symbols can be 0508, so a number is also a symbol here
2996  footprint->SetKeywords( FromUTF8() );
2997  NeedRIGHT();
2998  break;
2999 
3000  case T_property:
3001  properties.insert( parseProperty() );
3002  break;
3003 
3004  case T_path:
3005  NeedSYMBOLorNUMBER(); // Paths can be numerical so a number is also a symbol here
3006  footprint->SetPath( KIID_PATH( FromUTF8() ) );
3007  NeedRIGHT();
3008  break;
3009 
3010  case T_autoplace_cost90:
3011  footprint->SetPlacementCost90( parseInt( "auto place cost at 90 degrees" ) );
3012  NeedRIGHT();
3013  break;
3014 
3015  case T_autoplace_cost180:
3016  footprint->SetPlacementCost180( parseInt( "auto place cost at 180 degrees" ) );
3017  NeedRIGHT();
3018  break;
3019 
3020  case T_solder_mask_margin:
3021  footprint->SetLocalSolderMaskMargin( parseBoardUnits( "local solder mask margin value" ) );
3022  NeedRIGHT();
3023  break;
3024 
3025  case T_solder_paste_margin:
3026  footprint->SetLocalSolderPasteMargin(
3027  parseBoardUnits( "local solder paste margin value" ) );
3028  NeedRIGHT();
3029  break;
3030 
3031  case T_solder_paste_ratio:
3032  footprint->SetLocalSolderPasteMarginRatio(
3033  parseDouble( "local solder paste margin ratio value" ) );
3034  NeedRIGHT();
3035  break;
3036 
3037  case T_clearance:
3038  footprint->SetLocalClearance( parseBoardUnits( "local clearance value" ) );
3039  NeedRIGHT();
3040  break;
3041 
3042  case T_zone_connect:
3043  footprint->SetZoneConnection((ZONE_CONNECTION) parseInt( "zone connection value" ) );
3044  NeedRIGHT();
3045  break;
3046 
3047  case T_thermal_width:
3048  footprint->SetThermalWidth( parseBoardUnits( "thermal width value" ) );
3049  NeedRIGHT();
3050  break;
3051 
3052  case T_thermal_gap:
3053  footprint->SetThermalGap( parseBoardUnits( "thermal gap value" ) );
3054  NeedRIGHT();
3055  break;
3056 
3057  case T_attr:
3058  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3059  {
3060  switch( token )
3061  {
3062  case T_virtual: // legacy token prior to version 20200826
3064  break;
3065 
3066  case T_through_hole:
3067  attributes |= FP_THROUGH_HOLE;
3068  break;
3069 
3070  case T_smd:
3071  attributes |= FP_SMD;
3072  break;
3073 
3074  case T_board_only:
3075  attributes |= FP_BOARD_ONLY;
3076  break;
3077 
3078  case T_exclude_from_pos_files:
3079  attributes |= FP_EXCLUDE_FROM_POS_FILES;
3080  break;
3081 
3082  case T_exclude_from_bom:
3083  attributes |= FP_EXCLUDE_FROM_BOM;
3084  break;
3085 
3086  default:
3087  Expecting( "through_hole, smd, virtual, board_only, exclude_from_pos_files "
3088  "or exclude_from_bom" );
3089  }
3090  }
3091  break;
3092 
3093  case T_fp_text:
3094  {
3095  FP_TEXT* text = parseFP_TEXT();
3096  text->SetParent( footprint.get() );
3097  double orientation = text->GetTextAngle();
3098  orientation -= footprint->GetOrientation();
3099  text->SetTextAngle( orientation );
3100  text->SetDrawCoord();
3101 
3102  switch( text->GetType() )
3103  {
3105  footprint->Reference() = *text;
3106  const_cast<KIID&>( footprint->Reference().m_Uuid ) = text->m_Uuid;
3107  delete text;
3108  break;
3109 
3111  footprint->Value() = *text;
3112  const_cast<KIID&>( footprint->Value().m_Uuid ) = text->m_Uuid;
3113  delete text;
3114  break;
3115 
3116  default:
3117  footprint->Add( text, ADD_MODE::APPEND );
3118  }
3119  }
3120  break;
3121 
3122  case T_fp_arc:
3123  {
3124  FP_SHAPE* shape = parseFP_SHAPE();
3125 
3126  // Drop 0 and NaN angles as these can corrupt/crash the schematic
3127  if( std::isnormal( shape->GetAngle() ) )
3128  {
3129  shape->SetParent( footprint.get() );
3130  shape->SetDrawCoord();
3131  footprint->Add( shape, ADD_MODE::APPEND );
3132  }
3133  else
3134  delete shape;
3135  }
3136  break;
3137 
3138  case T_fp_circle:
3139  case T_fp_curve:
3140  case T_fp_rect:
3141  case T_fp_line:
3142  case T_fp_poly:
3143  {
3144  FP_SHAPE* shape = parseFP_SHAPE();
3145  shape->SetParent( footprint.get() );
3146  shape->SetDrawCoord();
3147  footprint->Add( shape, ADD_MODE::APPEND );
3148  }
3149  break;
3150 
3151  case T_pad:
3152  {
3153  PAD* pad = parsePAD( footprint.get() );
3154  pt = pad->GetPos0();
3155 
3156  RotatePoint( &pt, footprint->GetOrientation() );
3157  pad->SetPosition( pt + footprint->GetPosition() );
3158  footprint->Add( pad, ADD_MODE::APPEND );
3159  }
3160  break;
3161 
3162  case T_model:
3163  {
3164  FP_3DMODEL* model = parse3DModel();
3165  footprint->Add3DModel( model );
3166  delete model;
3167  }
3168  break;
3169 
3170  case T_zone:
3171  {
3172  ZONE* zone = parseZONE( footprint.get() );
3173  footprint->Add( zone, ADD_MODE::APPEND );
3174  }
3175  break;
3176 
3177  case T_group:
3178  parseGROUP( footprint.get() );
3179  break;
3180 
3181  default:
3182  Expecting( "locked, placed, tedit, tstamp, at, descr, tags, path, "
3183  "autoplace_cost90, autoplace_cost180, solder_mask_margin, "
3184  "solder_paste_margin, solder_paste_ratio, clearance, "
3185  "zone_connect, thermal_width, thermal_gap, attr, fp_text, "
3186  "fp_arc, fp_circle, fp_curve, fp_line, fp_poly, fp_rect, pad, "
3187  "zone, group, generator, version or model" );
3188  }
3189  }
3190 
3191  // In legacy files the lack of attributes indicated a through-hole component which was by
3192  // default excluded from pos files. However there was a hack to look for SMD pads and
3193  // consider those "mislabeled through-hole components" and therefore include them in place
3194  // files. We probably don't want to get into that game so we'll just include them by
3195  // default and let the user change it if required.
3196  if( m_requiredVersion < 20200826 && attributes == 0 )
3197  attributes |= FP_THROUGH_HOLE;
3198 
3199  // Legacy files controlled pad locking at the footprint level.
3200  if( m_requiredVersion < 20210108 )
3201  {
3202  for( PAD* pad : footprint->Pads() )
3203  pad->SetLocked( footprint->IsLocked() || footprint->LegacyPadsLocked() );
3204  }
3205 
3206  footprint->SetAttributes( attributes );
3207 
3208  footprint->SetFPID( fpid );
3209  footprint->SetProperties( properties );
3210 
3211  return footprint.release();
3212 }
ZONE_CONNECTION
How pads are covered by copper in zone.
Definition: zones.h:41
KIID CurStrToKIID()
void SetTextAngle(double aAngle) override
Definition: fp_text.cpp:70
double GetTextAngle() const
Definition: eda_text.h:181
void SetDrawCoord()
Set relative coordinates.
Definition: fp_text.cpp:199
virtual void SetLocked(bool aLocked)
Modify the 'lock' status for of the item.
Definition: board_item.h:257
bool m_tooRecent
true if version parses as later than supported
Definition: pcb_parser.h:363
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:228
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:165
int parseBoardUnits()
Definition: pcb_parser.h:287
FP_SHAPE * parseFP_SHAPE()
PCB_LAYER_ID
A quick note on layer IDs:
#define NULL
std::pair< wxString, wxString > parseProperty()
Definition: pcb_parser.cpp:240
TEXT_TYPE GetType() const
Definition: fp_text.h:141
PCB_LAYER_ID parseBoardItemLayer()
Parse the layer definition of a BOARD_ITEM object.
FP_TEXT * parseFP_TEXT()
PAD * parsePAD(FOOTPRINT *aParent=NULL)
ZONE handles a list of polygons defining a copper zone.
Definition: zone.h:57
void SetDrawCoord()
Set draw coordinates (absolute values ) from relative coordinates.
Definition: fp_shape.cpp:81
const KIID m_Uuid
Definition: eda_item.h:524
void parseGROUP(BOARD_ITEM *aParent)
const wxPoint & GetPos0() const
Definition: pad.h:226
int m_requiredVersion
set to the KiCad format version this board requires
Definition: pcb_parser.h:364
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:122
const char * name
Definition: DXF_plotter.cpp:59
#define SEXPR_BOARD_FILE_VERSION
Current s-expression file format version. 2 was the last legacy format version.
#define _(s)
Definition: 3d_actions.cpp:33
BOARD * m_board
Definition: pcb_parser.h:358
void SetPosition(const wxPoint &aPos) override
Definition: pad.h:171
double GetAngle() const
Definition: pcb_shape.h:127
double parseDouble()
Parse the current token as an ASCII numeric string with possible leading whitespace into a double pre...
Definition: pcb_parser.cpp:139
long parseHex()
Definition: pcb_parser.h:335
Definition: pad.h:60
int parseInt()
Definition: pcb_parser.h:324
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
FP_3DMODEL * parse3DModel()
Definition: pcb_parser.cpp:367
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, PCB_SHAPE::GetAngle(), PAD::GetPos0(), EDA_TEXT::GetTextAngle(), FP_TEXT::GetType(), EDA_ITEM::m_Uuid, name, NULL, LIB_ID::Parse(), parseDouble(), parseHex(), parseInt(), RotatePoint(), FP_SHAPE::SetDrawCoord(), FP_TEXT::SetDrawCoord(), EDA_ITEM::SetParent(), PAD::SetPosition(), FP_TEXT::SetTextAngle(), SEXPR_BOARD_FILE_VERSION, FP_TEXT::TEXT_is_REFERENCE, FP_TEXT::TEXT_is_VALUE, and THROW_IO_ERROR.

◆ parseFP_SHAPE()

FP_SHAPE * PCB_PARSER::parseFP_SHAPE ( )
private

We continue to parse the status field but it is no longer written

Definition at line 3316 of file pcb_parser.cpp.

3317 {
3318  wxCHECK_MSG( CurTok() == T_fp_arc || CurTok() == T_fp_circle || CurTok() == T_fp_curve ||
3319  CurTok() == T_fp_rect || CurTok() == T_fp_line || CurTok() == T_fp_poly, NULL,
3320  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as FP_SHAPE." ) );
3321 
3322  wxPoint pt;
3323  T token;
3324 
3325  std::unique_ptr<FP_SHAPE> shape = std::make_unique<FP_SHAPE>( nullptr );
3326 
3327  switch( CurTok() )
3328  {
3329  case T_fp_arc:
3330  shape->SetShape( S_ARC );
3331  NeedLEFT();
3332  token = NextTok();
3333 
3334  // the start keyword actually gives the arc center
3335  // Allows also T_center for future change
3336  if( token != T_start && token != T_center )
3337  Expecting( T_start );
3338 
3339  pt.x = parseBoardUnits( "X coordinate" );
3340  pt.y = parseBoardUnits( "Y coordinate" );
3341  shape->SetStart0( pt );
3342  NeedRIGHT();
3343  NeedLEFT();
3344  token = NextTok();
3345 
3346  if( token != T_end ) // end keyword actually gives the starting point of the arc
3347  Expecting( T_end );
3348 
3349  pt.x = parseBoardUnits( "X coordinate" );
3350  pt.y = parseBoardUnits( "Y coordinate" );
3351  shape->SetEnd0( pt );
3352  NeedRIGHT();
3353  NeedLEFT();
3354  token = NextTok();
3355 
3356  if( token != T_angle )
3357  Expecting( T_angle );
3358 
3359  // Setting angle will set m_ThirdPoint0, so must be done after setting
3360  // m_Start0 and m_End0
3361  shape->SetAngle( parseDouble( "segment angle" ) * 10.0 );
3362  NeedRIGHT();
3363  break;
3364 
3365  case T_fp_circle:
3366  shape->SetShape( S_CIRCLE );
3367  NeedLEFT();
3368  token = NextTok();
3369 
3370  if( token != T_center )
3371  Expecting( T_center );
3372 
3373  pt.x = parseBoardUnits( "X coordinate" );
3374  pt.y = parseBoardUnits( "Y coordinate" );
3375  shape->SetStart0( pt );
3376  NeedRIGHT();
3377  NeedLEFT();
3378  token = NextTok();
3379 
3380  if( token != T_end )
3381  Expecting( T_end );
3382 
3383  pt.x = parseBoardUnits( "X coordinate" );
3384  pt.y = parseBoardUnits( "Y coordinate" );
3385  shape->SetEnd0( pt );
3386  NeedRIGHT();
3387  break;
3388 
3389  case T_fp_curve:
3390  shape->SetShape( S_CURVE );
3391  NeedLEFT();
3392  token = NextTok();
3393 
3394  if( token != T_pts )
3395  Expecting( T_pts );
3396 
3397  shape->SetStart0( parseXY() );
3398  shape->SetBezier0_C1( parseXY() );
3399  shape->SetBezier0_C2( parseXY() );
3400  shape->SetEnd0( parseXY() );
3401  NeedRIGHT();
3402  break;
3403 
3404  case T_fp_rect:
3405  shape->SetShape( S_RECT );
3406  NeedLEFT();
3407  token = NextTok();
3408 
3409  if( token != T_start )
3410  Expecting( T_start );
3411 
3412  pt.x = parseBoardUnits( "X coordinate" );
3413  pt.y = parseBoardUnits( "Y coordinate" );
3414  shape->SetStart0( pt );
3415 
3416  NeedRIGHT();
3417  NeedLEFT();
3418  token = NextTok();
3419 
3420  if( token != T_end )
3421  Expecting( T_end );
3422 
3423  pt.x = parseBoardUnits( "X coordinate" );
3424  pt.y = parseBoardUnits( "Y coordinate" );
3425  shape->SetEnd0( pt );
3426  NeedRIGHT();
3427  break;
3428 
3429  case T_fp_line:
3430  // Default PCB_SHAPE type is S_SEGMENT.
3431  NeedLEFT();
3432  token = NextTok();
3433 
3434  if( token != T_start )
3435  Expecting( T_start );
3436 
3437  pt.x = parseBoardUnits( "X coordinate" );
3438  pt.y = parseBoardUnits( "Y coordinate" );
3439  shape->SetStart0( pt );
3440 
3441  NeedRIGHT();
3442  NeedLEFT();
3443  token = NextTok();
3444 
3445  if( token != T_end )
3446  Expecting( T_end );
3447 
3448  pt.x = parseBoardUnits( "X coordinate" );
3449  pt.y = parseBoardUnits( "Y coordinate" );
3450  shape->SetEnd0( pt );
3451  NeedRIGHT();
3452  break;
3453 
3454  case T_fp_poly:
3455  {
3456  shape->SetShape( S_POLYGON );
3457  NeedLEFT();
3458  token = NextTok();
3459 
3460  if( token != T_pts )
3461  Expecting( T_pts );
3462 
3463  std::vector< wxPoint > pts;
3464 
3465  while( (token = NextTok() ) != T_RIGHT )
3466  pts.push_back( parseXY() );
3467 
3468  shape->SetPolyPoints( pts );
3469  }
3470  break;
3471 
3472  default:
3473  Expecting( "fp_arc, fp_circle, fp_curve, fp_line, fp_poly, or fp_rect" );
3474  }
3475 
3476  bool foundFill = false;
3477 
3478  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3479  {
3480  if( token != T_LEFT )
3481  Expecting( T_LEFT );
3482 
3483  token = NextTok();
3484 
3485  switch( token )
3486  {
3487  case T_layer:
3488  shape->SetLayer( parseBoardItemLayer() );
3489  NeedRIGHT();
3490  break;
3491 
3492  case T_width:
3493  shape->SetWidth( parseBoardUnits( T_width ) );
3494  NeedRIGHT();
3495  break;
3496 
3497  case T_tstamp:
3498  NextTok();
3499  const_cast<KIID&>( shape->m_Uuid ) = CurStrToKIID();
3500  NeedRIGHT();
3501  break;
3502 
3503  case T_fill:
3504  foundFill = true;
3505 
3506  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3507  {
3508  if( token == T_LEFT )
3509  token = NextTok();
3510 
3511  switch( token )
3512  {
3513  // T_yes was used to indicate filling when first introduced,
3514  // so treat it like a solid fill since that was the only fill available
3515  case T_yes:
3516  case T_solid:
3517  shape->SetFilled( true );
3518  break;
3519 
3520  case T_none:
3521  shape->SetFilled( false );
3522  break;
3523 
3524  default:
3525  Expecting( "yes, none, solid" );
3526  }
3527  }
3528 
3529  break;
3530 
3532  case T_status:
3533  shape->SetStatus( static_cast<STATUS_FLAGS>( parseHex() ) );
3534  NeedRIGHT();
3535  break;
3536 
3537  case T_locked:
3538  shape->SetLocked( true );
3539  NeedRIGHT();
3540  break;
3541 
3542  default:
3543  Expecting( "layer, width, fill, tstamp, locked, or status" );
3544  }
3545  }
3546 
3547  if( !foundFill )
3548  {
3549  // Legacy versions didn't have a filled flag but allowed some shapes to indicate they
3550  // should be filled by specifying a 0 stroke-width.
3551  if( shape->GetWidth() == 0
3552  && ( shape->GetShape() == S_RECT || shape->GetShape() == S_CIRCLE ) )
3553  {
3554  shape->SetFilled( true );
3555  }
3556  // Polygons on non-Edge_Cuts layers were always filled
3557  else if( shape->GetShape() == S_POLYGON && shape->GetLayer() != Edge_Cuts )
3558  {
3559  shape->SetFilled( true );
3560  }
3561  }
3562 
3563  // Only filled shapes may have a zero line-width. This is not permitted in KiCad but some
3564  // external tools can generate invalid files.
3565  if( shape->GetWidth() <= 0 && !shape->IsFilled() )
3566  {
3567  shape->SetWidth( Millimeter2iu( DEFAULT_LINE_WIDTH ) );
3568  }
3569 
3570  return shape.release();
3571 }
KIID CurStrToKIID()
wxPoint parseXY()
Parse a coordinate pair (xy X Y) in board units (mm).
Definition: pcb_parser.cpp:208
polygon (not yet used for tracks, but could be in microwave apps)
Definition: board_item.h:54
#define DEFAULT_LINE_WIDTH
Arcs (with rounded ends)
Definition: board_item.h:52
segment with non rounded ends
Definition: board_item.h:51
int parseBoardUnits()
Definition: pcb_parser.h:287
#define NULL
PCB_LAYER_ID parseBoardItemLayer()
Parse the layer definition of a BOARD_ITEM object.
double parseDouble()
Parse the current token as an ASCII numeric string with possible leading whitespace into a double pre...
Definition: pcb_parser.cpp:139
ring
Definition: board_item.h:53
long parseHex()
Definition: pcb_parser.h:335
Bezier Curve.
Definition: board_item.h:55
static constexpr int Millimeter2iu(double mm)

References DEFAULT_LINE_WIDTH, Edge_Cuts, Millimeter2iu(), NULL, parseDouble(), parseHex(), S_ARC, S_CIRCLE, S_CURVE, S_POLYGON, and S_RECT.

◆ parseFP_TEXT()

FP_TEXT * PCB_PARSER::parseFP_TEXT ( )
private

Definition at line 3215 of file pcb_parser.cpp.

3216 {
3217  wxCHECK_MSG( CurTok() == T_fp_text, NULL,
3218  wxString::Format( wxT( "Cannot parse %s as FP_TEXT at line %d, offset %d." ),
3219  GetTokenString( CurTok() ),
3220  CurLineNumber(), CurOffset() ) );
3221 
3222  T token = NextTok();
3223 
3224  std::unique_ptr<FP_TEXT> text = std::make_unique<FP_TEXT>( nullptr );
3225 
3226  switch( token )
3227  {
3228  case T_reference:
3229  text->SetType( FP_TEXT::TEXT_is_REFERENCE );
3230  break;
3231 
3232  case T_value:
3233  text->SetType( FP_TEXT::TEXT_is_VALUE );
3234  break;
3235 
3236  case T_user:
3237  break; // Default type is user text.
3238 
3239  default:
3241  wxString::Format( _( "Cannot handle footprint text type %s" ), FromUTF8() ) );
3242  }
3243 
3244  NeedSYMBOLorNUMBER();
3245 
3246  wxString value = FromUTF8();
3247  value.Replace( "%V", "${VALUE}" );
3248  value.Replace( "%R", "${REFERENCE}" );
3249  text->SetText( value );
3250  NeedLEFT();
3251  token = NextTok();
3252 
3253  if( token != T_at )
3254  Expecting( T_at );
3255 
3256  wxPoint pt;
3257 
3258  pt.x = parseBoardUnits( "X coordinate" );
3259  pt.y = parseBoardUnits( "Y coordinate" );
3260  text->SetPos0( pt );
3261 
3262  NextTok();
3263 
3264  if( CurTok() == T_NUMBER )
3265  {
3266  text->SetTextAngle( parseDouble() * 10.0 );
3267  NextTok();
3268  }
3269 
3270  if( CurTok() == T_unlocked )
3271  {
3272  text->SetKeepUpright( false );
3273  NextTok();
3274  }
3275 
3276  if( CurTok() != T_RIGHT )
3277  {
3278  Unexpected( CurText() );
3279  }
3280 
3281  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3282  {
3283  if( token == T_LEFT )
3284  token = NextTok();
3285 
3286  switch( token )
3287  {
3288  case T_layer:
3289  text->SetLayer( parseBoardItemLayer() );
3290  NeedRIGHT();
3291  break;
3292 
3293  case T_hide:
3294  text->SetVisible( false );
3295  break;
3296 
3297  case T_effects:
3298  parseEDA_TEXT( (EDA_TEXT*) text.get() );
3299  break;
3300 
3301  case T_tstamp:
3302  NextTok();
3303  const_cast<KIID&>( text->m_Uuid ) = CurStrToKIID();
3304  NeedRIGHT();
3305  break;
3306 
3307  default:
3308  Expecting( "layer, hide, effects or tstamp" );
3309  }
3310  }
3311 
3312  return text.release();
3313 }
KIID CurStrToKIID()
void parseEDA_TEXT(EDA_TEXT *aText)
Parse the common settings for any object derived from EDA_TEXT.
Definition: pcb_parser.cpp:255
int parseBoardUnits()
Definition: pcb_parser.h:287
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:119
#define NULL
PCB_LAYER_ID parseBoardItemLayer()
Parse the layer definition of a BOARD_ITEM object.
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 _(s)
Definition: 3d_actions.cpp:33
double parseDouble()
Parse the current token as an ASCII numeric string with possible leading whitespace into a double pre...
Definition: pcb_parser.cpp:139
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38

References _, Format(), NULL, parseDouble(), FP_TEXT::TEXT_is_REFERENCE, FP_TEXT::TEXT_is_VALUE, and THROW_IO_ERROR.

◆ parseGeneralSection()

void PCB_PARSER::parseGeneralSection ( )
private

Definition at line 890 of file pcb_parser.cpp.

891 {
892  wxCHECK_RET( CurTok() == T_general,
893  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
894  wxT( " as a general section." ) );
895 
896  T token;
897 
898  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
899  {
900  if( token != T_LEFT )
901  Expecting( T_LEFT );
902 
903  token = NextTok();
904 
905  switch( token )
906  {
907  case T_thickness:
909  NeedRIGHT();
910  break;
911 
912  default: // Skip everything but the board thickness.
913  while( ( token = NextTok() ) != T_RIGHT )
914  {
915  if( !IsSymbol( token ) && token != T_NUMBER )
916  Expecting( "symbol or number" );
917  }
918  }
919  }
920 }
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.h:591
void SetBoardThickness(int aThickness)
int parseBoardUnits()
Definition: pcb_parser.h:287
BOARD * m_board
Definition: pcb_parser.h:358

◆ parseGROUP()

void PCB_PARSER::parseGROUP ( BOARD_ITEM aParent)
private

Definition at line 4126 of file pcb_parser.cpp.

4127 {
4128  wxCHECK_RET( CurTok() == T_group,
4129  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PCB_GROUP." ) );
4130 
4131  wxPoint pt;
4132  T token;
4133 
4134  m_groupInfos.push_back( GROUP_INFO() );
4135  GROUP_INFO& groupInfo = m_groupInfos.back();
4136  groupInfo.parent = aParent;
4137 
4138  token = NextTok();
4139 
4140  if( token != T_LEFT )
4141  {
4142  // Optional group name present.
4143 
4144  if( !IsSymbol( token ) )
4145  Expecting( DSN_SYMBOL );
4146 
4147  groupInfo.name = FromUTF8();
4148  }
4149 
4150  NeedLEFT();
4151  token = NextTok();
4152 
4153  if( token != T_id )
4154  {
4155  Expecting( T_id );
4156  }
4157 
4158  NextTok();
4159  groupInfo.uuid = CurStrToKIID();
4160  NeedRIGHT();
4161 
4162  NeedLEFT();
4163  token = NextTok();
4164 
4165  if( token != T_members )
4166  {
4167  Expecting( T_members );
4168  }
4169 
4170  while( ( token = NextTok() ) != T_RIGHT )
4171  {
4172  // This token is the Uuid of the item in the group.
4173  // Since groups are serialized at the end of the file/footprint, the Uuid should already
4174  // have been seen and exist in the board.
4175  KIID uuid( CurStr() );
4176  groupInfo.memberUuids.push_back( uuid );
4177  }
4178 
4179  NeedRIGHT();
4180 }
KIID CurStrToKIID()
Definition: kiid.h:44
std::vector< GROUP_INFO > m_groupInfos
Definition: pcb_parser.h:384

References DSN_SYMBOL, 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 849 of file pcb_parser.cpp.

850 {
851  wxCHECK_RET( CurTok() == T_kicad_pcb,
852  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a header." ) );
853 
854  NeedLEFT();
855 
856  T tok = NextTok();
857 
858  if( tok == T_version )
859  {
860  m_requiredVersion = parseInt( FromUTF8().mb_str( wxConvUTF8 ) );
862  NeedRIGHT();
863 
864  NeedLEFT();
865  NeedSYMBOL();
866  NeedSYMBOL();
867 
868  // Older formats included build data
870  NeedSYMBOL();
871 
872  NeedRIGHT();
873  }
874  else
875  {
876  m_requiredVersion = 20201115; // Last version before we started writing version #s
877  // in footprint files as well as board files.
879 
880  // Skip the host name and host build version information.
881  NeedSYMBOL();
882  NeedSYMBOL();
883  NeedRIGHT();
884  }
885 
887 }
void SetFileFormatVersionAtLoad(int aVersion)
Definition: board.h:358
bool m_tooRecent
true if version parses as later than supported
Definition: pcb_parser.h:363
#define BOARD_FILE_HOST_VERSION
Earlier files than this include the host tag.
int m_requiredVersion
set to the KiCad format version this board requires
Definition: pcb_parser.h:364
#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:358
int parseInt()
Definition: pcb_parser.h:324

References BOARD_FILE_HOST_VERSION, parseInt(), and SEXPR_BOARD_FILE_VERSION.

◆ parseHex()

long PCB_PARSER::parseHex ( )
inlineprivate

Definition at line 335 of file pcb_parser.h.

336  {
337  NextTok();
338  return strtol( CurText(), NULL, 16 );
339  }
#define NULL

References NULL.

◆ parseInt() [1/2]

int PCB_PARSER::parseInt ( )
inlineprivate

Definition at line 324 of file pcb_parser.h.

325  {
326  return (int)strtol( CurText(), NULL, 10 );
327  }
#define NULL

References NULL.

Referenced by parseInt().

◆ parseInt() [2/2]

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

Definition at line 329 of file pcb_parser.h.

330  {
331  NeedNUMBER( aExpected );
332  return parseInt();
333  }
int parseInt()
Definition: pcb_parser.h:324

References parseInt().

◆ parseLayer()

void PCB_PARSER::parseLayer ( LAYER aLayer)
private

Definition at line 1087 of file pcb_parser.cpp.

1088 {
1089  T token;
1090 
1091  std::string name;
1092  std::string userName;
1093  std::string type;
1094  bool isVisible = true;
1095 
1096  aLayer->clear();
1097 
1098  if( CurTok() != T_LEFT )
1099  Expecting( T_LEFT );
1100 
1101  // this layer_num is not used, we DO depend on LAYER_T however.
1102  LAYER_NUM layer_num = parseInt( "layer index" );
1103 
1104  NeedSYMBOLorNUMBER();
1105  name = CurText();
1106 
1107  NeedSYMBOL();
1108  type = CurText();
1109 
1110  token = NextTok();
1111 
1112  // @todo Figure out why we are looking for a hide token in the layer definition.
1113  if( token == T_hide )
1114  {
1115  isVisible = false;
1116  NeedRIGHT();
1117  }
1118  else if( token == T_STRING )
1119  {
1120  userName = CurText();
1121  NeedRIGHT();
1122  }
1123  else if( token != T_RIGHT )
1124  {
1125  Expecting( "hide, user defined name, or )" );
1126  }
1127 
1128  aLayer->m_name = FROM_UTF8( name.c_str() );
1129  aLayer->m_type = LAYER::ParseType( type.c_str() );
1130  aLayer->m_number = layer_num;
1131  aLayer->m_visible = isVisible;
1132 
1133  if( !userName.empty() )
1134  aLayer->m_userName = FROM_UTF8( userName.c_str() );
1135 
1136  // The canonical name will get reset back to the default for copper layer on the next
1137  // save. The user defined name is now a separate optional layer token from the canonical
1138  // name.
1139  if( aLayer->m_name != LSET::Name( static_cast<PCB_LAYER_ID>( aLayer->m_number ) ) )
1140  aLayer->m_userName = aLayer->m_name;
1141 }
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:103
LAYER_T m_type
The type of the layer.
Definition: board.h:105
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:106
wxString m_userName
The user defined name of the layer.
Definition: board.h:104
static LAYER_T ParseType(const char *aType)
Convert a string to a LAYER_T.
Definition: board.cpp:420
int LAYER_NUM
This can be replaced with int and removed.
void clear()
Definition: board.h:83
const char * name
Definition: DXF_plotter.cpp:59
int m_number
The layer ID.
Definition: board.h:107
int parseInt()
Definition: pcb_parser.h:324

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 1390 of file pcb_parser.cpp.

1391 {
1392  wxCHECK_RET( CurTok() == T_layers,
1393  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as layers." ) );
1394 
1395  T token;
1396  LSET visibleLayers;
1397  LSET enabledLayers;
1398  int copperLayerCount = 0;
1399  LAYER layer;
1400  bool anyHidden = false;
1401 
1402  std::unordered_map< std::string, std::string > v3_layer_names;
1403  std::vector<LAYER> cu;
1404 
1405  createOldLayerMapping( v3_layer_names );
1406 
1407  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1408  {
1409  parseLayer( &layer );
1410 
1411  if( layer.m_type == LT_UNDEFINED ) // it's a non-copper layer
1412  break;
1413 
1414  cu.push_back( layer ); // it's copper
1415  }
1416 
1417  // All Cu layers are parsed, but not the non-cu layers here.
1418 
1419  // The original *.kicad_pcb file format and the inverted
1420  // Cu stack format both have all the Cu layers first, so use this
1421  // trick to handle either. The layer number in the (layers ..)
1422  // s-expression element are ignored.
1423  if( cu.size() )
1424  {
1425  // Rework the layer numbers, which changed when the Cu stack
1426  // was flipped. So we instead use position in the list.
1427  cu[cu.size()-1].m_number = B_Cu;
1428 
1429  for( unsigned i=0; i < cu.size()-1; ++i )
1430  {
1431  cu[i].m_number = i;
1432  }
1433 
1434  for( std::vector<LAYER>::const_iterator it = cu.begin(); it<cu.end(); ++it )
1435  {
1436  enabledLayers.set( it->m_number );
1437 
1438  if( it->m_visible )
1439  visibleLayers.set( it->m_number );
1440  else
1441  anyHidden = true;
1442 
1443  m_board->SetLayerDescr( PCB_LAYER_ID( it->m_number ), *it );
1444 
1445  UTF8 name = it->m_name;
1446 
1447  m_layerIndices[ name ] = PCB_LAYER_ID( it->m_number );
1448  m_layerMasks[ name ] = LSET( PCB_LAYER_ID( it->m_number ) );
1449  }
1450 
1451  copperLayerCount = cu.size();
1452  }
1453 
1454  // process non-copper layers
1455  while( token != T_RIGHT )
1456  {
1457  LAYER_ID_MAP::const_iterator it = m_layerIndices.find( UTF8( layer.m_name ) );
1458 
1459  if( it == m_layerIndices.end() )
1460  {
1461  auto new_layer_it = v3_layer_names.find( layer.m_name.ToStdString() );
1462 
1463  if( new_layer_it != v3_layer_names.end() )
1464  it = m_layerIndices.find( new_layer_it->second );
1465 
1466  if( it == m_layerIndices.end() )
1467  {
1468  wxString error = wxString::Format(
1469  _( "Layer \"%s\" in file \"%s\" at line %d, is not in fixed layer hash" ),
1470  layer.m_name,
1471  CurSource(),
1472  CurLineNumber(),
1473  CurOffset()
1474  );
1475 
1476  THROW_IO_ERROR( error );
1477  }
1478 
1479  // If we are here, then we have found a translated layer name. Put it in the maps so that
1480  // items on this layer get the appropriate layer ID number
1481  m_layerIndices[ UTF8( layer.m_name ) ] = it->second;
1482  m_layerMasks[ UTF8( layer.m_name ) ] = it->second;
1483  layer.m_name = it->first;
1484  }
1485 
1486  layer.m_number = it->second;
1487  enabledLayers.set( layer.m_number );
1488 
1489  if( layer.m_visible )
1490  visibleLayers.set( layer.m_number );
1491  else
1492  anyHidden = true;
1493 
1494  m_board->SetLayerDescr( it->second, layer );
1495 
1496  token = NextTok();
1497 
1498  if( token != T_LEFT )
1499  break;
1500 
1501  parseLayer( &layer );
1502  }
1503 
1504  // We need at least 2 copper layers and there must be an even number of them.
1505  if( copperLayerCount < 2 || (copperLayerCount % 2) != 0 )
1506  {
1507  wxString err = wxString::Format(
1508  _( "%d is not a valid layer count" ), copperLayerCount );
1509 
1510  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
1511  }
1512 
1513  m_board->SetCopperLayerCount( copperLayerCount );
1514  m_board->SetEnabledLayers( enabledLayers );
1515 
1516  // Only set this if any layers were explicitly marked as hidden. Otherwise, we want to leave
1517  // this alone; default visibility will show everything
1518  if( anyHidden )
1519  m_board->m_LegacyVisibleLayers = visibleLayers;
1520 }
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:103
LAYER_T m_type
The type of the layer.
Definition: board.h:105
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:441
PCB_LAYER_ID
A quick note on layer IDs:
LSET is a set of PCB_LAYER_IDs.
#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:308
bool m_visible
Definition: board.h:106
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:59
Container to hold information pertinent to a layer of a BOARD.
Definition: board.h:76
#define _(s)
Definition: 3d_actions.cpp:33
BOARD * m_board
Definition: pcb_parser.h:358
LAYER_ID_MAP m_layerIndices
map layer name to it's index
Definition: pcb_parser.h:359
int m_number
The layer ID.
Definition: board.h:107
#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:334
void SetEnabledLayers(LSET aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings Changes the bit-mask of ena...
Definition: board.cpp:467
LSET_MAP m_layerMasks
map layer names to their masks
Definition: pcb_parser.h:360

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 2061 of file pcb_parser.cpp.

2062 {
2063  wxCHECK_RET( CurTok() == T_net_class,
2064  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as net class." ) );
2065 
2066  T token;
2067 
2068  NETCLASSPTR nc = std::make_shared<NETCLASS>( wxEmptyString );
2069 
2070  // Read netclass name (can be a name or just a number like track width)
2071  NeedSYMBOLorNUMBER();
2072  nc->SetName( FromUTF8() );
2073  NeedSYMBOL();
2074  nc->SetDescription( FromUTF8() );
2075 
2076  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2077  {
2078  if( token != T_LEFT )
2079  Expecting( T_LEFT );
2080 
2081  token = NextTok();
2082 
2083  switch( token )
2084  {
2085  case T_clearance:
2086  nc->SetClearance( parseBoardUnits( T_clearance ) );
2087  break;
2088 
2089  case T_trace_width:
2090  nc->SetTrackWidth( parseBoardUnits( T_trace_width ) );
2091  break;
2092 
2093  case T_via_dia:
2094  nc->SetViaDiameter( parseBoardUnits( T_via_dia ) );
2095  break;
2096 
2097  case T_via_drill:
2098  nc->SetViaDrill( parseBoardUnits( T_via_drill ) );
2099  break;
2100 
2101  case T_uvia_dia:
2102  nc->SetuViaDiameter( parseBoardUnits( T_uvia_dia ) );
2103  break;
2104 
2105  case T_uvia_drill:
2106  nc->SetuViaDrill( parseBoardUnits( T_uvia_drill ) );
2107  break;
2108 
2109  case T_diff_pair_width:
2110  nc->SetDiffPairWidth( parseBoardUnits( T_diff_pair_width ) );
2111  break;
2112 
2113  case T_diff_pair_gap:
2114  nc->SetDiffPairGap( parseBoardUnits( T_diff_pair_gap ) );
2115  break;
2116 
2117  case T_add_net:
2118  NeedSYMBOLorNUMBER();
2119  nc->Add( FromUTF8() );
2120  break;
2121 
2122  default:
2123  Expecting( "clearance, trace_width, via_dia, via_drill, uvia_dia, uvia_drill, "
2124  "diff_pair_width, diff_pair_gap or add_net" );
2125  }
2126 
2127  NeedRIGHT();
2128  }
2129 
2130  if( !m_board->GetDesignSettings().GetNetClasses().Add( nc ) )
2131  {
2132  // Must have been a name conflict, this is a bad board file.
2133  // User may have done a hand edit to the file.
2134 
2135  // unique_ptr will delete nc on this code path
2136 
2137  wxString error;
2138  error.Printf( _( "Duplicate NETCLASS name \"%s\" in file \"%s\" at line %d, offset %d" ),
2139  nc->GetName().GetData(), CurSource().GetData(), CurLineNumber(), CurOffset() );
2140  THROW_IO_ERROR( error );
2141  }
2142 }
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.h:591
int parseBoardUnits()
Definition: pcb_parser.h:287
NETCLASSES & GetNetClasses() const
bool Add(const NETCLASSPTR &aNetclass)
Add aNetclass and puts it into this NETCLASSES container.
Definition: netclass.cpp:90
#define _(s)
Definition: 3d_actions.cpp:33
BOARD * m_board
Definition: pcb_parser.h:358
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38

References _, and THROW_IO_ERROR.

◆ parseNETINFO_ITEM()

void PCB_PARSER::parseNETINFO_ITEM ( )
private

Definition at line 2035 of file pcb_parser.cpp.

2036 {
2037  wxCHECK_RET( CurTok() == T_net,
2038  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as net." ) );
2039 
2040  int netCode = parseInt( "net number" );
2041 
2042  NeedSYMBOLorNUMBER();
2043  wxString name = FromUTF8();
2044 
2045  NeedRIGHT();
2046 
2047  // net 0 should be already in list, so store this net
2048  // if it is not the net 0, or if the net 0 does not exists.
2049  // (TODO: a better test.)
2051  {
2052  NETINFO_ITEM* net = new NETINFO_ITEM( m_board, name, netCode );
2053  m_board->Add( net );
2054 
2055  // Store the new code mapping
2056  pushValueIntoMap( netCode, net->GetNetCode() );
2057  }
2058 }
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1268
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT) override
Adds an item to the container.
Definition: board.cpp:563
Handle the data for a net.
Definition: netinfo.h:64
const char * name
Definition: DXF_plotter.cpp:59
BOARD * m_board
Definition: pcb_parser.h:358
void pushValueIntoMap(int aIndex, int aValue)
Add aValue value in netcode mapping (m_netCodes) at aIndex.
Definition: pcb_parser.cpp:127
int parseInt()
Definition: pcb_parser.h:324
static const int UNCONNECTED
Constant that forces initialization of a netinfo item to the NETINFO_ITEM ORPHANED (typically -1) whe...
Definition: netinfo.h:365
int GetNetCode() const
Definition: netinfo.h:113

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

◆ parsePAD()

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

Definition at line 3574 of file pcb_parser.cpp.

3575 {
3576  wxCHECK_MSG( CurTok() == T_pad, NULL,
3577  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PAD." ) );
3578 
3579  wxSize sz;
3580  wxPoint pt;
3581 
3582  std::unique_ptr<PAD> pad = std::make_unique<PAD>( aParent );
3583 
3584  // File only contains a token if KeepTopBottom is true
3585  pad->SetKeepTopBottom( false );
3586 
3587  NeedSYMBOLorNUMBER();
3588  pad->SetName( FromUTF8() );
3589 
3590  T token = NextTok();
3591 
3592  switch( token )
3593  {
3594  case T_thru_hole:
3595  pad->SetAttribute( PAD_ATTRIB_PTH );
3596  break;
3597 
3598  case T_smd:
3599  pad->SetAttribute( PAD_ATTRIB_SMD );
3600 
3601  // Default PAD object is thru hole with drill.
3602  // SMD pads have no hole
3603  pad->SetDrillSize( wxSize( 0, 0 ) );
3604  break;
3605 
3606  case T_connect:
3607  pad->SetAttribute( PAD_ATTRIB_CONN );
3608 
3609  // Default PAD object is thru hole with drill.
3610  // CONN pads have no hole
3611  pad->SetDrillSize( wxSize( 0, 0 ) );
3612  break;
3613 
3614  case T_np_thru_hole:
3615  pad->SetAttribute( PAD_ATTRIB_NPTH );
3616  break;
3617 
3618  default:
3619  Expecting( "thru_hole, smd, connect, or np_thru_hole" );
3620  }
3621 
3622  token = NextTok();
3623 
3624  switch( token )
3625  {
3626  case T_circle:
3627  pad->SetShape( PAD_SHAPE_CIRCLE );
3628  break;
3629 
3630  case T_rect:
3631  pad->SetShape( PAD_SHAPE_RECT );
3632  break;
3633 
3634  case T_oval:
3635  pad->SetShape( PAD_SHAPE_OVAL );
3636  break;
3637 
3638  case T_trapezoid:
3639  pad->SetShape( PAD_SHAPE_TRAPEZOID );
3640  break;
3641 
3642  case T_roundrect:
3643  // Note: the shape can be PAD_SHAPE_ROUNDRECT or PAD_SHAPE_CHAMFERED_RECT
3644  // (if chamfer parameters are found later in pad descr.)
3645  pad->SetShape( PAD_SHAPE_ROUNDRECT );
3646  break;
3647 
3648  case T_custom:
3649  pad->SetShape( PAD_SHAPE_CUSTOM );
3650  break;
3651 
3652  default:
3653  Expecting( "circle, rectangle, roundrect, oval, trapezoid or custom" );
3654  }
3655 
3656  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3657  {
3658  if( token != T_LEFT )
3659  Expecting( T_LEFT );
3660 
3661  token = NextTok();
3662 
3663  switch( token )
3664  {
3665  case T_size:
3666  sz.SetWidth( parseBoardUnits( "width value" ) );
3667  sz.SetHeight( parseBoardUnits( "height value" ) );
3668  pad->SetSize( sz );
3669  NeedRIGHT();
3670  break;
3671 
3672  case T_at:
3673  pt.x = parseBoardUnits( "X coordinate" );
3674  pt.y = parseBoardUnits( "Y coordinate" );
3675  pad->SetPos0( pt );
3676  token = NextTok();
3677 
3678  if( token == T_NUMBER )
3679  {
3680  pad->SetOrientation( parseDouble() * 10.0 );
3681  NeedRIGHT();
3682  }
3683  else if( token != T_RIGHT )
3684  {
3685  Expecting( ") or angle value" );
3686  }
3687 
3688  break;
3689 
3690  case T_rect_delta:
3691  {
3692  wxSize delta;
3693  delta.SetWidth( parseBoardUnits( "rectangle delta width" ) );
3694  delta.SetHeight( parseBoardUnits( "rectangle delta height" ) );
3695  pad->SetDelta( delta );
3696  NeedRIGHT();
3697  }
3698  break;
3699 
3700  case T_drill:
3701  {
3702  bool haveWidth = false;
3703  wxSize drillSize = pad->GetDrillSize();
3704 
3705  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3706  {
3707  if( token == T_LEFT )
3708  token = NextTok();
3709 
3710  switch( token )
3711  {
3712  case T_oval:
3713  pad->SetDrillShape( PAD_DRILL_SHAPE_OBLONG );
3714  break;
3715 
3716  case T_NUMBER:
3717  {
3718  if( !haveWidth )
3719  {
3720  drillSize.SetWidth( parseBoardUnits() );
3721 
3722  // If height is not defined the width and height are the same.
3723  drillSize.SetHeight( drillSize.GetWidth() );
3724  haveWidth = true;
3725  }
3726  else
3727  {
3728  drillSize.SetHeight( parseBoardUnits() );
3729  }
3730 
3731  }
3732  break;
3733 
3734  case T_offset:
3735  pt.x = parseBoardUnits( "drill offset x" );
3736  pt.y = parseBoardUnits( "drill offset y" );
3737  pad->SetOffset( pt );
3738  NeedRIGHT();
3739  break;
3740 
3741  default:
3742  Expecting( "oval, size, or offset" );
3743  }
3744  }
3745 
3746  // This fixes a bug caused by setting the default PAD drill size to a value other
3747  // than 0 used to fix a bunch of debug assertions even though it is defined as a
3748  // through hole pad. Wouldn't a though hole pad with no drill be a surface mount
3749  // pad (or a conn pad which is a smd pad with no solder paste)?
3750  if( ( pad->GetAttribute() != PAD_ATTRIB_SMD ) && ( pad->GetAttribute() != PAD_ATTRIB_CONN ) )
3751  pad->SetDrillSize( drillSize );
3752  else
3753  pad->SetDrillSize( wxSize( 0, 0 ) );
3754 
3755  }
3756  break;
3757 
3758  case T_layers:
3759  {
3760  LSET layerMask = parseBoardItemLayersAsMask();
3761  pad->SetLayerSet( layerMask );
3762  }
3763  break;
3764 
3765  case T_net:
3766  if( ! pad->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
3767  {
3768  wxLogError( wxString::Format( _( "Invalid net ID in\n"
3769  "file: '%s'\n"
3770  "line: %d\n"
3771  "offset: %d" ),
3772  CurSource(),
3773  CurLineNumber(),
3774  CurOffset() ) );
3775  }
3776 
3777  NeedSYMBOLorNUMBER();
3778 
3779  // Test validity of the netname in file for netcodes expected having a net name
3780  if( m_board && pad->GetNetCode() > 0 &&
3781  FromUTF8() != m_board->FindNet( pad->GetNetCode() )->GetNetname() )
3782  {
3783  pad->SetNetCode( NETINFO_LIST::ORPHANED, /* aNoAssert */ true );
3784  wxLogError( wxString::Format( _( "Net name doesn't match net ID in\n"
3785  "file: '%s'\n"
3786  "line: %d\n"
3787  "offset: %d" ),
3788  CurSource(),
3789  CurLineNumber(),
3790  CurOffset() ) );
3791  }
3792 
3793  NeedRIGHT();
3794  break;
3795 
3796  case T_pinfunction:
3797  NeedSYMBOLorNUMBER();
3798  pad->SetPinFunction( FromUTF8() );
3799  NeedRIGHT();
3800  break;
3801 
3802  case T_pintype:
3803  NeedSYMBOLorNUMBER();
3804  pad->SetPinType( FromUTF8() );
3805  NeedRIGHT();
3806  break;
3807 
3808  case T_die_length:
3809  pad->SetPadToDieLength( parseBoardUnits( T_die_length ) );
3810  NeedRIGHT();
3811  break;
3812 
3813  case T_solder_mask_margin:
3814  pad->SetLocalSolderMaskMargin( parseBoardUnits( T_solder_mask_margin ) );
3815  NeedRIGHT();
3816  break;
3817 
3818  case T_solder_paste_margin:
3819  pad->SetLocalSolderPasteMargin( parseBoardUnits( T_solder_paste_margin ) );
3820  NeedRIGHT();
3821  break;
3822 
3823  case T_solder_paste_margin_ratio:
3824  pad->SetLocalSolderPasteMarginRatio(
3825  parseDouble( "pad local solder paste margin ratio value" ) );
3826  NeedRIGHT();
3827  break;
3828 
3829  case T_clearance:
3830  pad->SetLocalClearance( parseBoardUnits( "local clearance value" ) );
3831  NeedRIGHT();
3832  break;
3833 
3834  case T_zone_connect:
3835  pad->SetZoneConnection( (ZONE_CONNECTION) parseInt( "zone connection value" ) );
3836  NeedRIGHT();
3837  break;
3838 
3839  case T_thermal_width:
3840  pad->SetThermalSpokeWidth( parseBoardUnits( T_thermal_width ) );
3841  NeedRIGHT();
3842  break;
3843 
3844  case T_thermal_gap:
3845  pad->SetThermalGap( parseBoardUnits( T_thermal_gap ) );
3846  NeedRIGHT();
3847  break;
3848 
3849  case T_roundrect_rratio:
3850  pad->SetRoundRectRadiusRatio( parseDouble( "roundrect radius ratio" ) );
3851  NeedRIGHT();
3852  break;
3853 
3854  case T_chamfer_ratio:
3855  pad->SetChamferRectRatio( parseDouble( "chamfer ratio" ) );
3856 
3857  if( pad->GetChamferRectRatio() > 0 )
3858  pad->SetShape( PAD_SHAPE_CHAMFERED_RECT );
3859 
3860  NeedRIGHT();
3861  break;
3862 
3863  case T_chamfer:
3864  {
3865  int chamfers = 0;
3866  bool end_list = false;
3867 
3868  while( !end_list )
3869  {
3870  token = NextTok();
3871  switch( token )
3872  {
3873  case T_top_left:
3874  chamfers |= RECT_CHAMFER_TOP_LEFT;
3875  break;
3876 
3877  case T_top_right:
3878  chamfers |= RECT_CHAMFER_TOP_RIGHT;
3879  break;
3880 
3881  case T_bottom_left:
3882  chamfers |= RECT_CHAMFER_BOTTOM_LEFT;
3883  break;
3884 
3885  case T_bottom_right:
3886  chamfers |= RECT_CHAMFER_BOTTOM_RIGHT;
3887  break;
3888 
3889  case T_RIGHT:
3890  pad->SetChamferPositions( chamfers );
3891  end_list = true;
3892  break;
3893 
3894  default:
3895  Expecting( "chamfer_top_left chamfer_top_right chamfer_bottom_left or chamfer_bottom_right" );
3896  }
3897  }
3898 
3899  if( pad->GetChamferPositions() != RECT_NO_CHAMFER )
3900  pad->SetShape( PAD_SHAPE_CHAMFERED_RECT );
3901  }
3902  break;
3903 
3904  case T_property:
3905  {
3906  while( token != T_RIGHT )
3907  {
3908  token = NextTok();
3909 
3910  switch( token )
3911  {
3912  case T_pad_prop_bga:
3913  pad->SetProperty( PAD_PROP_BGA );
3914  break;
3915 
3916  case T_pad_prop_fiducial_glob:
3917  pad->SetProperty( PAD_PROP_FIDUCIAL_GLBL );
3918  break;
3919 
3920  case T_pad_prop_fiducial_loc:
3921  pad->SetProperty( PAD_PROP_FIDUCIAL_LOCAL );
3922  break;
3923 
3924  case T_pad_prop_testpoint:
3925  pad->SetProperty( PAD_PROP_TESTPOINT );
3926  break;
3927 
3928  case T_pad_prop_castellated:
3929  pad->SetProperty( PAD_PROP_CASTELLATED );
3930  break;
3931 
3932  case T_pad_prop_heatsink:
3933  pad->SetProperty( PAD_PROP_HEATSINK );
3934  break;
3935 
3936  case T_none:
3937  pad->SetProperty( PAD_PROP_NONE );
3938  break;
3939 
3940  case T_RIGHT:
3941  break;
3942 
3943  default:
3944 #if 0 // Currently: skip unknown property
3945  Expecting( "pad_prop_bga pad_prop_fiducial_glob pad_prop_fiducial_loc"
3946  " pad_prop_heatsink or pad_prop_castellated" );
3947 #endif
3948  break;
3949  }
3950  }
3951  }
3952  break;
3953 
3954  case T_options:
3955  parsePAD_option( pad.get() );
3956  break;
3957 
3958  case T_primitives:
3959  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3960  {
3961  if( token == T_LEFT )
3962  token = NextTok();
3963 
3964  // Currently, I am using parsePCB_SHAPE() to read basic shapes parameters,
3965  // because they are the same as a PCB_SHAPE.
3966  // However it could be better to write a specific parser, to avoid possible issues
3967  // if the PCB_SHAPE parser is modified.
3968  PCB_SHAPE* dummysegm = NULL;
3969 
3970  switch( token )
3971  {
3972  case T_gr_arc:
3973  dummysegm = parsePCB_SHAPE();
3974  pad->AddPrimitiveArc( dummysegm->GetCenter(), dummysegm->GetArcStart(),
3975  dummysegm->GetAngle(), dummysegm->GetWidth() );
3976  break;
3977 
3978  case T_gr_line:
3979  dummysegm = parsePCB_SHAPE();
3980  pad->AddPrimitiveSegment( dummysegm->GetStart(), dummysegm->GetEnd(),
3981  dummysegm->GetWidth() );
3982  break;
3983 
3984  case T_gr_circle:
3985  dummysegm = parsePCB_SHAPE();
3986  pad->AddPrimitiveCircle( dummysegm->GetCenter(), dummysegm->GetRadius(),
3987  dummysegm->GetWidth(), dummysegm->IsFilled() );
3988  break;
3989 
3990  case T_gr_rect:
3991  dummysegm = parsePCB_SHAPE();
3992  pad->AddPrimitiveRect( dummysegm->GetStart(), dummysegm->GetEnd(),
3993  dummysegm->GetWidth(), dummysegm->IsFilled() );
3994  break;
3995 
3996 
3997  case T_gr_poly:
3998  dummysegm = parsePCB_SHAPE();
3999  pad->AddPrimitivePoly( dummysegm->BuildPolyPointsList(), dummysegm->GetWidth(),
4000  dummysegm->IsFilled() );
4001  break;
4002 
4003  case T_gr_curve:
4004  dummysegm = parsePCB_SHAPE();
4005  pad->AddPrimitiveCurve( dummysegm->GetStart(), dummysegm->GetEnd(),
4006  dummysegm->GetBezControl1(),
4007  dummysegm->GetBezControl2(), dummysegm->GetWidth() );
4008  break;
4009 
4010  default:
4011  Expecting( "gr_line, gr_arc, gr_circle, gr_curve, gr_rect or gr_poly" );
4012  break;
4013  }
4014 
4015  delete dummysegm;
4016  }
4017  break;
4018 
4019  case T_remove_unused_layers:
4020  pad->SetRemoveUnconnected( true );
4021  NeedRIGHT();
4022  break;
4023 
4024  case T_keep_end_layers:
4025  pad->SetKeepTopBottom( true );
4026  NeedRIGHT();
4027  break;
4028 
4029  case T_locked:
4030  pad->SetLocked( true );
4031  NeedRIGHT();
4032  break;
4033 
4034  case T_tstamp:
4035  NextTok();
4036  const_cast<KIID&>( pad->m_Uuid ) = CurStrToKIID();
4037  NeedRIGHT();
4038  break;
4039 
4040  default:
4041  Expecting( "at, locked, drill, layers, net, die_length, roundrect_rratio, "
4042  "solder_mask_margin, solder_paste_margin, solder_paste_margin_ratio, "
4043  "clearance, tstamp, primitives, remove_unused_layers, keep_end_layers, "
4044  "pinfunction, pintype, zone_connect, thermal_width, or thermal_gap" );
4045  }
4046  }
4047 
4048  return pad.release();
4049 }
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1268
ZONE_CONNECTION
How pads are covered by copper in zone.
Definition: zones.h:41
bool IsFilled() const
Definition: pcb_shape.h:96
KIID CurStrToKIID()
LSET parseBoardItemLayersAsMask()
Parse the layers definition of a BOARD_ITEM object.
no special fabrication property
Definition: pad_shapes.h:96
const wxPoint & GetEnd() const
Function GetEnd returns the ending point of the graphic.
Definition: pcb_shape.h:156
a fiducial (usually a smd) for the full board
Definition: pad_shapes.h:98
int GetRadius() const
Function GetRadius returns the radius of this item Has meaning only for arc and circle.
Definition: pcb_shape.h:201
int GetWidth() const
Definition: pcb_shape.h:118
Smd pad, appears on the solder paste layer (default)
Definition: pad_shapes.h:81
Smd pad, used in BGA footprints.
Definition: pad_shapes.h:97
PCB_SHAPE * parsePCB_SHAPE()
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:85
a pad used as heat sink, usually in SMD footprints
Definition: pad_shapes.h:101
int parseBoardUnits()
Definition: pcb_parser.h:287
wxPoint GetArcStart() const
Definition: pcb_shape.h:179
a pad with a castellated through hole
Definition: pad_shapes.h:102
const std::vector< wxPoint > BuildPolyPointsList() const
Build and return the list of corners in a std::vector<wxPoint> It must be used only to convert the SH...
Definition: pcb_shape.cpp:1206
bool parsePAD_option(PAD *aPad)
LSET is a set of PCB_LAYER_IDs.
#define NULL
wxPoint GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_shape.cpp:341
const wxPoint & GetStart() const
Function GetStart returns the starting point of the graphic.
Definition: pcb_shape.h:145
Like smd, does not appear on the solder paste layer (default) note also has a special attribute in Ge...
Definition: pad_shapes.h:82
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:369
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
a fiducial (usually a smd) local to the parent footprint
Definition: pad_shapes.h:99
#define _(s)
Definition: 3d_actions.cpp:33
int getNetCode(int aNetCode)
< Convert net code using the mapping table if available, otherwise returns unchanged net code if < 0 ...
Definition: pcb_parser.h:130
BOARD * m_board
Definition: pcb_parser.h:358
const wxPoint & GetBezControl2() const
Definition: pcb_shape.h:136
double GetAngle() const
Definition: pcb_shape.h:127
Plated through hole pad.
Definition: pad_shapes.h:80
double parseDouble()
Parse the current token as an ASCII numeric string with possible leading whitespace into a double pre...
Definition: pcb_parser.cpp:139
int parseInt()
Definition: pcb_parser.h:324
a test point pad
Definition: pad_shapes.h:100
const wxPoint & GetBezControl1() const
Definition: pcb_shape.h:133

References _, PCB_SHAPE::BuildPolyPointsList(), Format(), PCB_SHAPE::GetAngle(), PCB_SHAPE::GetArcStart(), PCB_SHAPE::GetBezControl1(), PCB_SHAPE::GetBezControl2(), PCB_SHAPE::GetCenter(), PCB_SHAPE::GetEnd(), PCB_SHAPE::GetRadius(), PCB_SHAPE::GetStart(), PCB_SHAPE::GetWidth(), PCB_SHAPE::IsFilled(), NULL, NETINFO_LIST::ORPHANED, PAD_ATTRIB_CONN, PAD_ATTRIB_NPTH, PAD_ATTRIB_PTH, PAD_ATTRIB_SMD, PAD_DRILL_SHAPE_OBLONG, PAD_PROP_BGA, PAD_PROP_CASTELLATED, PAD_PROP_FIDUCIAL_GLBL, PAD_PROP_FIDUCIAL_LOCAL, PAD_PROP_HEATSINK, PAD_PROP_NONE, PAD_PROP_TESTPOINT, PAD_SHAPE_CHAMFERED_RECT, PAD_SHAPE_CIRCLE, PAD_SHAPE_CUSTOM, PAD_SHAPE_OVAL, PAD_SHAPE_RECT, PAD_SHAPE_ROUNDRECT, PAD_SHAPE_TRAPEZOID, parseDouble(), parseInt(), RECT_CHAMFER_BOTTOM_LEFT, RECT_CHAMFER_BOTTOM_RIGHT, RECT_CHAMFER_TOP_LEFT, RECT_CHAMFER_TOP_RIGHT, and RECT_NO_CHAMFER.

◆ parsePAD_option()

bool PCB_PARSER::parsePAD_option ( PAD aPad)
private

Definition at line 4052 of file pcb_parser.cpp.

4053 {
4054  // Parse only the (option ...) inside a pad description
4055  for( T token = NextTok(); token != T_RIGHT; token = NextTok() )
4056  {
4057  if( token != T_LEFT )
4058  Expecting( T_LEFT );
4059 
4060  token = NextTok();
4061 
4062  switch( token )
4063  {
4064  case T_anchor:
4065  token = NextTok();
4066  // Custom shaped pads have a "anchor pad", which is the reference
4067  // for connection calculations.
4068  // Because this is an anchor, only the 2 very basic shapes are managed:
4069  // circle and rect. The default is circle
4070  switch( token )
4071  {
4072  case T_circle: // default
4073  break;
4074 
4075  case T_rect:
4077  break;
4078 
4079  default:
4080  // Currently, because pad options is a moving target
4081  // just skip unknown keywords
4082  break;
4083  }
4084  NeedRIGHT();
4085  break;
4086 
4087  case T_clearance:
4088  token = NextTok();
4089  // Custom shaped pads have a clearance area that is the pad shape
4090  // (like usual pads) or the convex hull of the pad shape.
4091  switch( token )
4092  {
4093  case T_outline:
4095  break;
4096 
4097  case T_convexhull:
4099  break;
4100 
4101  default:
4102  // Currently, because pad options is a moving target
4103  // just skip unknown keywords
4104  break;
4105  }
4106  NeedRIGHT();
4107  break;
4108 
4109  default:
4110  // Currently, because pad options is a moving target
4111  // just skip unknown keywords
4112  while( (token = NextTok() ) != T_RIGHT )
4113  {}
4114  break;
4115  }
4116  }
4117 
4118  return true;
4119 }
void SetAnchorPadShape(PAD_SHAPE_T aShape)
Set the shape of the anchor pad for custom shaped pads.
Definition: pad.h:208
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:197

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

◆ parsePAGE_INFO()

void PCB_PARSER::parsePAGE_INFO ( )
private

Definition at line 923 of file pcb_parser.cpp.

924 {
925  wxCHECK_RET( ( CurTok() == T_page && m_requiredVersion <= 20200119 ) || CurTok() == T_paper,
926  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a PAGE_INFO." ) );
927 
928  T token;
929  PAGE_INFO pageInfo;
930 
931  NeedSYMBOL();
932 
933  wxString pageType = FromUTF8();
934 
935  if( !pageInfo.SetType( pageType ) )
936  {
937  wxString err;
938  err.Printf( _( "Page type \"%s\" is not valid " ), FromUTF8() );
939  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
940  }
941 
942  if( pageType == PAGE_INFO::Custom )
943  {
944  double width = parseDouble( "width" ); // width in mm
945 
946  // Perform some controls to avoid crashes if the size is edited by hands
947  if( width < 100.0 )
948  width = 100.0;
949  else if( width > 1200.0 )
950  width = 1200.0;
951 
952  double height = parseDouble( "height" ); // height in mm
953 
954  if( height < 100.0 )
955  height = 100.0;
956  else if( height > 1200.0 )
957  height = 1200.0;
958 
959  pageInfo.SetWidthMils( Mm2mils( width ) );
960  pageInfo.SetHeightMils( Mm2mils( height ) );
961  }
962 
963  token = NextTok();
964 
965  if( token == T_portrait )
966  {
967  pageInfo.SetPortrait( true );
968  NeedRIGHT();
969  }
970  else if( token != T_RIGHT )
971  {
972  Expecting( "portrait|)" );
973  }
974 
975  m_board->SetPageSettings( pageInfo );
976 }
int Mm2mils(double x)
Convert mm to mils.
Definition: base_units.h:62
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition: board.h:607
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
#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
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:364
#define _(s)
Definition: 3d_actions.cpp:33
BOARD * m_board
Definition: pcb_parser.h:358
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:139
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

We continue to parse the status field but it is no longer written

Definition at line 2145 of file pcb_parser.cpp.

2146 {
2147  wxCHECK_MSG( CurTok() == T_gr_arc || CurTok() == T_gr_circle || CurTok() == T_gr_curve ||
2148  CurTok() == T_gr_rect || CurTok() == T_gr_line || CurTok() == T_gr_poly, NULL,
2149  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PCB_SHAPE." ) );
2150 
2151  T token;
2152  wxPoint pt;
2153  std::unique_ptr<PCB_SHAPE> shape = std::make_unique<PCB_SHAPE>( nullptr );
2154 
2155  switch( CurTok() )
2156  {
2157  case T_gr_arc:
2158  shape->SetShape( S_ARC );
2159  NeedLEFT();
2160  token = NextTok();
2161 
2162  // the start keyword actually gives the arc center
2163  // Allows also T_center for future change
2164  if( token != T_start && token != T_center )
2165  Expecting( T_start );
2166 
2167  pt.x = parseBoardUnits( "X coordinate" );
2168  pt.y = parseBoardUnits( "Y coordinate" );
2169  shape->SetCenter( pt );
2170  NeedRIGHT();
2171  NeedLEFT();
2172  token = NextTok();
2173 
2174  if( token != T_end ) // the end keyword actually gives the starting point of the arc
2175  Expecting( T_end );
2176 
2177  pt.x = parseBoardUnits( "X coordinate" );
2178  pt.y = parseBoardUnits( "Y coordinate" );
2179  shape->SetArcStart( pt );
2180  NeedRIGHT();
2181  break;
2182 
2183  case T_gr_circle:
2184  shape->SetShape( S_CIRCLE );
2185  NeedLEFT();
2186  token = NextTok();
2187 
2188  if( token != T_center )
2189  Expecting( T_center );
2190 
2191  pt.x = parseBoardUnits( "X coordinate" );
2192  pt.y = parseBoardUnits( "Y coordinate" );
2193  shape->SetCenter( pt );
2194  NeedRIGHT();
2195  NeedLEFT();
2196 
2197  token = NextTok();
2198 
2199  if( token != T_end )
2200  Expecting( T_end );
2201 
2202  pt.x = parseBoardUnits( "X coordinate" );
2203  pt.y = parseBoardUnits( "Y coordinate" );
2204  shape->SetEnd( pt );
2205  NeedRIGHT();
2206  break;
2207 
2208  case T_gr_curve:
2209  shape->SetShape( S_CURVE );
2210  NeedLEFT();
2211  token = NextTok();
2212 
2213  if( token != T_pts )
2214  Expecting( T_pts );
2215 
2216  shape->SetStart( parseXY() );
2217  shape->SetBezControl1( parseXY() );
2218  shape->SetBezControl2( parseXY() );
2219  shape->SetEnd( parseXY() );
2220  NeedRIGHT();
2221  break;
2222 
2223  case T_gr_rect:
2224  shape->SetShape( S_RECT );
2225  NeedLEFT();
2226  token = NextTok();
2227 
2228  if( token != T_start )
2229  Expecting( T_start );
2230 
2231  pt.x = parseBoardUnits( "X coordinate" );
2232  pt.y = parseBoardUnits( "Y coordinate" );
2233  shape->SetStart( pt );
2234  NeedRIGHT();
2235  NeedLEFT();
2236  token = NextTok();
2237 
2238  if( token != T_end )
2239  Expecting( T_end );
2240 
2241  pt.x = parseBoardUnits( "X coordinate" );
2242  pt.y = parseBoardUnits( "Y coordinate" );
2243  shape->SetEnd( pt );
2244  NeedRIGHT();
2245  break;
2246 
2247  case T_gr_line:
2248  // Default PCB_SHAPE type is S_SEGMENT.
2249  NeedLEFT();
2250  token = NextTok();
2251 
2252  if( token != T_start )
2253  Expecting( T_start );
2254 
2255  pt.x = parseBoardUnits( "X coordinate" );
2256  pt.y = parseBoardUnits( "Y coordinate" );
2257  shape->SetStart( pt );
2258  NeedRIGHT();
2259  NeedLEFT();
2260  token = NextTok();
2261 
2262  if( token != T_end )
2263  Expecting( T_end );
2264 
2265  pt.x = parseBoardUnits( "X coordinate" );
2266  pt.y = parseBoardUnits( "Y coordinate" );
2267  shape->SetEnd( pt );
2268  NeedRIGHT();
2269  break;
2270 
2271  case T_gr_poly:
2272  {
2273  shape->SetShape( S_POLYGON );
2274  shape->SetWidth( 0 ); // this is the default value. will be (perhaps) modified later
2275  NeedLEFT();
2276  token = NextTok();
2277 
2278  if( token != T_pts )
2279  Expecting( T_pts );
2280 
2281  std::vector< wxPoint > pts;
2282 
2283  while( (token = NextTok() ) != T_RIGHT )
2284  pts.push_back( parseXY() );
2285 
2286  shape->SetPolyPoints( pts );
2287  }
2288  break;
2289 
2290  default:
2291  Expecting( "gr_arc, gr_circle, gr_curve, gr_line, gr_poly, or gp_rect" );
2292  }
2293 
2294  bool foundFill = false;
2295 
2296  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2297  {
2298  if( token != T_LEFT )
2299  Expecting( T_LEFT );
2300 
2301  token = NextTok();
2302 
2303  switch( token )
2304  {
2305  case T_angle:
2306  shape->SetAngle( parseDouble( "segment angle" ) * 10.0 );
2307  NeedRIGHT();
2308  break;
2309 
2310  case T_layer:
2311  shape->SetLayer( parseBoardItemLayer() );
2312  NeedRIGHT();
2313  break;
2314 
2315  case T_width:
2316  shape->SetWidth( parseBoardUnits( T_width ) );
2317  NeedRIGHT();
2318  break;
2319 
2320  case T_tstamp:
2321  NextTok();
2322  const_cast<KIID&>( shape->m_Uuid ) = CurStrToKIID();
2323  NeedRIGHT();
2324  break;
2325 
2326  case T_fill:
2327  foundFill = true;
2328 
2329  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2330  {
2331  if( token == T_LEFT )
2332  token = NextTok();
2333 
2334  switch( token )
2335  {
2336  // T_yes was used to indicate filling when first introduced,
2337  // so treat it like a solid fill since that was the only fill available
2338  case T_yes:
2339  case T_solid:
2340  shape->SetFilled( true );
2341  break;
2342 
2343  case T_none:
2344  shape->SetFilled( false );
2345  break;
2346 
2347  default:
2348  Expecting( "yes, none, solid" );
2349  }
2350  }
2351  break;
2352 
2354  case T_status:
2355  shape->SetStatus( static_cast<STATUS_FLAGS>( parseHex() ) );
2356  NeedRIGHT();
2357  break;
2358 
2359  case T_locked:
2360  shape->SetLocked( true );
2361  NeedRIGHT();
2362  break;
2363 
2364  default:
2365  Expecting( "layer, width, fill, tstamp, locked or status" );
2366  }
2367  }
2368 
2369  if( !foundFill )
2370  {
2371  // Legacy versions didn't have a filled flag but allowed some shapes to indicate they
2372  // should be filled by specifying a 0 stroke-width.
2373  if( shape->GetWidth() == 0
2374  && ( shape->GetShape() == S_RECT || shape->GetShape() == S_CIRCLE ) )
2375  {
2376  shape->SetFilled( true );
2377  }
2378  // Polygons on non-Edge_Cuts layers were always filled
2379  else if( shape->GetShape() == S_POLYGON && shape->GetLayer() != Edge_Cuts )
2380  {
2381  shape->SetFilled( true );
2382  }
2383  }
2384 
2385  // Only filled shapes may have a zero line-width. This is not permitted in KiCad but some
2386  // external tools can generate invalid files.
2387  if( shape->GetWidth() <= 0 && !shape->IsFilled() )
2388  {
2389  shape->SetWidth( Millimeter2iu( DEFAULT_LINE_WIDTH ) );
2390  }
2391 
2392  return shape.release();
2393 }
KIID CurStrToKIID()
wxPoint parseXY()
Parse a coordinate pair (xy X Y) in board units (mm).
Definition: pcb_parser.cpp:208
polygon (not yet used for tracks, but could be in microwave apps)
Definition: board_item.h:54
#define DEFAULT_LINE_WIDTH
Arcs (with rounded ends)
Definition: board_item.h:52
segment with non rounded ends
Definition: board_item.h:51
int parseBoardUnits()
Definition: pcb_parser.h:287
#define NULL
PCB_LAYER_ID parseBoardItemLayer()
Parse the layer definition of a BOARD_ITEM object.
double parseDouble()
Parse the current token as an ASCII numeric string with possible leading whitespace into a double pre...
Definition: pcb_parser.cpp:139
ring
Definition: board_item.h:53
long parseHex()
Definition: pcb_parser.h:335
Bezier Curve.
Definition: board_item.h:55
static constexpr int Millimeter2iu(double mm)

References DEFAULT_LINE_WIDTH, Edge_Cuts, Millimeter2iu(), NULL, parseDouble(), parseHex(), S_ARC, S_CIRCLE, S_CURVE, S_POLYGON, and S_RECT.

◆ parsePCB_TARGET()

PCB_TARGET * PCB_PARSER::parsePCB_TARGET ( )
private

Definition at line 5005 of file pcb_parser.cpp.

5006 {
5007  wxCHECK_MSG( CurTok() == T_target, NULL,
5008  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PCB_TARGET." ) );
5009 
5010  wxPoint pt;
5011  T token;
5012 
5013  std::unique_ptr<PCB_TARGET> target = std::make_unique<PCB_TARGET>( nullptr );
5014 
5015  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
5016  {
5017  if( token == T_LEFT )
5018  token = NextTok();
5019 
5020  switch( token )
5021  {
5022  case T_x:
5023  target->SetShape( 1 );
5024  break;
5025 
5026  case T_plus:
5027  target->SetShape( 0 );
5028  break;
5029 
5030  case T_at:
5031  pt.x = parseBoardUnits( "target x position" );
5032  pt.y = parseBoardUnits( "target y position" );
5033  target->SetPosition( pt );
5034  NeedRIGHT();
5035  break;
5036 
5037  case T_size:
5038  target->SetSize( parseBoardUnits( "target size" ) );
5039  NeedRIGHT();
5040  break;
5041 
5042  case T_width:
5043  target->SetWidth( parseBoardUnits( "target thickness" ) );
5044  NeedRIGHT();
5045  break;
5046 
5047  case T_layer:
5048  target->SetLayer( parseBoardItemLayer() );
5049  NeedRIGHT();
5050  break;
5051 
5052  case T_tstamp:
5053  NextTok();
5054  const_cast<KIID&>( target->m_Uuid ) = CurStrToKIID();
5055  NeedRIGHT();
5056  break;
5057 
5058  default:
5059  Expecting( "x, plus, at, size, width, layer or tstamp" );
5060  }
5061  }
5062 
5063  return target.release();
5064 }
KIID CurStrToKIID()
int parseBoardUnits()
Definition: pcb_parser.h:287
#define NULL
PCB_LAYER_ID parseBoardItemLayer()
Parse the layer definition of a BOARD_ITEM object.

References NULL.

◆ parsePCB_TEXT()

PCB_TEXT * PCB_PARSER::parsePCB_TEXT ( )
private

Definition at line 2396 of file pcb_parser.cpp.

2397 {
2398  wxCHECK_MSG( CurTok() == T_gr_text, NULL,
2399  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PCB_TEXT." ) );
2400 
2401  T token;
2402 
2403  std::unique_ptr<PCB_TEXT> text = std::make_unique<PCB_TEXT>( m_board );
2404  NeedSYMBOLorNUMBER();
2405 
2406  text->SetText( FromUTF8() );
2407  NeedLEFT();
2408  token = NextTok();
2409 
2410  if( token != T_at )
2411  Expecting( T_at );
2412 
2413  wxPoint pt;
2414 
2415  pt.x = parseBoardUnits( "X coordinate" );
2416  pt.y = parseBoardUnits( "Y coordinate" );
2417  text->SetTextPos( pt );
2418 
2419  // If there is no orientation defined, then it is the default value of 0 degrees.
2420  token = NextTok();
2421 
2422  if( token == T_NUMBER )
2423  {
2424  text->SetTextAngle( parseDouble() * 10.0 );
2425  NeedRIGHT();
2426  }
2427  else if( token != T_RIGHT )
2428  {
2429  Unexpected( CurText() );
2430  }
2431 
2432  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2433  {
2434  if( token != T_LEFT )
2435  Expecting( T_LEFT );
2436 
2437  token = NextTok();
2438 
2439  switch( token )
2440  {
2441  case T_layer:
2442  text->SetLayer( parseBoardItemLayer() );
2443  NeedRIGHT();
2444  break;
2445 
2446  case T_tstamp:
2447  NextTok();
2448  const_cast<KIID&>( text->m_Uuid ) = CurStrToKIID();
2449  NeedRIGHT();
2450  break;
2451 
2452  case T_effects:
2453  parseEDA_TEXT( (EDA_TEXT*) text.get() );
2454  break;
2455 
2456  default:
2457  Expecting( "layer, tstamp or effects" );
2458  }
2459  }
2460 
2461  return text.release();
2462 }
KIID CurStrToKIID()
void parseEDA_TEXT(EDA_TEXT *aText)
Parse the common settings for any object derived from EDA_TEXT.
Definition: pcb_parser.cpp:255
int parseBoardUnits()
Definition: pcb_parser.h:287
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:119
#define NULL
PCB_LAYER_ID parseBoardItemLayer()
Parse the layer definition of a BOARD_ITEM object.
BOARD * m_board
Definition: pcb_parser.h:358
double parseDouble()
Parse the current token as an ASCII numeric string with possible leading whitespace into a double pre...
Definition: pcb_parser.cpp:139

References NULL, and parseDouble().

◆ parseProperty()

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

Definition at line 240 of file pcb_parser.cpp.

241 {
242  wxString pName;
243  wxString pValue;
244 
245  NeedSYMBOL();
246  pName = FromUTF8();
247  NeedSYMBOL();
248  pValue = FromUTF8();
249  NeedRIGHT();
250 
251  return { pName, pValue };
252 }

◆ parseSetup()

void PCB_PARSER::parseSetup ( )
private

Definition at line 1576 of file pcb_parser.cpp.

1577 {
1578  wxCHECK_RET( CurTok() == T_setup,
1579  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as setup." ) );
1580 
1581  T token;
1582  NETCLASS* defaultNetClass = m_board->GetDesignSettings().GetDefault();
1583  BOARD_DESIGN_SETTINGS& designSettings = m_board->GetDesignSettings();
1584  ZONE_SETTINGS& zoneSettings = designSettings.GetDefaultZoneSettings();
1585 
1586  // Missing soldermask min width value means that the user has set the value to 0 and
1587  // not the default value (0.25mm)
1588  designSettings.m_SolderMaskMinWidth = 0;
1589 
1590  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1591  {
1592  if( token != T_LEFT )
1593  Expecting( T_LEFT );
1594 
1595  token = NextTok();
1596 
1597  switch( token )
1598  {
1599  case T_stackup:
1601  break;
1602 
1603  case T_last_trace_width: // not used now
1604  /* lastTraceWidth =*/ parseBoardUnits( T_last_trace_width );
1605  NeedRIGHT();
1606  break;
1607 
1608  case T_user_trace_width:
1609  {
1610  // Make room for the netclass value
1611  if( designSettings.m_TrackWidthList.empty() )
1612  designSettings.m_TrackWidthList.emplace_back( 0 );
1613 
1614  designSettings.m_TrackWidthList.push_back( parseBoardUnits( T_user_trace_width ) );
1616  NeedRIGHT();
1617  break;
1618  }
1619 
1620  case T_trace_clearance:
1621  defaultNetClass->SetClearance( parseBoardUnits( T_trace_clearance ) );
1623  NeedRIGHT();
1624  break;
1625 
1626  case T_zone_clearance:
1627  zoneSettings.m_ZoneClearance = parseBoardUnits( T_zone_clearance );
1629  NeedRIGHT();
1630  break;
1631 
1632  case T_zone_45_only:
1633  zoneSettings.m_Zone_45_Only = parseBool();
1635  NeedRIGHT();
1636  break;
1637 
1638  case T_clearance_min:
1639  designSettings.m_MinClearance = parseBoardUnits( T_clearance_min );
1641  NeedRIGHT();
1642  break;
1643 
1644  case T_trace_min:
1645  designSettings.m_TrackMinWidth = parseBoardUnits( T_trace_min );
1647  NeedRIGHT();
1648  break;
1649 
1650  case T_via_size:
1651  defaultNetClass->SetViaDiameter( parseBoardUnits( T_via_size ) );
1653  NeedRIGHT();
1654  break;
1655 
1656  case T_via_drill:
1657  defaultNetClass->SetViaDrill( parseBoardUnits( T_via_drill ) );
1659  NeedRIGHT();
1660  break;
1661 
1662  case T_via_min_annulus:
1663  designSettings.m_ViasMinAnnulus = parseBoardUnits( T_via_min_annulus );
1665  NeedRIGHT();
1666  break;
1667 
1668  case T_via_min_size:
1669  designSettings.m_ViasMinSize = parseBoardUnits( T_via_min_size );
1671  NeedRIGHT();
1672  break;
1673 
1674  case T_through_hole_min:
1675  designSettings.m_MinThroughDrill = parseBoardUnits( T_through_hole_min );
1677  NeedRIGHT();
1678  break;
1679 
1680  // Legacy token for T_through_hole_min
1681  case T_via_min_drill:
1682  designSettings.m_MinThroughDrill = parseBoardUnits( T_via_min_drill );
1684  NeedRIGHT();
1685  break;
1686 
1687  case T_hole_to_hole_min:
1688  designSettings.m_HoleToHoleMin = parseBoardUnits( T_hole_to_hole_min );
1690  NeedRIGHT();
1691  break;
1692 
1693  case T_user_via:
1694  {
1695  int viaSize = parseBoardUnits( "user via size" );
1696  int viaDrill = parseBoardUnits( "user via drill" );
1697 
1698  // Make room for the netclass value
1699  if( designSettings.m_ViasDimensionsList.empty() )
1700  designSettings.m_ViasDimensionsList.emplace_back( VIA_DIMENSION( 0, 0 ) );
1701 
1702  designSettings.m_ViasDimensionsList.emplace_back( VIA_DIMENSION( viaSize, viaDrill ) );
1704  NeedRIGHT();
1705  }
1706  break;
1707 
1708  case T_uvia_size:
1709  defaultNetClass->SetuViaDiameter( parseBoardUnits( T_uvia_size ) );
1711  NeedRIGHT();
1712  break;
1713 
1714  case T_uvia_drill:
1715  defaultNetClass->SetuViaDrill( parseBoardUnits( T_uvia_drill ) );
1717  NeedRIGHT();
1718  break;
1719 
1720  case T_uvias_allowed:
1721  designSettings.m_MicroViasAllowed = parseBool();
1723  NeedRIGHT();
1724  break;
1725 
1726  case T_blind_buried_vias_allowed:
1727  designSettings.m_BlindBuriedViaAllowed = parseBool();
1729  NeedRIGHT();
1730  break;
1731 
1732  case T_uvia_min_size:
1733  designSettings.m_MicroViasMinSize = parseBoardUnits( T_uvia_min_size );
1735  NeedRIGHT();
1736  break;
1737 
1738  case T_uvia_min_drill:
1739  designSettings.m_MicroViasMinDrill = parseBoardUnits( T_uvia_min_drill );
1741  NeedRIGHT();
1742  break;
1743 
1744  case T_user_diff_pair:
1745  {
1746  int width = parseBoardUnits( "user diff-pair width" );
1747  int gap = parseBoardUnits( "user diff-pair gap" );
1748  int viaGap = parseBoardUnits( "user diff-pair via gap" );
1749  designSettings.m_DiffPairDimensionsList.emplace_back( DIFF_PAIR_DIMENSION( width, gap, viaGap ) );
1751  NeedRIGHT();
1752  }
1753  break;
1754 
1755  case T_segment_width: // note: legacy (pre-6.0) token
1756  designSettings.m_LineThickness[ LAYER_CLASS_COPPER ] = parseBoardUnits( T_segment_width );
1758  NeedRIGHT();
1759  break;
1760 
1761  case T_edge_width: // note: legacy (pre-6.0) token
1762  designSettings.m_LineThickness[ LAYER_CLASS_EDGES ] = parseBoardUnits( T_edge_width );
1764  NeedRIGHT();
1765  break;
1766 
1767  case T_mod_edge_width: // note: legacy (pre-6.0) token
1768  designSettings.m_LineThickness[ LAYER_CLASS_SILK ] = parseBoardUnits( T_mod_edge_width );
1770  NeedRIGHT();
1771  break;
1772 
1773  case T_pcb_text_width: // note: legacy (pre-6.0) token
1774  designSettings.m_TextThickness[ LAYER_CLASS_COPPER ] = parseBoardUnits( T_pcb_text_width );
1776  NeedRIGHT();
1777  break;
1778 
1779  case T_mod_text_width: // note: legacy (pre-6.0) token
1780  designSettings.m_TextThickness[ LAYER_CLASS_SILK ] = parseBoardUnits( T_mod_text_width );
1782  NeedRIGHT();
1783  break;
1784 
1785  case T_pcb_text_size: // note: legacy (pre-6.0) token
1786  designSettings.m_TextSize[ LAYER_CLASS_COPPER ].x = parseBoardUnits( "pcb text width" );
1787  designSettings.m_TextSize[ LAYER_CLASS_COPPER ].y = parseBoardUnits( "pcb text height" );
1789  NeedRIGHT();
1790  break;
1791 
1792  case T_mod_text_size: // note: legacy (pre-6.0) token
1793  designSettings.m_TextSize[ LAYER_CLASS_SILK ].x = parseBoardUnits( "footprint text width" );
1794  designSettings.m_TextSize[ LAYER_CLASS_SILK ].y = parseBoardUnits( "footprint text height" );
1796  NeedRIGHT();
1797  break;
1798 
1799  case T_defaults:
1800  parseDefaults( designSettings );
1802  break;
1803 
1804  case T_pad_size:
1805  {
1806  wxSize sz;
1807  sz.SetWidth( parseBoardUnits( "master pad width" ) );
1808  sz.SetHeight( parseBoardUnits( "master pad height" ) );
1809  designSettings.m_Pad_Master.SetSize( sz );
1811  NeedRIGHT();
1812  }
1813  break;
1814 
1815  case T_pad_drill:
1816  {
1817  int drillSize = parseBoardUnits( T_pad_drill );
1818  designSettings.m_Pad_Master.SetDrillSize( wxSize( drillSize, drillSize ) );
1820  NeedRIGHT();
1821  }
1822  break;
1823 
1824  case T_pad_to_mask_clearance:
1825  designSettings.m_SolderMaskMargin = parseBoardUnits( T_pad_to_mask_clearance );
1826  NeedRIGHT();
1827  break;
1828 
1829  case T_solder_mask_min_width:
1830  designSettings.m_SolderMaskMinWidth = parseBoardUnits( T_solder_mask_min_width );
1831  NeedRIGHT();
1832  break;
1833 
1834  case T_pad_to_paste_clearance:
1835  designSettings.m_SolderPasteMargin = parseBoardUnits( T_pad_to_paste_clearance );
1836  NeedRIGHT();
1837  break;
1838 
1839  case T_pad_to_paste_clearance_ratio:
1840  designSettings.m_SolderPasteMarginRatio = parseDouble( T_pad_to_paste_clearance_ratio );
1841  NeedRIGHT();
1842  break;
1843 
1844  case T_aux_axis_origin:
1845  {
1846  int x = parseBoardUnits( "auxiliary origin X" );
1847  int y = parseBoardUnits( "auxiliary origin Y" );
1848  designSettings.m_AuxOrigin = wxPoint( x, y );
1849  // Aux origin still stored in board for the moment
1850  //m_board->m_LegacyDesignSettingsLoaded = true;
1851  NeedRIGHT();
1852  }
1853  break;
1854 
1855  case T_grid_origin:
1856  {
1857  int x = parseBoardUnits( "grid origin X" );
1858  int y = parseBoardUnits( "grid origin Y" );
1859  designSettings.m_GridOrigin = wxPoint( x, y );
1860  // Grid origin still stored in board for the moment
1861  //m_board->m_LegacyDesignSettingsLoaded = true;
1862  NeedRIGHT();
1863  }
1864  break;
1865 
1866  // Stored in board prior to 6.0
1867  case T_visible_elements:
1868  {
1869  // Make sure to start with DefaultVisible so all new layers are set
1871 
1872  int visible = parseHex() | MIN_VISIBILITY_MASK;
1873 
1874  for( size_t i = 0; i < sizeof( int ) * CHAR_BIT; i++ )
1875  m_board->m_LegacyVisibleItems.set( i, visible & ( 1u << i ) );
1876 
1877  NeedRIGHT();
1878  }
1879  break;
1880 
1881  case T_max_error:
1882  designSettings.m_MaxError = parseBoardUnits( T_max_error );
1884  NeedRIGHT();
1885  break;
1886 
1887  case T_filled_areas_thickness: // Note: legacy (early 5.99) token
1888  designSettings.m_ZoneFillVersion = parseBool() ? 5 : 6;
1890  NeedRIGHT();
1891  break;
1892 
1893  case T_pcbplotparams:
1894  {
1895  PCB_PLOT_PARAMS plotParams;
1896  PCB_PLOT_PARAMS_PARSER parser( reader );
1897  // parser must share the same current line as our current PCB parser
1898  // synchronize it.
1899  parser.SyncLineReaderWith( *this );
1900 
1901  plotParams.Parse( &parser );
1902  SyncLineReaderWith( parser );
1903 
1904  m_board->SetPlotOptions( plotParams );
1905  }
1906  break;
1907 
1908  default:
1909  Unexpected( CurText() );
1910  }
1911  }
1912 }
Container to handle a stock of specific vias each with unique diameter and drill sizes in the BOARD c...
int m_ZoneFillVersion
Option to select different fill algorithms.
wxPoint m_GridOrigin
origin for grid offsets
bool m_LegacyDesignSettingsLoaded
True if the legacy board design settings were loaded from a file.
Definition: board.h:338
PCB_PLOT_PARAMS_PARSER is the parser class for PCB_PLOT_PARAMS.
std::vector< int > m_TrackWidthList
std::vector< DIFF_PAIR_DIMENSION > m_DiffPairDimensionsList
void parseBoardStackup()
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.h:591
void SetSize(const wxSize &aSize)
Definition: pad.h:231
Container to handle a stock of specific differential pairs each with unique track width,...
void SetViaDrill(int aSize)
Definition: netclass.h:137
int parseBoardUnits()
Definition: pcb_parser.h:287
wxSize m_TextSize[LAYER_CLASS_COUNT]
bool parseBool()
Definition: pcb_parser.cpp:169
int m_TextThickness[LAYER_CLASS_COUNT]
#define MIN_VISIBILITY_MASK
void SetClearance(int aClearance)
Definition: netclass.h:125
void SetDrillSize(const wxSize &aSize)
Definition: pad.h:241
A collection of nets and the parameters used to route or test these nets.
Definition: netclass.h:46
static GAL_SET DefaultVisible()
Definition: lset.cpp:933
bool m_BlindBuriedViaAllowed
true to allow blind/buried vias
void SetPlotOptions(const PCB_PLOT_PARAMS &aOptions)
Definition: board.h:610
void SetuViaDiameter(int aSize)
Definition: netclass.h:141
PCB_PLOT_PARAMS handles plot parameters and options when plotting/printing a board.
int m_LineThickness[LAYER_CLASS_COUNT]
void parseDefaults(BOARD_DESIGN_SETTINGS &aSettings)
ZONE_SETTINGS handles zones parameters.
Definition: zone_settings.h:67
void SetuViaDrill(int aSize)
Definition: netclass.h:145
BOARD * m_board
Definition: pcb_parser.h:358
NETCLASS * GetDefault() const
std::vector< VIA_DIMENSION > m_ViasDimensionsList
double parseDouble()
Parse the current token as an ASCII numeric string with possible leading whitespace into a double pre...
Definition: pcb_parser.cpp:139
void SetViaDiameter(int aDia)
Definition: netclass.h:133
ZONE_SETTINGS & GetDefaultZoneSettings()
bool m_MicroViasAllowed
true to allow micro vias
long parseHex()
Definition: pcb_parser.h:335
void Parse(PCB_PLOT_PARAMS_PARSER *aParser)
wxPoint m_AuxOrigin
origin for plot exports
Container for design settings for a BOARD object.
GAL_SET m_LegacyVisibleItems
Definition: board.h:335

References GAL_SET::DefaultVisible(), BOARD_DESIGN_SETTINGS::GetDefaultZoneSettings(), LAYER_CLASS_COPPER, LAYER_CLASS_EDGES, LAYER_CLASS_SILK, BOARD_DESIGN_SETTINGS::m_AuxOrigin, BOARD_DESIGN_SETTINGS::m_BlindBuriedViaAllowed, BOARD_DESIGN_SETTINGS::m_DiffPairDimensionsList, BOARD_DESIGN_SETTINGS::m_GridOrigin, BOARD_DESIGN_SETTINGS::m_HoleToHoleMin, BOARD_DESIGN_SETTINGS::m_LineThickness, BOARD_DESIGN_SETTINGS::m_MaxError, BOARD_DESIGN_SETTINGS::m_MicroViasAllowed, BOARD_DESIGN_SETTINGS::m_MicroViasMinDrill, BOARD_DESIGN_SETTINGS::m_MicroViasMinSize, BOARD_DESIGN_SETTINGS::m_MinClearance, BOARD_DESIGN_SETTINGS::m_MinThroughDrill, BOARD_DESIGN_SETTINGS::m_Pad_Master, BOARD_DESIGN_SETTINGS::m_SolderMaskMargin, BOARD_DESIGN_SETTINGS::m_SolderMaskMinWidth, BOARD_DESIGN_SETTINGS::m_SolderPasteMargin, BOARD_DESIGN_SETTINGS::m_SolderPasteMarginRatio, BOARD_DESIGN_SETTINGS::m_TextSize, BOARD_DESIGN_SETTINGS::m_TextThickness, BOARD_DESIGN_SETTINGS::m_TrackMinWidth, BOARD_DESIGN_SETTINGS::m_TrackWidthList, BOARD_DESIGN_SETTINGS::m_ViasDimensionsList, BOARD_DESIGN_SETTINGS::m_ViasMinAnnulus, BOARD_DESIGN_SETTINGS::m_ViasMinSize, ZONE_SETTINGS::m_Zone_45_Only, ZONE_SETTINGS::m_ZoneClearance, BOARD_DESIGN_SETTINGS::m_ZoneFillVersion, MIN_VISIBILITY_MASK, PCB_PLOT_PARAMS::Parse(), parseDouble(), parseHex(), NETCLASS::SetClearance(), PAD::SetDrillSize(), PAD::SetSize(), NETCLASS::SetuViaDiameter(), NETCLASS::SetuViaDrill(), NETCLASS::SetViaDiameter(), and NETCLASS::SetViaDrill().

◆ parseTITLE_BLOCK()

void PCB_PARSER::parseTITLE_BLOCK ( )
private

Definition at line 979 of file pcb_parser.cpp.

980 {
981  wxCHECK_RET( CurTok() == T_title_block,
982  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
983  wxT( " as TITLE_BLOCK." ) );
984 
985  T token;
986  TITLE_BLOCK titleBlock;
987 
988  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
989  {
990  if( token != T_LEFT )
991  Expecting( T_LEFT );
992 
993  token = NextTok();
994 
995  switch( token )
996  {
997  case T_title:
998  NextTok();
999  titleBlock.SetTitle( FromUTF8() );
1000  break;
1001 
1002  case T_date:
1003  NextTok();
1004  titleBlock.SetDate( FromUTF8() );
1005  break;
1006 
1007  case T_rev:
1008  NextTok();
1009  titleBlock.SetRevision( FromUTF8() );
1010  break;
1011 
1012  case T_company:
1013  NextTok();
1014  titleBlock.SetCompany( FromUTF8() );
1015  break;
1016 
1017  case T_comment:
1018  {
1019  int commentNumber = parseInt( "comment" );
1020 
1021  switch( commentNumber )
1022  {
1023  case 1:
1024  NextTok();
1025  titleBlock.SetComment( 0, FromUTF8() );
1026  break;
1027 
1028  case 2:
1029  NextTok();
1030  titleBlock.SetComment( 1, FromUTF8() );
1031  break;
1032 
1033  case 3:
1034  NextTok();
1035  titleBlock.SetComment( 2, FromUTF8() );
1036  break;
1037 
1038  case 4:
1039  NextTok();
1040  titleBlock.SetComment( 3, FromUTF8() );
1041  break;
1042 
1043  case 5:
1044  NextTok();
1045  titleBlock.SetComment( 4, FromUTF8() );
1046  break;
1047 
1048  case 6:
1049  NextTok();
1050  titleBlock.SetComment( 5, FromUTF8() );
1051  break;
1052 
1053  case 7:
1054  NextTok();
1055  titleBlock.SetComment( 6, FromUTF8() );
1056  break;
1057 
1058  case 8:
1059  NextTok();
1060  titleBlock.SetComment( 7, FromUTF8() );
1061  break;
1062 
1063  case 9:
1064  NextTok();
1065  titleBlock.SetComment( 8, FromUTF8() );
1066  break;
1067 
1068  default:
1069  wxString err;
1070  err.Printf( wxT( "%d is not a valid title block comment number" ), commentNumber );
1071  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
1072  }
1073  }
1074  break;
1075 
1076  default:
1077  Expecting( "title, date, rev, company, or comment" );
1078  }
1079 
1080  NeedRIGHT();
1081  }
1082 
1083  m_board->SetTitleBlock( titleBlock );
1084 }
void SetRevision(const wxString &aRevision)
Definition: title_block.h:81
void SetTitleBlock(const TITLE_BLOCK &aTitleBlock)
Definition: board.h:614
void SetDate(const wxString &aDate)
Set the date field, and defaults to the current time and date.
Definition: title_block.h:71
Hold the information shown in the lower right corner of a plot, printout, or editing view.
Definition: title_block.h:40
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:164
void SetComment(int aIdx, const wxString &aComment)
Definition: title_block.h:101
void SetCompany(const wxString &aCompany)
Definition: title_block.h:91
void SetTitle(const wxString &aTitle)
Definition: title_block.h:58
BOARD * m_board
Definition: pcb_parser.h:358
int parseInt()
Definition: pcb_parser.h:324

References parseInt(), TITLE_BLOCK::SetComment(), TITLE_BLOCK::SetCompany(), TITLE_BLOCK::SetDate(), TITLE_BLOCK::SetRevision(), TITLE_BLOCK::SetTitle(), and THROW_PARSE_ERROR.

◆ parseTRACK()

TRACK * PCB_PARSER::parseTRACK ( )
private

We continue to parse the status field but it is no longer written

Definition at line 4260 of file pcb_parser.cpp.

4261 {
4262  wxCHECK_MSG( CurTok() == T_segment, NULL,
4263  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as TRACK." ) );
4264 
4265  wxPoint pt;
4266  T token;
4267 
4268  std::unique_ptr<TRACK> track = std::make_unique<TRACK>( m_board );
4269 
4270  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4271  {
4272  if( token != T_LEFT )
4273  Expecting( T_LEFT );
4274 
4275  token = NextTok();
4276 
4277  switch( token )
4278  {
4279  case T_start:
4280  pt.x = parseBoardUnits( "start x" );
4281  pt.y = parseBoardUnits( "start y" );
4282  track->SetStart( pt );
4283  break;
4284 
4285  case T_end:
4286  pt.x = parseBoardUnits( "end x" );
4287  pt.y = parseBoardUnits( "end y" );
4288  track->SetEnd( pt );
4289  break;
4290 
4291  case T_width:
4292  track->SetWidth( parseBoardUnits( "width" ) );
4293  break;
4294 
4295  case T_layer:
4296  track->SetLayer( parseBoardItemLayer() );
4297  break;
4298 
4299  case T_net:
4300  if( !track->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
4302  _( "Invalid net ID in\nfile: \"%s\"\nline: %d\noffset: %d" ), CurSource(),
4303  CurLineNumber(), CurOffset() ) );
4304  break;
4305 
4306  case T_tstamp:
4307  NextTok();
4308  const_cast<KIID&>( track->m_Uuid ) = CurStrToKIID();
4309  break;
4310 
4312  case T_status:
4313  track->SetStatus( static_cast<STATUS_FLAGS>( parseHex() ) );
4314  break;
4315 
4316  case T_locked:
4317  track->SetLocked( true );
4318  break;
4319 
4320  default:
4321  Expecting( "start, end, width, layer, net, tstamp, or locked" );
4322  }
4323 
4324  NeedRIGHT();
4325  }
4326 
4327  return track.release();
4328 }
KIID CurStrToKIID()
int parseBoardUnits()
Definition: pcb_parser.h:287
#define NULL
PCB_LAYER_ID parseBoardItemLayer()
Parse the layer definition of a BOARD_ITEM object.
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 _(s)
Definition: 3d_actions.cpp:33
int getNetCode(int aNetCode)
< Convert net code using the mapping table if available, otherwise returns unchanged net code if < 0 ...
Definition: pcb_parser.h:130
BOARD * m_board
Definition: pcb_parser.h:358
long parseHex()
Definition: pcb_parser.h:335
int parseInt()
Definition: pcb_parser.h:324
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38

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

◆ parseVIA()

VIA * PCB_PARSER::parseVIA ( )
private

We continue to parse the status field but it is no longer written

Definition at line 4331 of file pcb_parser.cpp.

4332 {
4333  wxCHECK_MSG( CurTok() == T_via, NULL,
4334  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as VIA." ) );
4335 
4336  wxPoint pt;
4337  T token;
4338 
4339  std::unique_ptr<VIA> via = std::make_unique<VIA>( m_board );
4340 
4341  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4342  {
4343  if( token == T_LEFT )
4344  token = NextTok();
4345 
4346  switch( token )
4347  {
4348  case T_blind:
4349  via->SetViaType( VIATYPE::BLIND_BURIED );
4350  break;
4351 
4352  case T_micro:
4353  via->SetViaType( VIATYPE::MICROVIA );
4354  break;
4355 
4356  case T_at:
4357  pt.x = parseBoardUnits( "start x" );
4358  pt.y = parseBoardUnits( "start y" );
4359  via->SetStart( pt );
4360  via->SetEnd( pt );
4361  NeedRIGHT();
4362  break;
4363 
4364  case T_size:
4365  via->SetWidth( parseBoardUnits( "via width" ) );
4366  NeedRIGHT();
4367  break;
4368 
4369  case T_drill:
4370  via->SetDrill( parseBoardUnits( "drill diameter" ) );
4371  NeedRIGHT();
4372  break;
4373 
4374  case T_layers:
4375  {
4376  PCB_LAYER_ID layer1, layer2;
4377  NextTok();
4378  layer1 = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
4379  NextTok();
4380  layer2 = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
4381  via->SetLayerPair( layer1, layer2 );
4382  NeedRIGHT();
4383  }
4384  break;
4385 
4386  case T_net:
4387  if( !via->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
4388  {
4389  THROW_IO_ERROR( wxString::Format( _( "Invalid net ID in\n"
4390  "file: '%s'\n"
4391  "line: %d\n"
4392  "offset: %d" ),
4393  CurSource(),
4394  CurLineNumber(),
4395  CurOffset() ) );
4396  }
4397 
4398  NeedRIGHT();
4399  break;
4400 
4401  case T_remove_unused_layers:
4402  via->SetRemoveUnconnected( true );
4403  NeedRIGHT();
4404  break;
4405 
4406  case T_keep_end_layers:
4407  via->SetKeepTopBottom( true );
4408  NeedRIGHT();
4409  break;
4410 
4411  case T_tstamp:
4412  NextTok();
4413  const_cast<KIID&>( via->m_Uuid ) = CurStrToKIID();
4414  NeedRIGHT();
4415  break;
4416 
4418  case T_status:
4419  via->SetStatus( static_cast<STATUS_FLAGS>( parseHex() ) );
4420  NeedRIGHT();
4421  break;
4422 
4423  case T_locked:
4424  via->SetLocked( true );
4425  NeedRIGHT();
4426  break;
4427 
4428  case T_free:
4429  via->SetIsFree();
4430  NeedRIGHT();
4431  break;
4432 
4433  default:
4434  Expecting( "blind, micro, at, size, drill, layers, net, free, tstamp, or status" );
4435  }
4436  }
4437 
4438  return via.release();
4439 }
KIID CurStrToKIID()
int parseBoardUnits()
Definition: pcb_parser.h:287
PCB_LAYER_ID
A quick note on layer IDs:
#define NULL
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 _(s)
Definition: 3d_actions.cpp:33
int getNetCode(int aNetCode)
< Convert net code using the mapping table if available, otherwise returns unchanged net code if < 0 ...
Definition: pcb_parser.h:130
BOARD * m_board
Definition: pcb_parser.h:358
LAYER_ID_MAP m_layerIndices
map layer name to it's index
Definition: pcb_parser.h:359
long parseHex()
Definition: pcb_parser.h:335
int parseInt()
Definition: pcb_parser.h:324
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38

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

◆ parseXY() [1/2]

wxPoint PCB_PARSER::parseXY ( )
private

Parse a coordinate pair (xy X Y) in board units (mm).

The parser checks if the previous token was T_LEFT and parses the remainder of the token syntax. This is used when parsing a list of coordinate points. This way the parser can be used in either case.

Returns
A wxPoint object containing the coordinate pair.
Exceptions
PARSE_ERRORif the coordinate pair syntax is incorrect.

Definition at line 208 of file pcb_parser.cpp.

209 {
210  if( CurTok() != T_LEFT )
211  NeedLEFT();
212 
213  wxPoint pt;
214  T token = NextTok();
215 
216  if( token != T_xy )
217  Expecting( T_xy );
218 
219  pt.x = parseBoardUnits( "X coordinate" );
220  pt.y = parseBoardUnits( "Y coordinate" );
221 
222  NeedRIGHT();
223 
224  return pt;
225 }
int parseBoardUnits()
Definition: pcb_parser.h:287

◆ parseXY() [2/2]

void PCB_PARSER::parseXY ( int *  aX,
int *  aY 
)
private

Definition at line 228 of file pcb_parser.cpp.

229 {
230  wxPoint pt = parseXY();
231 
232  if( aX )
233  *aX = pt.x;
234 
235  if( aY )
236  *aY = pt.y;
237 }
wxPoint parseXY()
Parse a coordinate pair (xy X Y) in board units (mm).
Definition: pcb_parser.cpp:208

◆ parseZONE()

ZONE * PCB_PARSER::parseZONE ( BOARD_ITEM_CONTAINER aParent)
private

Definition at line 4442 of file pcb_parser.cpp.

4443 {
4444  wxCHECK_MSG( CurTok() == T_zone, NULL,
4445  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
4446  wxT( " as ZONE." ) );
4447 
4449 
4450  int hatchPitch = ZONE::GetDefaultHatchPitch();
4451  wxPoint pt;
4452  T token;
4453  int tmp;
4454  wxString netnameFromfile; // the zone net name find in file
4455 
4456  // bigger scope since each filled_polygon is concatenated in here
4457  std::map<PCB_LAYER_ID, SHAPE_POLY_SET> pts;
4458  bool inFootprint = false;
4459  PCB_LAYER_ID filledLayer;
4460  bool addedFilledPolygons = false;
4461 
4462  if( dynamic_cast<FOOTPRINT*>( aParent ) ) // The zone belongs a footprint
4463  inFootprint = true;
4464 
4465  std::unique_ptr<ZONE> zone;
4466 
4467  if( inFootprint )
4468  zone = std::make_unique<FP_ZONE>( aParent );
4469  else
4470  zone = std::make_unique<ZONE>( aParent );
4471 
4472  zone->SetPriority( 0 );
4473 
4474  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4475  {
4476  if( token == T_LEFT )
4477  token = NextTok();
4478 
4479  switch( token )
4480  {
4481  case T_net:
4482  // Init the net code only, not the netname, to be sure
4483  // the zone net name is the name read in file.
4484  // (When mismatch, the user will be prompted in DRC, to fix the actual name)
4485  tmp = getNetCode( parseInt( "net number" ) );
4486 
4487  if( tmp < 0 )
4488  tmp = 0;
4489 
4490  if( !zone->SetNetCode( tmp, /* aNoAssert */ true ) )
4492  _( "Invalid net ID in\nfile: \"%s\"\nline: %d\noffset: %d" ), CurSource(),
4493  CurLineNumber(), CurOffset() ) );
4494 
4495  NeedRIGHT();
4496  break;
4497 
4498  case T_net_name:
4499  NeedSYMBOLorNUMBER();
4500  netnameFromfile = FromUTF8();
4501  NeedRIGHT();
4502  break;
4503 
4504  case T_layer: // keyword for zones that are on only one layer
4505  zone->SetLayer( parseBoardItemLayer() );
4506  NeedRIGHT();
4507  break;
4508 
4509  case T_layers: // keyword for zones that can live on a set of layers
4510  zone->SetLayerSet( parseBoardItemLayersAsMask() );
4511  break;
4512 
4513  case T_tstamp:
4514  NextTok();
4515  const_cast<KIID&>( zone->m_Uuid ) = CurStrToKIID();
4516  NeedRIGHT();
4517  break;
4518 
4519  case T_hatch:
4520  token = NextTok();
4521 
4522  if( token != T_none && token != T_edge && token != T_full )
4523  Expecting( "none, edge, or full" );
4524 
4525  switch( token )
4526  {
4527  default:
4528  case T_none: hatchStyle = ZONE_BORDER_DISPLAY_STYLE::NO_HATCH; break;
4529  case T_edge: hatchStyle = ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_EDGE; break;
4530  case T_full: hatchStyle = ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_FULL; break;
4531  }
4532 
4533  hatchPitch = parseBoardUnits( "hatch pitch" );
4534  NeedRIGHT();
4535  break;
4536 
4537  case T_priority:
4538  zone->SetPriority( parseInt( "zone priority" ) );
4539  NeedRIGHT();
4540  break;
4541 
4542  case T_connect_pads:
4543  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4544  {
4545  if( token == T_LEFT )
4546  token = NextTok();
4547 
4548  switch( token )
4549  {
4550  case T_yes:
4551  zone->SetPadConnection( ZONE_CONNECTION::FULL );
4552  break;
4553 
4554  case T_no:
4555  zone->SetPadConnection( ZONE_CONNECTION::NONE );
4556  break;
4557 
4558  case T_thru_hole_only:
4559  zone->SetPadConnection( ZONE_CONNECTION::THT_THERMAL );
4560  break;
4561 
4562  case T_clearance:
4563  zone->SetLocalClearance( parseBoardUnits( "zone clearance" ) );