KiCad PCB EDA Suite
PCB_PARSER Class Reference

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

#include <pcb_parser.h>

Inheritance diagram for PCB_PARSER:

Classes

struct  GROUP_INFO
 

Public Member Functions

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

Private Types

typedef std::unordered_map< std::string, PCB_LAYER_IDLAYER_ID_MAP
 
typedef std::unordered_map< std::string, LSETLSET_MAP
 
typedef std::unordered_map< wxString, KIIDKIID_MAP
 The type of progress bar timeout. More...
 
using TIMEOUT = std::chrono::milliseconds
 The clock used for the timestamp (guaranteed to be monotonic). More...
 
using CLOCK = std::chrono::steady_clock
 The type of the time stamps. More...
 
using TIME_PT = std::chrono::time_point< CLOCK >
 

Private Member Functions

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

Private Attributes

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

Detailed Description

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

Definition at line 72 of file pcb_parser.h.

Member Typedef Documentation

◆ CLOCK

using PCB_PARSER::CLOCK = std::chrono::steady_clock
private

The type of the time stamps.

Definition at line 374 of file pcb_parser.h.

◆ KIID_MAP

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

The type of progress bar timeout.

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

◆ LSET_MAP

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

Definition at line 365 of file pcb_parser.h.

◆ TIME_PT

using PCB_PARSER::TIME_PT = std::chrono::time_point<CLOCK>
private

Definition at line 375 of file pcb_parser.h.

◆ TIMEOUT

using PCB_PARSER::TIMEOUT = std::chrono::milliseconds
private

The clock used for the timestamp (guaranteed to be monotonic).

Definition at line 371 of file pcb_parser.h.

Constructor & Destructor Documentation

◆ PCB_PARSER()

PCB_PARSER::PCB_PARSER ( LINE_READER aReader = nullptr)
inline

Definition at line 75 of file pcb_parser.h.

75  :
76  PCB_LEXER( aReader ),
77  m_board( nullptr ),
78  m_resetKIIDs( false ),
79  m_progressReporter( nullptr ),
80  m_lineReader( nullptr ),
81  m_lastProgressTime( std::chrono::steady_clock::now() ),
82  m_lineCount( 0 )
83  {
84  init();
85  }
unsigned m_lineCount
for progress reporting
Definition: pcb_parser.h:394
const LINE_READER * m_lineReader
for progress reporting
Definition: pcb_parser.h:392
PROGRESS_REPORTER * m_progressReporter
optional; may be nullptr
Definition: pcb_parser.h:391
TIME_PT m_lastProgressTime
for progress reporting
Definition: pcb_parser.h:393
BOARD * m_board
Definition: pcb_parser.h:377
void init()
Clear and re-establish m_layerMap with the default layer names.
Definition: pcb_parser.cpp:67
bool m_resetKIIDs
reading into an existing board; reset UUIDs
Definition: pcb_parser.h:384

References init().

Member Function Documentation

◆ checkpoint()

void PCB_PARSER::checkpoint ( )
private

Definition at line 112 of file pcb_parser.cpp.

113 {
114  if( m_progressReporter )
115  {
116  TIME_PT curTime = CLOCK::now();
117  unsigned curLine = m_lineReader->LineNumber();
118  auto delta = std::chrono::duration_cast<TIMEOUT>( curTime - m_lastProgressTime );
119 
120  if( delta > std::chrono::milliseconds( 100 ) )
121  {
122  m_progressReporter->SetCurrentProgress( ( (double) curLine )
123  / std::max( 1U, m_lineCount ) );
124 
126  THROW_IO_ERROR( ( "Open cancelled by user." ) );
127 
128  m_lastProgressTime = curTime;
129  }
130  }
131 }
unsigned m_lineCount
for progress reporting
Definition: pcb_parser.h:394
std::chrono::time_point< CLOCK > TIME_PT
const LINE_READER * m_lineReader
for progress reporting
Definition: pcb_parser.h:392
PROGRESS_REPORTER * m_progressReporter
optional; may be nullptr
Definition: pcb_parser.h:391
TIME_PT m_lastProgressTime
for progress reporting
Definition: pcb_parser.h:393
virtual unsigned LineNumber() const
Return the line number of the last line read from this LINE_READER.
Definition: richio.h:135
constexpr int delta
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
virtual void SetCurrentProgress(double aProgress)=0
Set the progress value to aProgress (0..1).

References delta, and THROW_IO_ERROR.

◆ createOldLayerMapping()

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

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

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

Definition at line 1536 of file pcb_parser.cpp.

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

◆ CurStrToKIID()

KIID PCB_PARSER::CurStrToKIID ( )
private

Definition at line 5551 of file pcb_parser.cpp.

5552 {
5553  KIID aId;
5554 
5555  if( m_resetKIIDs )
5556  {
5557  aId = KIID();
5558  m_resetKIIDMap.insert( std::make_pair( CurStr(), aId ) );
5559  }
5560  else
5561  {
5562  aId = KIID( CurStr() );
5563  }
5564 
5565  return aId;
5566 }
KIID_MAP m_resetKIIDMap
Definition: pcb_parser.h:387
Definition: kiid.h:44
bool m_resetKIIDs
reading into an existing board; reset UUIDs
Definition: pcb_parser.h:384

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

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

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

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

References _, and THROW_PARSE_ERROR.

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

◆ init()

void PCB_PARSER::init ( )
private

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

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

Definition at line 67 of file pcb_parser.cpp.

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

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

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

References m_tooRecent.

Referenced by PCB_PLUGIN::DoLoad(), CLIPBOARD_IO::Load(), and PCB_PLUGIN::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 1718 of file pcb_parser.cpp.

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

References Rescue.

◆ Parse()

BOARD_ITEM * PCB_PARSER::Parse ( )

Definition at line 627 of file pcb_parser.cpp.

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

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

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

◆ parse3DModel()

FP_3DMODEL * PCB_PARSER::parse3DModel ( )
private

Definition at line 521 of file pcb_parser.cpp.

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

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

◆ parseAngle() [1/2]

double PCB_PARSER::parseAngle ( )
inlineprivate

Parse angles into deci-degrees.

Definition at line 318 of file pcb_parser.h.

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

References parseDouble().

◆ parseAngle() [2/2]

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

Definition at line 320 of file pcb_parser.h.

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

References parseDouble().

◆ parseARC()

PCB_ARC * PCB_PARSER::parseARC ( )
private

Definition at line 4627 of file pcb_parser.cpp.

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

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

◆ parseBOARD()

BOARD * PCB_PARSER::parseBOARD ( )
private

Definition at line 677 of file pcb_parser.cpp.

678 {
679  try
680  {
681  return parseBOARD_unchecked();
682  }
683  catch( const PARSE_ERROR& parse_error )
684  {
685  if( m_tooRecent )
686  throw FUTURE_FORMAT_ERROR( parse_error, GetRequiredVersion() );
687  else
688  throw;
689  }
690 }
bool m_tooRecent
true if version parses as later than supported
Definition: pcb_parser.h:382
wxString GetRequiredVersion()
Return a string representing the version of KiCad required to open this file.
Definition: pcb_parser.cpp:247
BOARD * parseBOARD_unchecked()
Definition: pcb_parser.cpp:693
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 693 of file pcb_parser.cpp.

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

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

◆ parseBoardItemLayer()

PCB_LAYER_ID PCB_PARSER::parseBoardItemLayer ( )
private

Parse the layer definition of a BOARD_ITEM object.

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

Definition at line 1737 of file pcb_parser.cpp.

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

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

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

◆ parseBoardStackup()

void PCB_PARSER::parseBoardStackup ( )
private

Definition at line 1315 of file pcb_parser.cpp.

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

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

◆ parseBoardUnits() [1/3]

int PCB_PARSER::parseBoardUnits ( )
private

Definition at line 197 of file pcb_parser.cpp.

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

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

Referenced by parseBoardUnits().

◆ parseBoardUnits() [2/3]

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

Definition at line 217 of file pcb_parser.cpp.

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

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

◆ parseBoardUnits() [3/3]

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

Definition at line 329 of file pcb_parser.h.

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

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

◆ parseBool()

bool PCB_PARSER::parseBool ( )
private

Definition at line 232 of file pcb_parser.cpp.

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

◆ parseDefaults()

void PCB_PARSER::parseDefaults ( BOARD_DESIGN_SETTINGS aSettings)
private

Definition at line 2119 of file pcb_parser.cpp.

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

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

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

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

◆ parseDIMENSION()

PCB_DIMENSION_BASE * PCB_PARSER::parseDIMENSION ( )
private

Definition at line 2795 of file pcb_parser.cpp.

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

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

◆ parseDouble() [1/3]

double PCB_PARSER::parseDouble ( )
private

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

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

Definition at line 167 of file pcb_parser.cpp.

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

References _, and THROW_IO_ERROR.

Referenced by parseAngle(), and parseDouble().

◆ parseDouble() [2/3]

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

Definition at line 304 of file pcb_parser.h.

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

References parseDouble().

◆ parseDouble() [3/3]

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

Definition at line 310 of file pcb_parser.h.

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

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

◆ parseEDA_TEXT()

void PCB_PARSER::parseEDA_TEXT ( EDA_TEXT aText)
private

Parse the common settings for any object derived from EDA_TEXT.

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

Definition at line 403 of file pcb_parser.cpp.

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

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

◆ parseFOOTPRINT()

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

Definition at line 3207 of file pcb_parser.cpp.

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

◆ parseFOOTPRINT_unchecked()

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

Definition at line 3223 of file pcb_parser.cpp.

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

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

◆ parseFP_SHAPE()

FP_SHAPE * PCB_PARSER::parseFP_SHAPE ( )
private

Definition at line 3653 of file pcb_parser.cpp.

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

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

◆ parseFP_TEXT()

FP_TEXT * PCB_PARSER::parseFP_TEXT ( )
private

Definition at line 3544 of file pcb_parser.cpp.

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

References _, DSN_NUMBER, Format(), text, FP_TEXT::TEXT_is_REFERENCE, FP_TEXT::TEXT_is_VALUE, and THROW_IO_ERROR.

◆ parseGeneralSection()

void PCB_PARSER::parseGeneralSection ( )
private

Definition at line 1060 of file pcb_parser.cpp.

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

◆ parseGROUP()

void PCB_PARSER::parseGROUP ( BOARD_ITEM aParent)
private

Definition at line 4577 of file pcb_parser.cpp.

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

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

◆ parseHeader()

void PCB_PARSER::parseHeader ( )
private

Definition at line 1034 of file pcb_parser.cpp.

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

References parseInt(), and SEXPR_BOARD_FILE_VERSION.

◆ parseHex()

long PCB_PARSER::parseHex ( )
inlineprivate

Definition at line 345 of file pcb_parser.h.

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

◆ parseInt() [1/2]

int PCB_PARSER::parseInt ( )
inlineprivate

Definition at line 334 of file pcb_parser.h.

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

Referenced by parseInt().

◆ parseInt() [2/2]

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

Definition at line 339 of file pcb_parser.h.

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

References parseInt().

◆ parseLayer()

void PCB_PARSER::parseLayer ( LAYER aLayer)
private

Definition at line 1258 of file pcb_parser.cpp.

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

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

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

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

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

References _, ConvertToNewOverbarNotation(), and THROW_IO_ERROR.

◆ parseNETINFO_ITEM()

void PCB_PARSER::parseNETINFO_ITEM ( )
private

Definition at line 2239 of file pcb_parser.cpp.

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

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

◆ parseOutlinePoints()

void PCB_PARSER::parseOutlinePoints ( SHAPE_LINE_CHAIN aPoly)
private

Parses possible outline points and stores them into aPoly.

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

Parameters
aPolypolygon container to add points and arcs

Definition at line 291 of file pcb_parser.cpp.

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

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

◆ parsePAD()

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

Definition at line 4005 of file pcb_parser.cpp.

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

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

◆ parsePAD_option()

bool PCB_PARSER::parsePAD_option ( PAD aPad)
private

Definition at line 4505 of file pcb_parser.cpp.

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

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

◆ parsePAGE_INFO()

void PCB_PARSER::parsePAGE_INFO ( )
private

Definition at line 1093 of file pcb_parser.cpp.

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

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

◆ parsePCB_SHAPE()

PCB_SHAPE * PCB_PARSER::parsePCB_SHAPE ( )
private

Definition at line 2362 of file pcb_parser.cpp.

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

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

◆ parsePCB_TARGET()

PCB_TARGET * PCB_PARSER::parsePCB_TARGET ( )
private

Definition at line 5489 of file pcb_parser.cpp.

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

◆ parsePCB_TEXT()

PCB_TEXT * PCB_PARSER::parsePCB_TEXT ( )
private

Definition at line 2726 of file pcb_parser.cpp.

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

References text.

◆ parsePCB_TRACK()

PCB_TRACK * PCB_PARSER::parsePCB_TRACK ( )
private

Definition at line 4711 of file pcb_parser.cpp.

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

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

◆ parsePCB_VIA()

PCB_VIA * PCB_PARSER::parsePCB_VIA ( )
private

Definition at line 4789 of file pcb_parser.cpp.

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

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

◆ parseProperty()

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

Definition at line 388 of file pcb_parser.cpp.

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

◆ parseSetup()

void PCB_PARSER::parseSetup ( )
private

Definition at line 1770 of file pcb_parser.cpp.

1771 {
1772  wxCHECK_RET( CurTok() == T_setup,
1773  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as setup." ) );
1774 
1775  T token;
1776  NETCLASS* defaultNetClass = m_board->GetDesignSettings().GetDefault();
1777  BOARD_DESIGN_SETTINGS& designSettings = m_board->GetDesignSettings();
1778  ZONE_SETTINGS& zoneSettings = designSettings.GetDefaultZoneSettings();
1779 
1780  // Missing soldermask min width value means that the user has set the value to 0 and
1781  // not the default value (0.25mm)
1782  designSettings.m_SolderMaskMinWidth = 0;
1783 
1784  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1785  {
1786  if( token != T_LEFT )
1787  Expecting( T_LEFT );
1788 
1789  token = NextTok();
1790 
1791  switch( token )
1792  {
1793  case T_stackup:
1795  break;
1796 
1797  case T_last_trace_width: // not used now
1798  /* lastTraceWidth =*/ parseBoardUnits( T_last_trace_width );
1799  NeedRIGHT();
1800  break;
1801 
1802  case T_user_trace_width:
1803  {
1804  // Make room for the netclass value
1805  if( designSettings.m_TrackWidthList.empty() )
1806  designSettings.m_TrackWidthList.emplace_back( 0 );
1807 
1808  designSettings.m_TrackWidthList.push_back( parseBoardUnits( T_user_trace_width ) );
1810  NeedRIGHT();
1811  break;
1812  }
1813 
1814  case T_trace_clearance:
1815  defaultNetClass->SetClearance( parseBoardUnits( T_trace_clearance ) );
1817  NeedRIGHT();
1818  break;
1819 
1820  case T_zone_clearance:
1821  zoneSettings.m_ZoneClearance = parseBoardUnits( T_zone_clearance );
1823  NeedRIGHT();
1824  break;
1825 
1826  case T_zone_45_only:
1827  zoneSettings.m_Zone_45_Only = parseBool();
1829  NeedRIGHT();
1830  break;
1831 
1832  case T_clearance_min:
1833  designSettings.m_MinClearance = parseBoardUnits( T_clearance_min );
1835  NeedRIGHT();
1836  break;
1837 
1838  case T_trace_min:
1839  designSettings.m_TrackMinWidth = parseBoardUnits( T_trace_min );
1841  NeedRIGHT();
1842  break;
1843 
1844  case T_via_size:
1845  defaultNetClass->SetViaDiameter( parseBoardUnits( T_via_size ) );
1847  NeedRIGHT();
1848  break;
1849 
1850  case T_via_drill:
1851  defaultNetClass->SetViaDrill( parseBoardUnits( T_via_drill ) );
1853  NeedRIGHT();
1854  break;
1855 
1856  case T_via_min_annulus:
1857  designSettings.m_ViasMinAnnularWidth = parseBoardUnits( T_via_min_annulus );
1859  NeedRIGHT();
1860  break;
1861 
1862  case T_via_min_size:
1863  designSettings.m_ViasMinSize = parseBoardUnits( T_via_min_size );
1865  NeedRIGHT();
1866  break;
1867 
1868  case T_through_hole_min:
1869  designSettings.m_MinThroughDrill = parseBoardUnits( T_through_hole_min );
1871  NeedRIGHT();
1872  break;
1873 
1874  // Legacy token for T_through_hole_min
1875  case T_via_min_drill:
1876  designSettings.m_MinThroughDrill = parseBoardUnits( T_via_min_drill );
1878  NeedRIGHT();
1879  break;
1880 
1881  case T_hole_to_hole_min:
1882  designSettings.m_HoleToHoleMin = parseBoardUnits( T_hole_to_hole_min );
1884  NeedRIGHT();
1885  break;
1886 
1887  case T_user_via:
1888  {
1889  int viaSize = parseBoardUnits( "user via size" );
1890  int viaDrill = parseBoardUnits( "user via drill" );
1891 
1892  // Make room for the netclass value
1893  if( designSettings.m_ViasDimensionsList.empty() )
1894  designSettings.m_ViasDimensionsList.emplace_back( VIA_DIMENSION( 0, 0 ) );
1895 
1896  designSettings.m_ViasDimensionsList.emplace_back( VIA_DIMENSION( viaSize, viaDrill ) );
1898  NeedRIGHT();
1899  break;
1900  }
1901 
1902  case T_uvia_size:
1903  defaultNetClass->SetuViaDiameter( parseBoardUnits( T_uvia_size ) );
1905  NeedRIGHT();
1906  break;
1907 
1908  case T_uvia_drill:
1909  defaultNetClass->SetuViaDrill( parseBoardUnits( T_uvia_drill ) );
1911  NeedRIGHT();
1912  break;
1913 
1914  case T_uvias_allowed:
1915  designSettings.m_MicroViasAllowed = parseBool();
1917  NeedRIGHT();
1918  break;
1919 
1920  case T_blind_buried_vias_allowed:
1921  designSettings.m_BlindBuriedViaAllowed = parseBool();
1923  NeedRIGHT();
1924  break;
1925 
1926  case T_uvia_min_size:
1927  designSettings.m_MicroViasMinSize = parseBoardUnits( T_uvia_min_size );
1929  NeedRIGHT();
1930  break;
1931 
1932  case T_uvia_min_drill:
1933  designSettings.m_MicroViasMinDrill = parseBoardUnits( T_uvia_min_drill );
1935  NeedRIGHT();
1936  break;
1937 
1938  case T_user_diff_pair:
1939  {
1940  int width = parseBoardUnits( "user diff-pair width" );
1941  int gap = parseBoardUnits( "user diff-pair gap" );
1942  int viaGap = parseBoardUnits( "user diff-pair via gap" );
1943  designSettings.m_DiffPairDimensionsList.emplace_back(
1944  DIFF_PAIR_DIMENSION( width, gap, viaGap ) );
1946  NeedRIGHT();
1947  }
1948 
1949  break;
1950 
1951  case T_segment_width: // note: legacy (pre-6.0) token
1952  designSettings.m_LineThickness[ LAYER_CLASS_COPPER ] =
1953  parseBoardUnits( T_segment_width );
1955  NeedRIGHT();
1956  break;
1957 
1958  case T_edge_width: // note: legacy (pre-6.0) token
1959  designSettings.m_LineThickness[ LAYER_CLASS_EDGES ] = parseBoardUnits( T_edge_width );
1961  NeedRIGHT();
1962  break;
1963 
1964  case T_mod_edge_width: // note: legacy (pre-6.0) token
1965  designSettings.m_LineThickness[ LAYER_CLASS_SILK ] =
1966  parseBoardUnits( T_mod_edge_width );
1968  NeedRIGHT();
1969  break;
1970 
1971  case T_pcb_text_width: // note: legacy (pre-6.0) token
1972  designSettings.m_TextThickness[ LAYER_CLASS_COPPER ] =
1973  parseBoardUnits( T_pcb_text_width );
1975  NeedRIGHT();
1976  break;
1977 
1978  case T_mod_text_width: // note: legacy (pre-6.0) token
1979  designSettings.m_TextThickness[ LAYER_CLASS_SILK ] =
1980  parseBoardUnits( T_mod_text_width );
1982  NeedRIGHT();
1983  break;
1984 
1985  case T_pcb_text_size: // note: legacy (pre-6.0) token
1986  designSettings.m_TextSize[ LAYER_CLASS_COPPER ].x = parseBoardUnits( "pcb text width" );
1987  designSettings.m_TextSize[ LAYER_CLASS_COPPER ].y =
1988  parseBoardUnits( "pcb text height" );
1990  NeedRIGHT();
1991  break;
1992 
1993  case T_mod_text_size: // note: legacy (pre-6.0) token
1994  designSettings.m_TextSize[ LAYER_CLASS_SILK ].x =
1995  parseBoardUnits( "footprint text width" );
1996  designSettings.m_TextSize[ LAYER_CLASS_SILK ].y =
1997  parseBoardUnits( "footprint text height" );
1999  NeedRIGHT();
2000  break;
2001 
2002  case T_defaults:
2003  parseDefaults( designSettings );
2005  break;
2006 
2007  case T_pad_size:
2008  {
2009  wxSize sz;
2010  sz.SetWidth( parseBoardUnits( "master pad width" ) );
2011  sz.SetHeight( parseBoardUnits( "master pad height" ) );
2012  designSettings.m_Pad_Master->SetSize( sz );
2014  NeedRIGHT();
2015  break;
2016  }
2017 
2018  case T_pad_drill:
2019  {
2020  int drillSize = parseBoardUnits( T_pad_drill );
2021  designSettings.m_Pad_Master->SetDrillSize( wxSize( drillSize, drillSize ) );
2023  NeedRIGHT();
2024  break;
2025  }
2026 
2027  case T_pad_to_mask_clearance:
2028  designSettings.m_SolderMaskMargin = parseBoardUnits( T_pad_to_mask_clearance );
2029  NeedRIGHT();
2030  break;
2031 
2032  case T_solder_mask_min_width:
2033  designSettings.m_SolderMaskMinWidth = parseBoardUnits( T_solder_mask_min_width );
2034  NeedRIGHT();
2035  break;
2036 
2037  case T_pad_to_paste_clearance:
2038  designSettings.m_SolderPasteMargin = parseBoardUnits( T_pad_to_paste_clearance );
2039  NeedRIGHT();
2040  break;
2041 
2042  case T_pad_to_paste_clearance_ratio:
2043  designSettings.m_SolderPasteMarginRatio = parseDouble( T_pad_to_paste_clearance_ratio );
2044  NeedRIGHT();
2045  break;
2046 
2047  case T_aux_axis_origin:
2048  {
2049  int x = parseBoardUnits( "auxiliary origin X" );
2050  int y = parseBoardUnits( "auxiliary origin Y" );
2051  designSettings.SetAuxOrigin( wxPoint( x, y ) );
2052 
2053  // Aux origin still stored in board for the moment
2054  //m_board->m_LegacyDesignSettingsLoaded = true;
2055  NeedRIGHT();
2056  break;
2057  }
2058 
2059  case T_grid_origin:
2060  {
2061  int x = parseBoardUnits( "grid origin X" );
2062  int y = parseBoardUnits( "grid origin Y" );
2063  designSettings.SetGridOrigin( wxPoint( x, y ) );
2064  // Grid origin still stored in board for the moment
2065  //m_board->m_LegacyDesignSettingsLoaded = true;
2066  NeedRIGHT();
2067  break;
2068  }
2069 
2070  // Stored in board prior to 6.0
2071  case T_visible_elements:
2072  {
2073  // Make sure to start with DefaultVisible so all new layers are set
2075 
2076  int visible = parseHex() | MIN_VISIBILITY_MASK;
2077 
2078  for( size_t i = 0; i < sizeof( int ) * CHAR_BIT; i++ )
2079  m_board->m_LegacyVisibleItems.set( i, visible & ( 1u << i ) );
2080 
2081  NeedRIGHT();
2082  break;
2083  }
2084 
2085  case T_max_error:
2086  designSettings.m_MaxError = parseBoardUnits( T_max_error );
2088  NeedRIGHT();
2089  break;
2090 
2091  case T_filled_areas_thickness: // Note: legacy (early 5.99) token
2092  designSettings.m_ZoneFillVersion = parseBool() ? 5 : 6;
2094  NeedRIGHT();
2095  break;
2096 
2097  case T_pcbplotparams:
2098  {
2099  PCB_PLOT_PARAMS plotParams;
2100  PCB_PLOT_PARAMS_PARSER parser( reader );
2101  // parser must share the same current line as our current PCB parser
2102  // synchronize it.
2103  parser.SyncLineReaderWith( *this );
2104 
2105  plotParams.Parse( &parser );
2106  SyncLineReaderWith( parser );
2107 
2108  m_board->SetPlotOptions( plotParams );
2109  break;
2110  }
2111 
2112  default:
2113  Unexpected( CurText() );
2114  }
2115  }
2116 }
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.
bool m_LegacyDesignSettingsLoaded
True if the legacy board design settings were loaded from a file.
Definition: board.h:269
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.cpp:590
Container to handle a stock of specific differential pairs each with unique track width,...
std::unique_ptr< PAD > m_Pad_Master
void SetViaDrill(int aSize)
Definition: netclass.h:137
int parseBoardUnits()
Definition: pcb_parser.cpp:197
wxSize m_TextSize[LAYER_CLASS_COUNT]
bool parseBool()
Definition: pcb_parser.cpp:232
int m_TextThickness[LAYER_CLASS_COUNT]
void SetAuxOrigin(const wxPoint &aOrigin)
void SetClearance(int aClearance)
Definition: netclass.h:125
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:942
bool m_BlindBuriedViaAllowed
true to allow blind/buried vias
void SetPlotOptions(const PCB_PLOT_PARAMS &aOptions)
Definition: board.h:540
void SetuViaDiameter(int aSize)
Definition: netclass.h:141
#define MIN_VISIBILITY_MASK
Definition: layer_ids.h:450
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:377
NETCLASS * GetDefault() const
void SetGridOrigin(const wxPoint &aOrigin)
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:167
void SetViaDiameter(int aDia)
Definition: netclass.h:133
GAL_SET & set()
Definition: layer_ids.h:306
ZONE_SETTINGS & GetDefaultZoneSettings()
bool m_MicroViasAllowed
true to allow micro vias
long parseHex()
Definition: pcb_parser.h:345
void Parse(PCB_PLOT_PARAMS_PARSER *aParser)
Container for design settings for a BOARD object.
GAL_SET m_LegacyVisibleItems
Definition: board.h:266

References GAL_SET::DefaultVisible(), BOARD_DESIGN_SETTINGS::GetDefaultZoneSettings(), LAYER_CLASS_COPPER, LAYER_CLASS_EDGES, LAYER_CLASS_SILK, BOARD_DE