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, BOARD *aAppendToMe, std::function< bool(wxString, int, wxString, wxString)> *aQueryUserCallback, PROGRESS_REPORTER *aProgressReporter=nullptr, unsigned aLineCount=0)
 
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 it's 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_BITMAPparsePCB_BITMAP (BOARD_ITEM *aParent)
 
PCB_TEXTBOXparsePCB_TEXTBOX ()
 
PCB_DIMENSION_BASEparseDIMENSION (BOARD_ITEM *aParent, bool aInFP)
 
FOOTPRINTparseFOOTPRINT_unchecked (wxArrayString *aInitialComments=nullptr)
 
FP_TEXTparseFP_TEXT ()
 
FP_TEXTBOXparseFP_TEXTBOX ()
 
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...
 
VECTOR2I 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...
 
void parseRenderCache (EDA_TEXT *text)
 Parse the render cache for any object derived from EDA_TEXT. More...
 
FP_3DMODELparse3DModel ()
 
int parseBoardUnits ()
 Parse the current token as an ASCII numeric string with possible leading whitespace into a double precision floating point number. More...
 
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_appendToExisting
 reading into an existing board; reset UUIDs More...
 
KIID_MAP m_resetKIIDMap
 
bool m_showLegacySegmentZoneWarning
 
bool m_showLegacy5ZoneWarning
 
PROGRESS_REPORTERm_progressReporter
 optional; may be nullptr More...
 
TIME_PT m_lastProgressTime
 for progress reporting More...
 
unsigned m_lineCount
 for progress reporting More...
 
std::vector< GROUP_INFOm_groupInfos
 
std::function< bool(wxString aTitle, int aIcon, wxString aMsg, wxString aAction)> * m_queryUserCallback
 

Detailed Description

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

Definition at line 73 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 333 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 327 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 325 of file pcb_parser.h.

◆ LSET_MAP

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

Definition at line 326 of file pcb_parser.h.

◆ TIME_PT

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

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

Constructor & Destructor Documentation

◆ PCB_PARSER()

PCB_PARSER::PCB_PARSER ( LINE_READER aReader,
BOARD aAppendToMe,
std::function< bool(wxString, int, wxString, wxString)> *  aQueryUserCallback,
PROGRESS_REPORTER aProgressReporter = nullptr,
unsigned  aLineCount = 0 
)
inline

Definition at line 76 of file pcb_parser.h.

78 :
79 PCB_LEXER( aReader ),
80 m_board( aAppendToMe ),
81 m_appendToExisting( aAppendToMe != nullptr ),
82 m_progressReporter( aProgressReporter ),
83 m_lastProgressTime( std::chrono::steady_clock::now() ),
84 m_lineCount( aLineCount ),
85 m_queryUserCallback( aQueryUserCallback )
86 {
87 init();
88 }
void init()
Clear and re-establish m_layerMap with the default layer names.
Definition: pcb_parser.cpp:77
TIME_PT m_lastProgressTime
for progress reporting
Definition: pcb_parser.h:354
bool m_appendToExisting
reading into an existing board; reset UUIDs
Definition: pcb_parser.h:345
std::function< bool(wxString aTitle, int aIcon, wxString aMsg, wxString aAction)> * m_queryUserCallback
Definition: pcb_parser.h:372
PROGRESS_REPORTER * m_progressReporter
optional; may be nullptr
Definition: pcb_parser.h:353
BOARD * m_board
Definition: pcb_parser.h:338
unsigned m_lineCount
for progress reporting
Definition: pcb_parser.h:355

References init().

Member Function Documentation

◆ checkpoint()

void PCB_PARSER::checkpoint ( )
private

Definition at line 123 of file pcb_parser.cpp.

124{
126 {
127 TIME_PT curTime = CLOCK::now();
128 unsigned curLine = reader->LineNumber();
129 auto delta = std::chrono::duration_cast<TIMEOUT>( curTime - m_lastProgressTime );
130
131 if( delta > std::chrono::milliseconds( 250 ) )
132 {
133 m_progressReporter->SetCurrentProgress( ( (double) curLine )
134 / std::max( 1U, m_lineCount ) );
135
137 THROW_IO_ERROR( ( "Open cancelled by user." ) );
138
139 m_lastProgressTime = curTime;
140 }
141 }
142}
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
virtual void SetCurrentProgress(double aProgress)=0
Set the progress value to aProgress (0..1).
std::chrono::time_point< CLOCK > TIME_PT
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
constexpr int delta

References delta, PROGRESS_REPORTER::KeepRefreshing(), m_lastProgressTime, m_lineCount, m_progressReporter, PROGRESS_REPORTER::SetCurrentProgress(), and THROW_IO_ERROR.

Referenced by parseBOARD_unchecked().

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

1605{
1606 // N.B. This mapping only includes Italian, Polish and French as they were the only languages
1607 // that mapped the layer names as of cc2022b1ac739aa673d2a0b7a2047638aa7a47b3 (kicad-i18n)
1608 // when the bug was fixed in KiCad source.
1609
1610 // Italian
1611 aMap["Adesivo.Retro"] = "B.Adhes";
1612 aMap["Adesivo.Fronte"] = "F.Adhes";
1613 aMap["Pasta.Retro"] = "B.Paste";
1614 aMap["Pasta.Fronte"] = "F.Paste";
1615 aMap["Serigrafia.Retro"] = "B.SilkS";
1616 aMap["Serigrafia.Fronte"] = "F.SilkS";
1617 aMap["Maschera.Retro"] = "B.Mask";
1618 aMap["Maschera.Fronte"] = "F.Mask";
1619 aMap["Grafica"] = "Dwgs.User";
1620 aMap["Commenti"] = "Cmts.User";
1621 aMap["Eco1"] = "Eco1.User";
1622 aMap["Eco2"] = "Eco2.User";
1623 aMap["Contorno.scheda"] = "Edge.Cuts";
1624
1625 // Polish
1626 aMap["Kleju_Dolna"] = "B.Adhes";
1627 aMap["Kleju_Gorna"] = "F.Adhes";
1628 aMap["Pasty_Dolna"] = "B.Paste";
1629 aMap["Pasty_Gorna"] = "F.Paste";
1630 aMap["Opisowa_Dolna"] = "B.SilkS";
1631 aMap["Opisowa_Gorna"] = "F.SilkS";
1632 aMap["Maski_Dolna"] = "B.Mask";
1633 aMap["Maski_Gorna"] = "F.Mask";
1634 aMap["Rysunkowa"] = "Dwgs.User";
1635 aMap["Komentarzy"] = "Cmts.User";
1636 aMap["ECO1"] = "Eco1.User";
1637 aMap["ECO2"] = "Eco2.User";
1638 aMap["Krawedziowa"] = "Edge.Cuts";
1639
1640 // French
1641 aMap["Dessous.Adhes"] = "B.Adhes";
1642 aMap["Dessus.Adhes"] = "F.Adhes";
1643 aMap["Dessous.Pate"] = "B.Paste";
1644 aMap["Dessus.Pate"] = "F.Paste";
1645 aMap["Dessous.SilkS"] = "B.SilkS";
1646 aMap["Dessus.SilkS"] = "F.SilkS";
1647 aMap["Dessous.Masque"] = "B.Mask";
1648 aMap["Dessus.Masque"] = "F.Mask";
1649 aMap["Dessin.User"] = "Dwgs.User";
1650 aMap["Contours.Ci"] = "Edge.Cuts";
1651}

Referenced by parseLayers().

◆ CurStrToKIID()

KIID PCB_PARSER::CurStrToKIID ( )
private

Definition at line 6212 of file pcb_parser.cpp.

6213{
6214 KIID aId;
6215
6216 if( m_appendToExisting )
6217 {
6218 aId = KIID();
6219 m_resetKIIDMap.insert( std::make_pair( CurStr(), aId ) );
6220 }
6221 else
6222 {
6223 aId = KIID( CurStr() );
6224 }
6225
6226 return aId;
6227}
Definition: kiid.h:48
KIID_MAP m_resetKIIDMap
Definition: pcb_parser.h:348

References m_appendToExisting, and m_resetKIIDMap.

Referenced by parseARC(), parseDIMENSION(), parseFOOTPRINT_unchecked(), parseFP_SHAPE(), parseFP_TEXT(), parseFP_TEXTBOX(), parseGROUP(), parsePAD(), parsePCB_SHAPE(), parsePCB_TARGET(), parsePCB_TEXT(), parsePCB_TEXTBOX(), parsePCB_TRACK(), parsePCB_VIA(), and parseZONE().

◆ 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 it's out of range

Definition at line 119 of file pcb_parser.h.

120 {
121 if( ( aNetCode >= 0 ) && ( aNetCode < (int) m_netCodes.size() ) )
122 return m_netCodes[aNetCode];
123
124 return aNetCode;
125 }
std::vector< int > m_netCodes
net codes mapping for boards being loaded
Definition: pcb_parser.h:342

References m_netCodes.

Referenced by parseARC(), parsePAD(), parsePCB_TRACK(), parsePCB_VIA(), and parseZONE().

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

229{
230 int year, month, day;
231
232 year = m_requiredVersion / 10000;
233 month = ( m_requiredVersion / 100 ) - ( year * 100 );
234 day = m_requiredVersion - ( year * 10000 ) - ( month * 100 );
235
236 // wx throws an assertion, not a catchable exception, when the date is invalid.
237 // User input shouldn't give wx asserts, so check manually and throw a proper
238 // error instead
239 if( day <= 0 || month <= 0 || month > 12 ||
240 day > wxDateTime::GetNumberOfDays( (wxDateTime::Month)( month - 1 ), year ) )
241 {
242 wxString err;
243 err.Printf( _( "Cannot interpret date code %d" ), m_requiredVersion );
244 THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
245 }
246
247 wxDateTime date( day, (wxDateTime::Month)( month - 1 ), year, 0, 0, 0, 0 );
248 return date.FormatDate();
249}
int m_requiredVersion
set to the KiCad format version this board requires
Definition: pcb_parser.h:344
#define _(s)
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:164

References _, m_requiredVersion, and THROW_PARSE_ERROR.

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

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

78{
81 m_tooRecent = false;
83 m_layerIndices.clear();
84 m_layerMasks.clear();
85 m_resetKIIDMap.clear();
86
87 // Add untranslated default (i.e. English) layernames.
88 // Some may be overridden later if parsing a board rather than a footprint.
89 // The English name will survive if parsing only a footprint.
90 for( int layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer )
91 {
92 std::string untranslated = TO_UTF8( wxString( LSET::Name( PCB_LAYER_ID( layer ) ) ) );
93
94 m_layerIndices[ untranslated ] = PCB_LAYER_ID( layer );
95 m_layerMasks[ untranslated ] = LSET( PCB_LAYER_ID( layer ) );
96 }
97
98 m_layerMasks[ "*.Cu" ] = LSET::AllCuMask();
99 m_layerMasks[ "*In.Cu" ] = LSET::InternalCuMask();
100 m_layerMasks[ "F&B.Cu" ] = LSET( 2, F_Cu, B_Cu );
101 m_layerMasks[ "*.Adhes" ] = LSET( 2, B_Adhes, F_Adhes );
102 m_layerMasks[ "*.Paste" ] = LSET( 2, B_Paste, F_Paste );
103 m_layerMasks[ "*.Mask" ] = LSET( 2, B_Mask, F_Mask );
104 m_layerMasks[ "*.SilkS" ] = LSET( 2, B_SilkS, F_SilkS );
105 m_layerMasks[ "*.Fab" ] = LSET( 2, B_Fab, F_Fab );
106 m_layerMasks[ "*.CrtYd" ] = LSET( 2, B_CrtYd, F_CrtYd );
107
108 // This is for the first pretty & *.kicad_pcb formats, which had
109 // Inner1_Cu - Inner14_Cu with the numbering sequence
110 // reversed from the subsequent format's In1_Cu - In30_Cu numbering scheme.
111 // The newer format brought in an additional 16 Cu layers and flipped the cu stack but
112 // kept the gap between one of the outside layers and the last cu internal.
113
114 for( int i=1; i<=14; ++i )
115 {
116 std::string key = StrPrintf( "Inner%d.Cu", i );
117
118 m_layerMasks[ key ] = LSET( PCB_LAYER_ID( In15_Cu - i ) );
119 }
120}
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:530
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:733
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:773
static const wxChar * Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition: lset.cpp:82
LSET_MAP m_layerMasks
map layer names to their masks
Definition: pcb_parser.h:340
bool m_tooRecent
true if version parses as later than supported
Definition: pcb_parser.h:343
bool m_showLegacySegmentZoneWarning
Definition: pcb_parser.h:350
bool m_showLegacy5ZoneWarning
Definition: pcb_parser.h:351
LAYER_ID_MAP m_layerIndices
map layer name to it's index
Definition: pcb_parser.h:339
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:59
@ F_CrtYd
Definition: layer_ids.h:117
@ B_Adhes
Definition: layer_ids.h:97
@ F_Paste
Definition: layer_ids.h:101
@ F_Adhes
Definition: layer_ids.h:98
@ B_Mask
Definition: layer_ids.h:106
@ B_Cu
Definition: layer_ids.h:95
@ F_Mask
Definition: layer_ids.h:107
@ B_Paste
Definition: layer_ids.h:100
@ In15_Cu
Definition: layer_ids.h:79
@ F_Fab
Definition: layer_ids.h:120
@ F_SilkS
Definition: layer_ids.h:104
@ B_CrtYd
Definition: layer_ids.h:116
@ B_SilkS
Definition: layer_ids.h:103
@ PCB_LAYER_ID_COUNT
Definition: layer_ids.h:137
@ F_Cu
Definition: layer_ids.h:64
@ B_Fab
Definition: layer_ids.h:119
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:96
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:84

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(), m_layerIndices, m_layerMasks, m_requiredVersion, m_resetKIIDMap, m_showLegacy5ZoneWarning, m_showLegacySegmentZoneWarning, m_tooRecent, LSET::Name(), PCB_LAYER_ID_COUNT, StrPrintf(), and TO_UTF8.

Referenced by PCB_PARSER().

◆ IsTooRecent()

bool PCB_PARSER::IsTooRecent ( )
inline

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

Definition at line 105 of file pcb_parser.h.

106 {
107 return m_tooRecent;
108 }

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

1787{
1788 // avoid constructing another std::string, use lexer's directly
1789 typename M::const_iterator it = aMap.find( curText );
1790
1791 if( it == aMap.end() )
1792 {
1793 m_undefinedLayers.insert( curText );
1794 return Rescue;
1795 }
1796
1797 // Some files may have saved items to the Rescue Layer due to an issue in v5
1798 if( it->second == Rescue )
1799 m_undefinedLayers.insert( curText );
1800
1801 return it->second;
1802}
std::set< wxString > m_undefinedLayers
set of layers not defined in layers section
Definition: pcb_parser.h:341
@ Rescue
Definition: layer_ids.h:133

References m_undefinedLayers, and Rescue.

◆ Parse()

BOARD_ITEM * PCB_PARSER::Parse ( )

Definition at line 681 of file pcb_parser.cpp.

682{
683 T token;
684 BOARD_ITEM* item;
685 LOCALE_IO toggle;
686
687 m_groupInfos.clear();
688
689 // FOOTPRINTS can be prefixed with an initial block of single line comments and these are
690 // kept for Format() so they round trip in s-expression form. BOARDs might eventually do
691 // the same, but currently do not.
692 std::unique_ptr<wxArrayString> initial_comments( ReadCommentLines() );
693
694 token = CurTok();
695
696 if( token == -1 ) // EOF
697 Unexpected( token );
698
699 if( token != T_LEFT )
700 Expecting( T_LEFT );
701
702 switch( NextTok() )
703 {
704 case T_kicad_pcb:
705 if( m_board == nullptr )
706 m_board = new BOARD();
707
708 item = (BOARD_ITEM*) parseBOARD();
709 break;
710
711 case T_module: // legacy token
712 case T_footprint:
713 item = (BOARD_ITEM*) parseFOOTPRINT( initial_comments.release() );
714
715 // Locking a footprint has no meaning outside of a board.
716 item->SetLocked( false );
717 break;
718
719 default:
720 wxString err;
721 err.Printf( _( "Unknown token '%s'" ), FromUTF8() );
722 THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
723 }
724
725 resolveGroups( item );
726
727 return item;
728}
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:70
virtual void SetLocked(bool aLocked)
Definition: board_item.h:266
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:265
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:41
std::vector< GROUP_INFO > m_groupInfos
Definition: pcb_parser.h:370
BOARD * parseBOARD()
Definition: pcb_parser.cpp:731
FOOTPRINT * parseFOOTPRINT(wxArrayString *aInitialComments=nullptr)
void resolveGroups(BOARD_ITEM *aParent)
Called after parsing a footprint definition or board to build the group membership lists.

References _, m_board, m_groupInfos, parseBOARD(), parseFOOTPRINT(), resolveGroups(), BOARD_ITEM::SetLocked(), and THROW_PARSE_ERROR.

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

◆ parse3DModel()

FP_3DMODEL * PCB_PARSER::parse3DModel ( )
private

Definition at line 575 of file pcb_parser.cpp.

576{
577 wxCHECK_MSG( CurTok() == T_model, nullptr,
578 wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as FP_3DMODEL." ) );
579
580 T token;
581
582 FP_3DMODEL* n3D = new FP_3DMODEL;
583 NeedSYMBOLorNUMBER();
584 n3D->m_Filename = FromUTF8();
585
586 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
587 {
588 if( token == T_LEFT )
589 token = NextTok();
590
591 switch( token )
592 {
593 case T_at:
594 NeedLEFT();
595 token = NextTok();
596
597 if( token != T_xyz )
598 Expecting( T_xyz );
599
600 /* Note:
601 * Prior to KiCad v5, model offset was designated by "at",
602 * and the units were in inches.
603 * Now we use mm, but support reading of legacy files
604 */
605
606 n3D->m_Offset.x = parseDouble( "x value" ) * 25.4f;
607 n3D->m_Offset.y = parseDouble( "y value" ) * 25.4f;
608 n3D->m_Offset.z = parseDouble( "z value" ) * 25.4f;
609
610 NeedRIGHT(); // xyz
611 NeedRIGHT(); // at
612 break;
613
614 case T_hide:
615 n3D->m_Show = false;
616 break;
617
618 case T_opacity:
619 n3D->m_Opacity = parseDouble( "opacity value" );
620 NeedRIGHT();
621 break;
622
623 case T_offset:
624 NeedLEFT();
625 token = NextTok();
626
627 if( token != T_xyz )
628 Expecting( T_xyz );
629
630 /*
631 * 3D model offset is in mm
632 */
633 n3D->m_Offset.x = parseDouble( "x value" );
634 n3D->m_Offset.y = parseDouble( "y value" );
635 n3D->m_Offset.z = parseDouble( "z value" );
636
637 NeedRIGHT(); // xyz
638 NeedRIGHT(); // offset
639 break;
640
641 case T_scale:
642 NeedLEFT();
643 token = NextTok();
644
645 if( token != T_xyz )
646 Expecting( T_xyz );
647
648 n3D->m_Scale.x = parseDouble( "x value" );
649 n3D->m_Scale.y = parseDouble( "y value" );
650 n3D->m_Scale.z = parseDouble( "z value" );
651
652 NeedRIGHT(); // xyz
653 NeedRIGHT(); // scale
654 break;
655
656 case T_rotate:
657 NeedLEFT();
658 token = NextTok();
659
660 if( token != T_xyz )
661 Expecting( T_xyz );
662
663 n3D->m_Rotation.x = parseDouble( "x value" );
664 n3D->m_Rotation.y = parseDouble( "y value" );
665 n3D->m_Rotation.z = parseDouble( "z value" );
666
667 NeedRIGHT(); // xyz
668 NeedRIGHT(); // rotate
669 break;
670
671 default:
672 Expecting( "at, hide, opacity, offset, scale, or rotate" );
673 }
674
675 }
676
677 return n3D;
678}
VECTOR3D m_Offset
3D model offset (mm)
Definition: footprint.h:93
double m_Opacity
Definition: footprint.h:94
VECTOR3D m_Rotation
3D model rotation (degrees)
Definition: footprint.h:92
VECTOR3D m_Scale
3D model scaling factor (dimensionless)
Definition: footprint.h:91
wxString m_Filename
The 3D shape filename in 3D library.
Definition: footprint.h:95
bool m_Show
Include model in rendering.
Definition: footprint.h:96
T y
Definition: vector3.h:62
T z
Definition: vector3.h:63
T x
Definition: vector3.h:61
double parseDouble(LINE_READER &aReader, const char *aLine, const char **aOutput)
Parses an ASCII point string with possible leading whitespace into a double precision floating point ...

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(), VECTOR3< T >::x, VECTOR3< T >::y, and VECTOR3< T >::z.

Referenced by parseFOOTPRINT_unchecked().

◆ parseARC()

PCB_ARC * PCB_PARSER::parseARC ( )
private

Definition at line 5205 of file pcb_parser.cpp.

5206{
5207 wxCHECK_MSG( CurTok() == T_arc, nullptr,
5208 wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as ARC." ) );
5209
5210 VECTOR2I pt;
5211 T token;
5212
5213 std::unique_ptr<PCB_ARC> arc = std::make_unique<PCB_ARC>( m_board );
5214
5215 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
5216 {
5217 if( token == T_locked )
5218 {
5219 arc->SetLocked( true );
5220 token = NextTok();
5221 }
5222
5223 if( token != T_LEFT )
5224 Expecting( T_LEFT );
5225
5226 token = NextTok();
5227
5228 switch( token )
5229 {
5230 case T_start:
5231 pt.x = parseBoardUnits( "start x" );
5232 pt.y = parseBoardUnits( "start y" );
5233 arc->SetStart( pt );
5234 break;
5235
5236 case T_mid:
5237 pt.x = parseBoardUnits( "mid x" );
5238 pt.y = parseBoardUnits( "mid y" );
5239 arc->SetMid( pt );
5240 break;
5241
5242 case T_end:
5243 pt.x = parseBoardUnits( "end x" );
5244 pt.y = parseBoardUnits( "end y" );
5245 arc->SetEnd( pt );
5246 break;
5247
5248 case T_width:
5249 arc->SetWidth( parseBoardUnits( "width" ) );
5250 break;
5251
5252 case T_layer:
5253 arc->SetLayer( parseBoardItemLayer() );
5254 break;
5255
5256 case T_net:
5257 if( !arc->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
5258 {
5259 wxLogError( _( "Invalid net ID in\nfile: %s\nline: %d\noffset: %d." ),
5260 CurSource(), CurLineNumber(), CurOffset() );
5261 }
5262 break;
5263
5264 case T_tstamp:
5265 NextTok();
5266 const_cast<KIID&>( arc->m_Uuid ) = CurStrToKIID();
5267 break;
5268
5269 // We continue to parse the status field but it is no longer written
5270 case T_status:
5271 arc->SetStatus( static_cast<EDA_ITEM_FLAGS>( parseHex() ) );
5272 break;
5273
5274 // Continue to process "(locked)" format which was output during 5.99 development
5275 case T_locked:
5276 arc->SetLocked( true );
5277 break;
5278
5279 default:
5280 Expecting( "start, mid, end, width, layer, net, tstamp, or status" );
5281 }
5282
5283 NeedRIGHT();
5284 }
5285
5286 return arc.release();
5287}
PCB_LAYER_ID parseBoardItemLayer()
Parse the layer definition of a BOARD_ITEM object.
int parseBoardUnits()
Parse the current token as an ASCII numeric string with possible leading whitespace into a double pre...
Definition: pcb_parser.cpp:178
int getNetCode(int aNetCode)
< Convert net code using the mapping table if available, otherwise returns unchanged net code if < 0 ...
Definition: pcb_parser.h:119
KIID CurStrToKIID()
int parseInt()
Definition: pcb_parser.h:295
long parseHex()
Definition: pcb_parser.h:306
std::uint32_t EDA_ITEM_FLAGS

References _, CurStrToKIID(), getNetCode(), m_board, parseBoardItemLayer(), parseBoardUnits(), parseHex(), parseInt(), VECTOR2< T >::x, and VECTOR2< T >::y.

Referenced by parseBOARD_unchecked().

◆ parseBOARD()

BOARD * PCB_PARSER::parseBOARD ( )
private

Definition at line 731 of file pcb_parser.cpp.

732{
733 try
734 {
735 return parseBOARD_unchecked();
736 }
737 catch( const PARSE_ERROR& parse_error )
738 {
739 if( m_tooRecent )
740 throw FUTURE_FORMAT_ERROR( parse_error, GetRequiredVersion() );
741 else
742 throw;
743 }
744}
BOARD * parseBOARD_unchecked()
Definition: pcb_parser.cpp:747
wxString GetRequiredVersion()
Return a string representing the version of KiCad required to open this file.
Definition: pcb_parser.cpp:228
Variant of PARSE_ERROR indicating that a syntax or related error was likely caused by a file generate...
Definition: ki_exception.h:175
A filename or source description, a problem input line, a line number, a byte offset,...
Definition: ki_exception.h:119

References GetRequiredVersion(), m_tooRecent, and parseBOARD_unchecked().

Referenced by Parse().

◆ parseBOARD_unchecked()

BOARD * PCB_PARSER::parseBOARD_unchecked ( )
private

Definition at line 747 of file pcb_parser.cpp.

748{
749 T token;
750 std::map<wxString, wxString> properties;
751
752 parseHeader();
753
754 std::vector<BOARD_ITEM*> bulkAddedItems;
755 BOARD_ITEM* item = nullptr;
756
757 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
758 {
759 checkpoint();
760
761 if( token != T_LEFT )
762 Expecting( T_LEFT );
763
764 token = NextTok();
765
766 if( token == T_page && m_requiredVersion <= 20200119 )
767 token = T_paper;
768
769 switch( token )
770 {
771 case T_host: // legacy token
772 NeedSYMBOL();
773 m_board->SetGenerator( FromUTF8() );
774
775 // Older formats included build data
777 NeedSYMBOL();
778
779 NeedRIGHT();
780 break;
781
782 case T_generator:
783 NeedSYMBOL();
784 m_board->SetGenerator( FromUTF8() );
785 NeedRIGHT();
786 break;
787
788 case T_general:
790 break;
791
792 case T_paper:
794 break;
795
796 case T_title_block:
798 break;
799
800 case T_layers:
801 parseLayers();
802 break;
803
804 case T_setup:
805 parseSetup();
806 break;
807
808 case T_property:
809 properties.insert( parseProperty() );
810 break;
811
812 case T_net:
814 break;
815
816 case T_net_class:
819 break;
820
821 case T_gr_arc:
822 case T_gr_curve:
823 case T_gr_line:
824 case T_gr_poly:
825 case T_gr_circle:
826 case T_gr_rect:
827 item = parsePCB_SHAPE();
828 m_board->Add( item, ADD_MODE::BULK_APPEND, true );
829 bulkAddedItems.push_back( item );
830 break;
831
832 case T_image:
833 item = parsePCB_BITMAP( m_board );
834 m_board->Add( item, ADD_MODE::BULK_APPEND, true );
835 bulkAddedItems.push_back( item );
836 break;
837
838 case T_gr_text:
839 item = parsePCB_TEXT();
840 m_board->Add( item, ADD_MODE::BULK_APPEND, true );
841 bulkAddedItems.push_back( item );
842 break;
843
844 case T_gr_text_box:
845 item = parsePCB_TEXTBOX();
846 m_board->Add( item, ADD_MODE::BULK_APPEND, true );
847 bulkAddedItems.push_back( item );
848 break;
849
850 case T_dimension:
851 item = parseDIMENSION( m_board, false );
852 m_board->Add( item, ADD_MODE::BULK_APPEND, true );
853 bulkAddedItems.push_back( item );
854 break;
855
856 case T_module: // legacy token
857 case T_footprint:
858 item = parseFOOTPRINT();
859 m_board->Add( item, ADD_MODE::BULK_APPEND, true );
860 bulkAddedItems.push_back( item );
861 break;
862
863 case T_segment:
864 item = parsePCB_TRACK();
865 m_board->Add( item, ADD_MODE::BULK_APPEND, true );
866 bulkAddedItems.push_back( item );
867 break;
868
869 case T_arc:
870 item = parseARC();
871 m_board->Add( item, ADD_MODE::BULK_APPEND, true );
872 bulkAddedItems.push_back( item );
873 break;
874
875 case T_group:
877 break;
878
879 case T_via:
880 item = parsePCB_VIA();
881 m_board->Add( item, ADD_MODE::BULK_APPEND, true );
882 bulkAddedItems.push_back( item );
883 break;
884
885 case T_zone:
886 item = parseZONE( m_board );
887 m_board->Add( item, ADD_MODE::BULK_APPEND, true );
888 bulkAddedItems.push_back( item );
889 break;
890
891 case T_target:
892 item = parsePCB_TARGET();
893 m_board->Add( item, ADD_MODE::BULK_APPEND, true );
894 bulkAddedItems.push_back( item );
895 break;
896
897 default:
898 wxString err;
899 err.Printf( _( "Unknown token '%s'" ), FromUTF8() );
900 THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
901 }
902 }
903
904 if( bulkAddedItems.size() > 0 )
905 m_board->FinalizeBulkAdd( bulkAddedItems );
906
907 m_board->SetProperties( properties );
908
909 if( m_undefinedLayers.size() > 0 )
910 {
911 bool deleteItems;
912 std::vector<BOARD_ITEM*> deleteList;
913 wxString msg = wxString::Format( _( "Items found on undefined layers. Do you wish to\n"
914 "rescue them to the User.Comments layer?" ) );
915 wxString details = wxString::Format( _( "Undefined layers:" ) );
916
917 for( const wxString& undefinedLayer : m_undefinedLayers )
918 details += wxT( "\n " ) + undefinedLayer;
919
920 wxRichMessageDialog dlg( nullptr, msg, _( "Warning" ),
921 wxYES_NO | wxCANCEL | wxCENTRE | wxICON_WARNING | wxSTAY_ON_TOP );
922 dlg.ShowDetailedText( details );
923 dlg.SetYesNoCancelLabels( _( "Rescue" ), _( "Delete" ), _( "Cancel" ) );
924
925 switch( dlg.ShowModal() )
926 {
927 case wxID_YES: deleteItems = false; break;
928 case wxID_NO: deleteItems = true; break;
929 case wxID_CANCEL:
930 default: THROW_IO_ERROR( wxT( "CANCEL" ) );
931 }
932
933 auto visitItem = [&]( BOARD_ITEM* curr_item )
934 {
935 if( curr_item->GetLayer() == Rescue )
936 {
937 if( deleteItems )
938 deleteList.push_back( curr_item );
939 else
940 curr_item->SetLayer( Cmts_User );
941 }
942 };
943
944 for( PCB_TRACK* track : m_board->Tracks() )
945 {
946 if( track->Type() == PCB_VIA_T )
947 {
948 PCB_VIA* via = static_cast<PCB_VIA*>( track );
949 PCB_LAYER_ID top_layer, bottom_layer;
950
951 if( via->GetViaType() == VIATYPE::THROUGH )
952 continue;
953
954 via->LayerPair( &top_layer, &bottom_layer );
955
956 if( top_layer == Rescue || bottom_layer == Rescue )
957 {
958 if( deleteItems )
959 deleteList.push_back( via );
960 else
961 {
962 if( top_layer == Rescue )
963 top_layer = F_Cu;
964
965 if( bottom_layer == Rescue )
966 bottom_layer = B_Cu;
967
968 via->SetLayerPair( top_layer, bottom_layer );
969 }
970 }
971 }
972 else
973 {
974 visitItem( track );
975 }
976 }
977
978 for( BOARD_ITEM* zone : m_board->Zones() )
979 visitItem( zone );
980
981 for( BOARD_ITEM* drawing : m_board->Drawings() )
982 visitItem( drawing );
983
984 for( FOOTPRINT* fp : m_board->Footprints() )
985 {
986 for( BOARD_ITEM* drawing : fp->GraphicalItems() )
987 visitItem( drawing );
988
989 for( BOARD_ITEM* zone : fp->Zones() )
990 visitItem( zone );
991 }
992
993 for( BOARD_ITEM* curr_item : deleteList )
994 m_board->Delete( curr_item );
995
996 m_undefinedLayers.clear();
997 }
998
999 return m_board;
1000}
virtual void Delete(BOARD_ITEM *aItem)
Removes an item from the container and deletes it.
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: board.cpp:754
void SetProperties(const std::map< wxString, wxString > &aProps)
Definition: board.h:333
ZONES & Zones()
Definition: board.h:313
FOOTPRINTS & Footprints()
Definition: board.h:307
TRACKS & Tracks()
Definition: board.h:304
bool m_LegacyNetclassesLoaded
True if netclasses were loaded from the file.
Definition: board.h:346
DRAWINGS & Drawings()
Definition: board.h:310
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:851
void SetGenerator(const wxString &aGenerator)
Definition: board.h:365
PCB_TRACK * parsePCB_TRACK()
PCB_SHAPE * parsePCB_SHAPE()
ZONE * parseZONE(BOARD_ITEM_CONTAINER *aParent)
PCB_TEXTBOX * parsePCB_TEXTBOX()
std::pair< wxString, wxString > parseProperty()
Definition: pcb_parser.cpp:369
PCB_VIA * parsePCB_VIA()
void parseSetup()
PCB_TEXT * parsePCB_TEXT()
void parseHeader()
PCB_TARGET * parsePCB_TARGET()
void parseGROUP(BOARD_ITEM *aParent)
void checkpoint()
Definition: pcb_parser.cpp:123
PCB_ARC * parseARC()
PCB_BITMAP * parsePCB_BITMAP(BOARD_ITEM *aParent)
PCB_DIMENSION_BASE * parseDIMENSION(BOARD_ITEM *aParent, bool aInFP)
void parseLayers()
void parseNETINFO_ITEM()
void parseGeneralSection()
void parseTITLE_BLOCK()
void parsePAGE_INFO()
void parseNETCLASS()
@ Cmts_User
Definition: layer_ids.h:110
#define BOARD_FILE_HOST_VERSION
Earlier files than this include the host tag.
Definition: pcb_plugin.h:135
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_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:102

References _, BOARD::Add(), B_Cu, BOARD_FILE_HOST_VERSION, BULK_APPEND, checkpoint(), Cmts_User, BOARD_ITEM_CONTAINER::Delete(), BOARD::Drawings(), F_Cu, BOARD::FinalizeBulkAdd(), BOARD::Footprints(), Format(), m_board, BOARD::m_LegacyNetclassesLoaded, m_requiredVersion, m_undefinedLayers, parseARC(), parseDIMENSION(), parseFOOTPRINT(), parseGeneralSection(), parseGROUP(), parseHeader(), parseLayers(), parseNETCLASS(), parseNETINFO_ITEM(), parsePAGE_INFO(), parsePCB_BITMAP(), parsePCB_SHAPE(), parsePCB_TARGET(), parsePCB_TEXT(), parsePCB_TEXTBOX(), parsePCB_TRACK(), parsePCB_VIA(), parseProperty(), parseSetup(), parseTITLE_BLOCK(), parseZONE(), PCB_VIA_T, Rescue, BOARD::SetGenerator(), BOARD::SetProperties(), THROUGH, THROW_IO_ERROR, THROW_PARSE_ERROR, BOARD::Tracks(), via, and BOARD::Zones().

Referenced by parseBOARD().

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

1806{
1807 wxCHECK_MSG( CurTok() == T_layer, UNDEFINED_LAYER,
1808 wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as layer." ) );
1809
1810 NextTok();
1811
1812 PCB_LAYER_ID layerIndex = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
1813
1814 // Handle closing ) in object parser.
1815
1816 return layerIndex;
1817}
@ UNDEFINED_LAYER
Definition: layer_ids.h:60

References m_layerIndices, and UNDEFINED_LAYER.

Referenced by parseARC(), parseDIMENSION(), parseFOOTPRINT_unchecked(), parseFP_SHAPE(), parseFP_TEXT(), parseFP_TEXTBOX(), parsePCB_BITMAP(), parsePCB_SHAPE(), parsePCB_TARGET(), parsePCB_TEXT(), parsePCB_TEXTBOX(), parsePCB_TRACK(), and parseZONE().

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

1821{
1822 wxCHECK_MSG( CurTok() == T_layers, LSET(),
1823 wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as item layers." ) );
1824
1825 LSET layerMask;
1826
1827 for( T token = NextTok(); token != T_RIGHT; token = NextTok() )
1828 {
1829 LSET mask = lookUpLayer<LSET>( m_layerMasks );
1830 layerMask |= mask;
1831 }
1832
1833 return layerMask;
1834}

References m_layerMasks.

Referenced by parsePAD(), and parseZONE().

◆ parseBoardStackup()

void PCB_PARSER::parseBoardStackup ( )
private

Definition at line 1383 of file pcb_parser.cpp.

1384{
1385 T token;
1386 wxString name;
1387 int dielectric_idx = 1; // the index of dielectric layers
1389
1390 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1391 {
1392 if( CurTok() != T_LEFT )
1393 Expecting( T_LEFT );
1394
1395 token = NextTok();
1396
1397 if( token != T_layer )
1398 {
1399 switch( token )
1400 {
1401 case T_copper_finish:
1402 NeedSYMBOL();
1403 stackup.m_FinishType = FromUTF8();
1404 NeedRIGHT();
1405 break;
1406
1407 case T_edge_plating:
1408 token = NextTok();
1409 stackup.m_EdgePlating = token == T_yes;
1410 NeedRIGHT();
1411 break;
1412
1413 case T_dielectric_constraints:
1414 token = NextTok();
1415 stackup.m_HasDielectricConstrains = token == T_yes;
1416 NeedRIGHT();
1417 break;
1418
1419 case T_edge_connector:
1420 token = NextTok();
1422
1423 if( token == T_yes )
1425 else if( token == T_bevelled )
1427
1428 NeedRIGHT();
1429 break;
1430
1431 case T_castellated_pads:
1432 token = NextTok();
1433 stackup.m_CastellatedPads = token == T_yes;
1434 NeedRIGHT();
1435 break;
1436
1437 default:
1438 // Currently, skip this item if not defined, because the stackup def
1439 // is a moving target
1440 //Expecting( "copper_finish, edge_plating, dielectric_constrains, edge_connector, castellated_pads" );
1441 skipCurrent();
1442 break;
1443 }
1444
1445 continue;
1446 }
1447
1448 NeedSYMBOL();
1449 name = FromUTF8();
1450
1451 // init the layer id. For dielectric, layer id = UNDEFINED_LAYER
1452 PCB_LAYER_ID layerId = m_board->GetLayerID( name );
1453
1454 // Init the type
1456
1457 if( layerId == F_SilkS || layerId == B_SilkS )
1459 else if( layerId == F_Mask || layerId == B_Mask )
1461 else if( layerId == F_Paste || layerId == B_Paste )
1463 else if( layerId == UNDEFINED_LAYER )
1465 else if( layerId >= F_Cu && layerId <= B_Cu )
1466 type = BS_ITEM_TYPE_COPPER;
1467
1468 BOARD_STACKUP_ITEM* item = nullptr;
1469
1470 if( type != BS_ITEM_TYPE_UNDEFINED )
1471 {
1472 item = new BOARD_STACKUP_ITEM( type );
1473 item->SetBrdLayerId( layerId );
1474
1475 if( type == BS_ITEM_TYPE_DIELECTRIC )
1476 item->SetDielectricLayerId( dielectric_idx++ );
1477
1478 stackup.Add( item );
1479 }
1480 else
1481 {
1482 Expecting( "layer_name" );
1483 }
1484
1485 bool has_next_sublayer = true;
1486 int sublayer_idx = 0; // the index of dielectric sub layers
1487 // sublayer 0 is always existing (main sublayer)
1488
1489 while( has_next_sublayer )
1490 {
1491 has_next_sublayer = false;
1492
1493 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1494 {
1495 if( token == T_addsublayer )
1496 {
1497 has_next_sublayer = true;
1498 break;
1499 }
1500
1501 if( token == T_LEFT )
1502 {
1503 token = NextTok();
1504
1505 switch( token )
1506 {
1507 case T_type:
1508 NeedSYMBOL();
1509 item->SetTypeName( FromUTF8() );
1510 NeedRIGHT();
1511 break;
1512
1513 case T_thickness:
1514 item->SetThickness( parseBoardUnits( T_thickness ), sublayer_idx );
1515 token = NextTok();
1516
1517 if( token == T_LEFT )
1518 break;
1519
1520 if( token == T_locked )
1521 {
1522 // Dielectric thickness can be locked (for impedance controlled layers)
1523 if( type == BS_ITEM_TYPE_DIELECTRIC )
1524 item->SetThicknessLocked( true, sublayer_idx );
1525
1526 NeedRIGHT();
1527 }
1528
1529 break;
1530
1531 case T_material:
1532 NeedSYMBOL();
1533 item->SetMaterial( FromUTF8(), sublayer_idx );
1534 NeedRIGHT();
1535 break;
1536
1537 case T_epsilon_r:
1538 NextTok();
1539 item->SetEpsilonR( parseDouble(), sublayer_idx );
1540 NeedRIGHT();
1541 break;
1542
1543 case T_loss_tangent:
1544 NextTok();
1545 item->SetLossTangent( parseDouble(), sublayer_idx );
1546 NeedRIGHT();
1547 break;
1548
1549 case T_color:
1550 NeedSYMBOL();
1551 name = FromUTF8();
1552
1553 // Older versions didn't store opacity with custom colors
1554 if( name.StartsWith( wxT( "#" ) ) && m_requiredVersion < 20210824 )
1555 {
1557
1558 if( item->GetType() == BS_ITEM_TYPE_SOLDERMASK )
1559 color = color.WithAlpha( DEFAULT_SOLDERMASK_OPACITY );
1560 else
1561 color = color.WithAlpha( 1.0 );
1562
1563 wxColour wx_color = color.ToColour();
1564
1565 // Open-code wxColour::GetAsString() because 3.0 doesn't handle rgba
1566 name.Printf( wxT("#%02X%02X%02X%02X" ),
1567 wx_color.Red(),
1568 wx_color.Green(),
1569 wx_color.Blue(),
1570 wx_color.Alpha() );
1571 }
1572
1573 item->SetColor( name, sublayer_idx );
1574 NeedRIGHT();
1575 break;
1576
1577 default:
1578 // Currently, skip this item if not defined, because the stackup def
1579 // is a moving target
1580 //Expecting( "type, thickness, material, epsilon_r, loss_tangent, color" );
1581 skipCurrent();
1582 }
1583 }
1584 }
1585
1586 if( has_next_sublayer ) // Prepare reading the next sublayer description
1587 {
1588 sublayer_idx++;
1589 item->AddDielectricPrms( sublayer_idx );
1590 }
1591 }
1592 }
1593
1594 if( token != T_RIGHT )
1595 {
1596 Expecting( ")" );
1597 }
1598
1599 // Success:
1601}
int color
Definition: DXF_plotter.cpp:57
const char * name
Definition: DXF_plotter.cpp:56
@ BS_EDGE_CONNECTOR_BEVELLED
Definition: board_stackup.h:57
@ BS_EDGE_CONNECTOR_NONE
Definition: board_stackup.h:55
@ BS_EDGE_CONNECTOR_IN_USE
Definition: board_stackup.h:56
BOARD_STACKUP_ITEM_TYPE
Definition: board_stackup.h:41
@ BS_ITEM_TYPE_UNDEFINED
Definition: board_stackup.h:42
@ BS_ITEM_TYPE_COPPER
Definition: board_stackup.h:43
@ BS_ITEM_TYPE_SILKSCREEN
Definition: board_stackup.h:49
@ BS_ITEM_TYPE_DIELECTRIC
Definition: board_stackup.h:44
@ BS_ITEM_TYPE_SOLDERPASTE
Definition: board_stackup.h:46
@ BS_ITEM_TYPE_SOLDERMASK
Definition: board_stackup.h:47
BOARD_STACKUP & GetStackupDescriptor()
Manage one layer needed to make a physical board.
Definition: board_stackup.h:91
void AddDielectricPrms(int aDielectricPrmsIdx)
Add (insert) a DIELECTRIC_PRMS item to m_DielectricPrmsList all values are set to default.
void SetDielectricLayerId(int aLayerId)
void SetThickness(int aThickness, int aDielectricSubLayer=0)
void SetThicknessLocked(bool aLocked, int aDielectricSubLayer=0)
void SetMaterial(const wxString &aName, int aDielectricSubLayer=0)
void SetLossTangent(double aTg, int aDielectricSubLayer=0)
BOARD_STACKUP_ITEM_TYPE GetType() const
void SetBrdLayerId(PCB_LAYER_ID aBrdLayerId)
void SetTypeName(const wxString &aName)
void SetColor(const wxString &aColorName, int aDielectricSubLayer=0)
void SetEpsilonR(double aEpsilon, int aDielectricSubLayer=0)
Manage layers needed to make a physical board.
bool m_CastellatedPads
True if castellated pads exist.
bool m_HasDielectricConstrains
True if some layers have impedance controlled tracks or have specific constrains for micro-wave appli...
void Add(BOARD_STACKUP_ITEM *aItem)
Add a new item in stackup layer.
bool m_EdgePlating
True if the edge board is plated.
BS_EDGE_CONNECTOR_CONSTRAINTS m_EdgeConnectorConstraints
If the board has edge connector cards, some constrains can be specified in job file: BS_EDGE_CONNECTO...
wxString m_FinishType
The name of external copper finish.
const PCB_LAYER_ID GetLayerID(const wxString &aLayerName) const
Return the ID of a layer.
Definition: board.cpp:436
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:686
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
void skipCurrent()
Skip the current token level, i.e search for the RIGHT parenthesis which closes the current descripti...
Definition: pcb_parser.cpp:145
#define DEFAULT_SOLDERMASK_OPACITY

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::GetDesignSettings(), BOARD::GetLayerID(), BOARD_DESIGN_SETTINGS::GetStackupDescriptor(), BOARD_STACKUP_ITEM::GetType(), m_board, BOARD_STACKUP::m_CastellatedPads, BOARD_STACKUP::m_EdgeConnectorConstraints, BOARD_STACKUP::m_EdgePlating, BOARD_STACKUP::m_FinishType, BOARD_STACKUP::m_HasDielectricConstrains, BOARD_DESIGN_SETTINGS::m_HasStackup, m_requiredVersion, name, parseBoardUnits(), 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(), skipCurrent(), and UNDEFINED_LAYER.

Referenced by parseSetup().

◆ parseBoardUnits() [1/3]

int PCB_PARSER::parseBoardUnits ( )
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 178 of file pcb_parser.cpp.

179{
180 // There should be no major rounding issues here, since the values in
181 // the file are in mm and get converted to nano-meters.
182 // See test program tools/test-nm-biu-to-ascii-mm-round-tripping.cpp
183 // to confirm or experiment. Use a similar strategy in both places, here
184 // and in the test program. Make that program with:
185 // $ make test-nm-biu-to-ascii-mm-round-tripping
186 auto retval = parseDouble() * pcbIUScale.IU_PER_MM;
187
188 // N.B. we currently represent board units as integers. Any values that are
189 // larger or smaller than those board units represent undefined behavior for
190 // the system. We limit values to the largest that is visible on the screen
191 // This is the diagonal distance of the full screen ~1.5m
192 constexpr double int_limit =
193 std::numeric_limits<int>::max() * 0.7071; // 0.7071 = roughly 1/sqrt(2)
194 return KiROUND( Clamp<double>( -int_limit, retval, int_limit ) );
195}
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:109
const double IU_PER_MM
Definition: base_units.h:77
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:85

References EDA_IU_SCALE::IU_PER_MM, KiROUND(), parseDouble(), and pcbIUScale.

Referenced by parseARC(), parseBoardStackup(), parseBoardUnits(), parseDefaults(), parseDefaultTextDims(), parseDIMENSION(), parseEDA_TEXT(), parseFOOTPRINT_unchecked(), parseFP_SHAPE(), parseFP_TEXT(), parseFP_TEXTBOX(), parseGeneralSection(), parseNETCLASS(), parseOutlinePoints(), parsePAD(), parsePCB_BITMAP(), parsePCB_SHAPE(), parsePCB_TARGET(), parsePCB_TEXT(), parsePCB_TEXTBOX(), parsePCB_TRACK(), parsePCB_VIA(), parseSetup(), parseXY(), and parseZONE().

◆ parseBoardUnits() [2/3]

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

Definition at line 198 of file pcb_parser.cpp.

199{
200 auto retval = parseDouble( aExpected ) * pcbIUScale.IU_PER_MM;
201
202 // N.B. we currently represent board units as integers. Any values that are
203 // larger or smaller than those board units represent undefined behavior for
204 // the system. We limit values to the largest that is visible on the screen
205 constexpr double int_limit = std::numeric_limits<int>::max() * 0.7071;
206
207 // Use here #KiROUND, not EKIROUND (see comments about them) when having a function as
208 // argument, because it will be called twice with #KIROUND.
209 return KiROUND( Clamp<double>( -int_limit, retval, int_limit ) );
210}

References EDA_IU_SCALE::IU_PER_MM, KiROUND(), parseDouble(), and pcbIUScale.

◆ parseBoardUnits() [3/3]

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

Definition at line 290 of file pcb_parser.h.

291 {
292 return parseBoardUnits( GetTokenText( aToken ) );
293 }
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 213 of file pcb_parser.cpp.

214{
215 T token = NextTok();
216
217 if( token == T_yes )
218 return true;
219 else if( token == T_no )
220 return false;
221 else
222 Expecting( "yes or no" );
223
224 return false;
225}

Referenced by parseSetup(), and parseZONE().

◆ parseDefaults()

void PCB_PARSER::parseDefaults ( BOARD_DESIGN_SETTINGS aSettings)
private

Definition at line 2210 of file pcb_parser.cpp.

2211{
2212 T token;
2213
2214 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2215 {
2216 if( token != T_LEFT )
2217 Expecting( T_LEFT );
2218
2219 token = NextTok();
2220
2221 switch( token )
2222 {
2223 case T_edge_clearance:
2224 designSettings.m_CopperEdgeClearance = parseBoardUnits( T_edge_clearance );
2226 NeedRIGHT();
2227 break;
2228
2229 case T_copper_line_width:
2230 designSettings.m_LineThickness[ LAYER_CLASS_COPPER ] = parseBoardUnits( token );
2231 NeedRIGHT();
2232 break;
2233
2234 case T_copper_text_dims:
2235 parseDefaultTextDims( designSettings, LAYER_CLASS_COPPER );
2236 break;
2237
2238 case T_courtyard_line_width:
2239 designSettings.m_LineThickness[ LAYER_CLASS_COURTYARD ] = parseBoardUnits( token );
2240 NeedRIGHT();
2241 break;
2242
2243 case T_edge_cuts_line_width:
2244 designSettings.m_LineThickness[ LAYER_CLASS_EDGES ] = parseBoardUnits( token );
2245 NeedRIGHT();
2246 break;
2247
2248 case T_silk_line_width:
2249 designSettings.m_LineThickness[ LAYER_CLASS_SILK ] = parseBoardUnits( token );
2250 NeedRIGHT();
2251 break;
2252
2253 case T_silk_text_dims:
2254 parseDefaultTextDims( designSettings, LAYER_CLASS_SILK );
2255 break;
2256
2257 case T_fab_layers_line_width:
2258 designSettings.m_LineThickness[ LAYER_CLASS_FAB ] = parseBoardUnits( token );
2259 NeedRIGHT();
2260 break;
2261
2262 case T_fab_layers_text_dims:
2263 parseDefaultTextDims( designSettings, LAYER_CLASS_FAB );
2264 break;
2265
2266 case T_other_layers_line_width:
2267 designSettings.m_LineThickness[ LAYER_CLASS_OTHERS ] = parseBoardUnits( token );
2268 NeedRIGHT();
2269 break;
2270
2271 case T_other_layers_text_dims:
2272 parseDefaultTextDims( designSettings, LAYER_CLASS_OTHERS );
2273 break;
2274
2275 case T_dimension_units:
2276 designSettings.m_DimensionUnitsMode =
2277 static_cast<DIM_UNITS_MODE>( parseInt( "dimension units" ) );
2278 NeedRIGHT();
2279 break;
2280
2281 case T_dimension_precision:
2282 designSettings.m_DimensionPrecision = parseInt( "dimension precision" );
2283 NeedRIGHT();
2284 break;
2285
2286 default:
2287 Unexpected( CurText() );
2288 }
2289 }
2290}
@ LAYER_CLASS_OTHERS
@ LAYER_CLASS_FAB
@ LAYER_CLASS_COURTYARD
@ LAYER_CLASS_SILK
@ LAYER_CLASS_COPPER
@ LAYER_CLASS_EDGES
bool m_LegacyCopperEdgeClearanceLoaded
Definition: board.h:343
void parseDefaultTextDims(BOARD_DESIGN_SETTINGS &aSettings, int aLayer)
DIM_UNITS_MODE
Used for storing the units selection in the file because EDA_UNITS alone doesn't cut it.
Definition: pcb_dimension.h:58

References LAYER_CLASS_COPPER, LAYER_CLASS_COURTYARD, LAYER_CLASS_EDGES, LAYER_CLASS_FAB, LAYER_CLASS_OTHERS, LAYER_CLASS_SILK, m_board, BOARD_DESIGN_SETTINGS::m_CopperEdgeClearance, BOARD_DESIGN_SETTINGS::m_DimensionPrecision, BOARD_DESIGN_SETTINGS::m_DimensionUnitsMode, BOARD::m_LegacyCopperEdgeClearanceLoaded, BOARD_DESIGN_SETTINGS::m_LineThickness, parseBoardUnits(), parseDefaultTextDims(), and parseInt().

Referenced by parseSetup().

◆ parseDefaultTextDims()

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

Definition at line 2293 of file pcb_parser.cpp.

2294{
2295 T token;
2296
2297 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2298 {
2299 if( token == T_LEFT )
2300 token = NextTok();
2301
2302 switch( token )
2303 {
2304 case T_size:
2305 aSettings.m_TextSize[ aLayer ].x = parseBoardUnits( "default text size X" );
2306 aSettings.m_TextSize[ aLayer ].y = parseBoardUnits( "default text size Y" );
2307 NeedRIGHT();
2308 break;
2309
2310 case T_thickness:
2311 aSettings.m_TextThickness[ aLayer ] = parseBoardUnits( "default text width" );
2312 NeedRIGHT();
2313 break;
2314
2315 case T_italic:
2316 aSettings.m_TextItalic[ aLayer ] = true;
2317 break;
2318
2319 case T_keep_upright:
2320 aSettings.m_TextUpright[ aLayer ] = true;
2321 break;
2322
2323 default:
2324 Expecting( "size, thickness, italic or keep_upright" );
2325 }
2326 }
2327}
bool m_TextUpright[LAYER_CLASS_COUNT]
int m_TextThickness[LAYER_CLASS_COUNT]
wxSize m_TextSize[LAYER_CLASS_COUNT]
bool m_TextItalic[LAYER_CLASS_COUNT]

References BOARD_DESIGN_SETTINGS::m_TextItalic, BOARD_DESIGN_SETTINGS::m_TextSize, BOARD_DESIGN_SETTINGS::m_TextThickness, BOARD_DESIGN_SETTINGS::m_TextUpright, and parseBoardUnits().

Referenced by parseDefaults().

◆ parseDIMENSION()

PCB_DIMENSION_BASE * PCB_PARSER::parseDIMENSION ( BOARD_ITEM aParent,
bool  aInFP 
)
private

Definition at line 3127 of file pcb_parser.cpp.

3128{
3129 wxCHECK_MSG( CurTok() == T_dimension, nullptr,
3130 wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as DIMENSION." ) );
3131
3132 T token;
3133 bool locked = false;
3134 std::unique_ptr<PCB_DIMENSION_BASE> dim;
3135
3136 token = NextTok();
3137
3138 if( token == T_locked )
3139 {
3140 locked = true;
3141 token = NextTok();
3142 }
3143
3144 // skip value that used to be saved
3145 if( token != T_LEFT )
3146 NeedLEFT();
3147
3148 token = NextTok();
3149
3150 bool isLegacyDimension = false;
3151
3152 // Old format
3153 if( token == T_width )
3154 {
3155 isLegacyDimension = true;
3156 dim = std::make_unique<PCB_DIM_ALIGNED>( aParent, aInFP ? PCB_FP_DIM_ALIGNED_T
3158 dim->SetLineThickness( parseBoardUnits( "dim width value" ) );
3159 NeedRIGHT();
3160 }
3161 else
3162 {
3163 if( token != T_type )
3164 Expecting( T_type );
3165
3166 switch( NextTok() )
3167 {
3168 case T_aligned:
3169 dim = std::make_unique<PCB_DIM_ALIGNED>( aParent, aInFP ? PCB_FP_DIM_ALIGNED_T
3171 break;
3172
3173 case T_orthogonal:
3174 dim = std::make_unique<PCB_DIM_ORTHOGONAL>( aParent, aInFP );
3175 break;
3176
3177 case T_leader:
3178 dim = std::make_unique<PCB_DIM_LEADER>( aParent, aInFP );
3179 break;
3180
3181 case T_center:
3182 dim = std::make_unique<PCB_DIM_CENTER>( aParent, aInFP );
3183 break;
3184
3185 case T_radial:
3186 dim = std::make_unique<PCB_DIM_RADIAL>( aParent, aInFP );
3187 break;
3188
3189 default:
3190 wxFAIL_MSG( wxT( "Cannot parse unknown dim type %s" ) + GetTokenString( CurTok() ) );
3191 }
3192
3193 NeedRIGHT();
3194 }
3195
3196 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3197 {
3198 if( token != T_LEFT )
3199 Expecting( T_LEFT );
3200
3201 token = NextTok();
3202
3203 switch( token )
3204 {
3205 case T_layer:
3206 dim->SetLayer( parseBoardItemLayer() );
3207 NeedRIGHT();
3208 break;
3209
3210 case T_tstamp:
3211 NextTok();
3212 const_cast<KIID&>( dim->m_Uuid ) = CurStrToKIID();
3213 NeedRIGHT();
3214 break;
3215
3216 case T_gr_text:
3217 {
3219 dim->Text() = *text;
3220
3221 // The text is part of the dim and shares its uuid
3222 const_cast<KIID&>( dim->Text().m_Uuid ) = dim->m_Uuid;
3223
3224 // Fetch other dim properties out of the text item
3225 dim->Text().SetTextPos( text->GetTextPos() );
3226
3227 if( isLegacyDimension )
3228 {
3230 EDA_UNIT_UTILS::FetchUnitsFromString( text->GetText(), units );
3231 dim->SetUnits( units );
3232 }
3233
3234 delete text;
3235 break;
3236 }
3237
3238 // New format: feature points
3239 case T_pts:
3240 {
3241 VECTOR2I point;
3242
3243 parseXY( &point.x, &point.y );
3244 dim->SetStart( point );
3245 parseXY( &point.x, &point.y );
3246 dim->SetEnd( point );
3247
3248 NeedRIGHT();
3249 break;
3250 }
3251
3252 case T_height:
3253 {
3254 int height = parseBoardUnits( "dim height value" );
3255 NeedRIGHT();
3256
3257 if( dim->Type() == PCB_DIM_ORTHOGONAL_T || dim->Type() == PCB_FP_DIM_ORTHOGONAL_T
3258 || dim->Type() == PCB_DIM_ALIGNED_T || dim->Type() == PCB_FP_DIM_ALIGNED_T )
3259 {
3260 PCB_DIM_ALIGNED* aligned = static_cast<PCB_DIM_ALIGNED*>( dim.get() );
3261 aligned->SetHeight( height );
3262 }
3263
3264 break;
3265 }
3266
3267 case T_leader_length:
3268 {
3269 int length = parseBoardUnits( "dim leader length value" );
3270 NeedRIGHT();
3271
3272 if( dim->Type() == PCB_DIM_RADIAL_T || dim->Type() == PCB_FP_DIM_RADIAL_T )
3273 {
3274 PCB_DIM_RADIAL* radial = static_cast<PCB_DIM_RADIAL*>( dim.get() );
3275 radial->SetLeaderLength( length );
3276 }
3277
3278 break;
3279 }
3280
3281 case T_orientation:
3282 {
3283 int orientation = parseInt( "orthogonal dim orientation" );
3284 NeedRIGHT();
3285
3286 if( dim->Type() == PCB_DIM_ORTHOGONAL_T || dim->Type() == PCB_FP_DIM_ORTHOGONAL_T )
3287 {
3288 PCB_DIM_ORTHOGONAL* ortho = static_cast<PCB_DIM_ORTHOGONAL*>( dim.get() );
3289 orientation = std::max( 0, std::min( 1, orientation ) );
3290 ortho->SetOrientation( static_cast<PCB_DIM_ORTHOGONAL::DIR>( orientation ) );
3291 }
3292
3293 break;
3294 }
3295
3296 case T_format:
3297 {
3298 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3299 {
3300 switch( token )
3301 {
3302 case T_LEFT:
3303 continue;
3304
3305 case T_prefix:
3306 NeedSYMBOLorNUMBER();
3307 dim->SetPrefix( FromUTF8() );
3308 NeedRIGHT();
3309 break;
3310
3311 case T_suffix:
3312 NeedSYMBOLorNUMBER();
3313 dim->SetSuffix( FromUTF8() );
3314 NeedRIGHT();
3315 break;
3316
3317 case T_units:
3318 {
3319 int mode = parseInt( "dim units mode" );
3320 mode = std::max( 0, std::min( 4, mode ) );
3321 dim->SetUnitsMode( static_cast<DIM_UNITS_MODE>( mode ) );
3322 NeedRIGHT();
3323 break;
3324 }
3325
3326 case T_units_format:
3327 {
3328 int format = parseInt( "dim units format" );
3329 format = std::max( 0, std::min( 3, format ) );
3330 dim->SetUnitsFormat( static_cast<DIM_UNITS_FORMAT>( format ) );
3331 NeedRIGHT();
3332 break;
3333 }
3334
3335 case T_precision:
3336 dim->SetPrecision( parseInt( "dim precision" ) );
3337 NeedRIGHT();
3338 break;
3339
3340 case T_override_value:
3341 NeedSYMBOLorNUMBER();
3342 dim->SetOverrideTextEnabled( true );
3343 dim->SetOverrideText( FromUTF8() );
3344 NeedRIGHT();
3345 break;
3346
3347 case T_suppress_zeroes:
3348 dim->SetSuppressZeroes( true );
3349 break;
3350
3351 default:
3352 Expecting( "prefix, suffix, units, units_format, precision, override_value, "
3353 "suppress_zeroes" );
3354 }
3355 }
3356 break;
3357 }
3358
3359 case T_style:
3360 {
3361 // new format: default to keep text aligned off unless token is present
3362 dim->SetKeepTextAligned( false );
3363
3364 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3365 {
3366 switch( token )
3367 {
3368 case T_LEFT:
3369 continue;
3370
3371 case T_thickness:
3372 dim->SetLineThickness( parseBoardUnits( "extension line thickness" ) );
3373 NeedRIGHT();
3374 break;
3375
3376 case T_arrow_length:
3377 dim->SetArrowLength( parseBoardUnits( "arrow length" ) );
3378 NeedRIGHT();
3379 break;
3380
3381 case T_text_position_mode:
3382 {
3383 int mode = parseInt( "dim text position mode" );
3384 mode = std::max( 0, std::min( 3, mode ) );
3385 dim->SetTextPositionMode( static_cast<DIM_TEXT_POSITION>( mode ) );
3386 NeedRIGHT();
3387 break;
3388 }
3389
3390 case T_extension_height:
3391 {
3392 PCB_DIM_ALIGNED* aligned = dynamic_cast<PCB_DIM_ALIGNED*>( dim.get() );
3393 wxCHECK_MSG( aligned, nullptr, wxT( "Invalid extension_height token" ) );
3394 aligned->SetExtensionHeight( parseBoardUnits( "extension height" ) );
3395 NeedRIGHT();
3396 break;
3397 }
3398
3399 case T_extension_offset:
3400 dim->SetExtensionOffset( parseBoardUnits( "extension offset" ) );
3401 NeedRIGHT();
3402 break;
3403
3404 case T_keep_text_aligned:
3405 dim->SetKeepTextAligned( true );
3406 break;
3407
3408 case T_text_frame:
3409 {
3410 KICAD_T expected_type = aInFP ? PCB_FP_DIM_LEADER_T : PCB_DIM_LEADER_T;
3411 wxCHECK_MSG( dim->Type() == expected_type, nullptr,
3412 wxT( "Invalid text_frame token" ) );
3413
3414 PCB_DIM_LEADER* leader = static_cast<PCB_DIM_LEADER*>( dim.get() );
3415
3416 int textFrame = parseInt( "dim text frame mode" );
3417 textFrame = std::max( 0, std::min( 3, textFrame ) );
3418 leader->SetTextBorder( static_cast<DIM_TEXT_BORDER>( textFrame ));
3419 NeedRIGHT();
3420 break;
3421 }
3422
3423 default:
3424 Expecting( "thickness, arrow_length, text_position_mode, extension_height, "
3425 "extension_offset" );
3426 }
3427 }
3428
3429 break;
3430 }
3431
3432 // Old format: feature1 stores a feature line. We only care about the origin.
3433 case T_feature1:
3434 {
3435 NeedLEFT();
3436 token = NextTok();
3437
3438 if( token != T_pts )
3439 Expecting( T_pts );
3440
3441 VECTOR2I point;
3442
3443 parseXY( &point.x, &point.y );
3444 dim->SetStart( point );
3445
3446 parseXY( nullptr, nullptr ); // Ignore second point
3447 NeedRIGHT();
3448 NeedRIGHT();
3449 break;
3450 }
3451
3452 // Old format: feature2 stores a feature line. We only care about the end point.
3453 case T_feature2:
3454 {
3455 NeedLEFT();
3456 token = NextTok();
3457
3458 if( token != T_pts )
3459 Expecting( T_pts );
3460
3461 VECTOR2I point;
3462
3463 parseXY( &point.x, &point.y );
3464 dim->SetEnd( point );
3465
3466 parseXY( nullptr, nullptr ); // Ignore second point
3467
3468 NeedRIGHT();
3469 NeedRIGHT();
3470 break;
3471 }
3472
3473 case T_crossbar:
3474 {
3475 NeedLEFT();
3476 token = NextTok();
3477
3478 if( token == T_pts )
3479 {
3480 // If we have a crossbar, we know we're an old aligned dim
3481 PCB_DIM_ALIGNED* aligned = static_cast<PCB_DIM_ALIGNED*>( dim.get() );
3482
3483 // Old style: calculate height from crossbar
3484 VECTOR2I point1, point2;
3485 parseXY( &point1.x, &point1.y );
3486 parseXY( &point2.x, &point2.y );
3487 aligned->UpdateHeight( point2, point1 ); // Yes, backwards intentionally
3488 NeedRIGHT();
3489 }
3490
3491 NeedRIGHT();
3492 break;
3493 }
3494
3495 // Arrow: no longer saved; no-op
3496 case T_arrow1a:
3497 NeedLEFT();
3498 token = NextTok();
3499
3500 if( token != T_pts )
3501 Expecting( T_pts );
3502
3503 parseXY( nullptr, nullptr );
3504 parseXY( nullptr, nullptr );
3505 NeedRIGHT();
3506 NeedRIGHT();
3507 break;
3508
3509 // Arrow: no longer saved; no-op
3510 case T_arrow1b:
3511 NeedLEFT();
3512 token = NextTok();
3513
3514 if( token != T_pts )
3515 Expecting( T_pts );
3516
3517 parseXY( nullptr, nullptr );
3518 parseXY( nullptr, nullptr );
3519 NeedRIGHT();
3520 NeedRIGHT();
3521 break;
3522
3523 // Arrow: no longer saved; no-op
3524 case T_arrow2a:
3525 NeedLEFT();
3526 token = NextTok();
3527
3528 if( token != T_pts )
3529 Expecting( T_pts );
3530
3531 parseXY( nullptr, nullptr );
3532 parseXY( nullptr, nullptr );
3533 NeedRIGHT();
3534 NeedRIGHT();
3535 break;
3536
3537 // Arrow: no longer saved; no-op
3538 case T_arrow2b:
3539 NeedLEFT();
3540 token = NextTok();
3541
3542 if( token != T_pts )
3543 Expecting( T_pts );
3544
3545 parseXY( nullptr, nullptr );
3546 parseXY( nullptr, nullptr );
3547 NeedRIGHT();
3548 NeedRIGHT();
3549 break;
3550
3551 default:
3552 Expecting( "layer, tstamp, gr_text, feature1, feature2, crossbar, arrow1a, "
3553 "arrow1b, arrow2a, or arrow2b" );
3554 }
3555 }
3556
3557 if( locked )
3558 dim->SetLocked( true );
3559
3560 dim->Update();
3561
3562 return dim.release();
3563}
For better understanding of the points that make a dimension:
void SetExtensionHeight(int aHeight)
void UpdateHeight(const VECTOR2I &aCrossbarStart, const VECTOR2I &aCrossbarEnd)
Update the stored height basing on points coordinates.
void SetHeight(int aHeight)
Set the distance from the feature points to the crossbar line.
A leader is a dimension-like object pointing to a specific point.
void SetTextBorder(DIM_TEXT_BORDER aFrame)
An orthogonal dimension is like an aligned dimension, but the extension lines are locked to the X or ...
A radial dimension indicates either the radius or diameter of an arc or circle.
void SetLeaderLength(int aLength)
VECTOR2I parseXY()
Parse a coordinate pair (xy X Y) in board units (mm).
Definition: pcb_parser.cpp:252
EDA_UNITS
Definition: eda_units.h:43
void FetchUnitsFromString(const wxString &aTextValue, EDA_UNITS &aUnits)
Writes any unit info found in the string to aUnits.
Definition: eda_units.cpp:68
DIM_TEXT_POSITION
Where to place the text on a dimension.
Definition: pcb_dimension.h:48
DIM_UNITS_FORMAT
How to display the units in a dimension's text.
Definition: pcb_dimension.h:40
DIM_TEXT_BORDER
Frame to show around dimension text.
Definition: pcb_dimension.h:69
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:78
@ PCB_FP_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition: typeinfo.h:95
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition: typeinfo.h:110
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:107
@ PCB_FP_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition: typeinfo.h:99
@ PCB_FP_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:96
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition: typeinfo.h:106
@ PCB_FP_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:98
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:109

References CurStrToKIID(), EDA_UNIT_UTILS::FetchUnitsFromString(), INCHES, locked, ortho, parseBoardItemLayer(), parseBoardUnits(), parseInt(), parsePCB_TEXT(), parseXY(), PCB_DIM_ALIGNED_T, PCB_DIM_LEADER_T, PCB_DIM_ORTHOGONAL_T, PCB_DIM_RADIAL_T, PCB_FP_DIM_ALIGNED_T, PCB_FP_DIM_LEADER_T, PCB_FP_DIM_ORTHOGONAL_T, PCB_FP_DIM_RADIAL_T, PCB_DIM_ALIGNED::SetExtensionHeight(), PCB_DIM_ALIGNED::SetHeight(), PCB_DIM_RADIAL::SetLeaderLength(), PCB_DIM_LEADER::SetTextBorder(), text, PCB_DIM_ALIGNED::UpdateHeight(), VECTOR2< T >::x, and VECTOR2< T >::y.

Referenced by parseBOARD_unchecked(), and parseFOOTPRINT_unchecked().

◆ parseEDA_TEXT()

void PCB_PARSER::parseEDA_TEXT ( EDA_TEXT aText)
private

Parse the common settings for any object derived from EDA_TEXT.

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

Definition at line 384 of file pcb_parser.cpp.

385{
386 wxCHECK_RET( CurTok() == T_effects,
387 wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as EDA_TEXT." ) );
388
389 // These are not written out if center/center, so we have to make sure we start that way.
392
393 // In version 20210606 the notation for overbars was changed from `~...~` to `~{...}`.
394 // We need to convert the old syntax to the new one.
395 if( m_requiredVersion < 20210606 )
396 aText->SetText( ConvertToNewOverbarNotation( aText->GetText() ) );
397
398 T token;
399
400 // Prior to v5.0 text size was omitted from file format if equal to 60mils
401 // Now, it is always explicitly written to file
402 bool foundTextSize = false;
403 wxString faceName;
404
405 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
406 {
407 if( token == T_LEFT )
408 token = NextTok();
409
410 switch( token )
411 {
412 case T_font:
413 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
414 {
415 if( token == T_LEFT )
416 continue;
417
418 switch( token )
419 {
420 case T_face:
421 NeedSYMBOL();
422 faceName = FromUTF8();
423 NeedRIGHT();
424 break;
425
426 case T_size:
427 {
428 wxSize sz;
429 sz.SetHeight( parseBoardUnits( "text height" ) );
430 sz.SetWidth( parseBoardUnits( "text width" ) );
431 aText->SetTextSize( sz );
432 NeedRIGHT();
433
434 foundTextSize = true;
435 break;
436 }
437
438 case T_line_spacing:
439 aText->SetLineSpacing( parseDouble( "line spacing" ) );
440 NeedRIGHT();
441 break;
442
443 case T_thickness:
444 aText->SetTextThickness( parseBoardUnits( "text thickness" ) );
445 NeedRIGHT();
446 break;
447
448 case T_bold:
449 aText->SetBold( true );
450 break;
451
452 case T_italic:
453 aText->SetItalic( true );
454 break;
455
456 default:
457 Expecting( "face, size, line_spacing, thickness, bold, or italic" );
458 }
459 }
460
461 if( !faceName.IsEmpty() )
462 {
463 aText->SetFont( KIFONT::FONT::GetFont( faceName, aText->IsBold(),
464 aText->IsItalic() ) );
465 }
466
467 break;
468
469 case T_justify:
470 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
471 {
472 if( token == T_LEFT )
473 continue;
474
475 switch( token )
476 {
477 case T_left:
479 break;
480
481 case T_right:
483 break;
484
485 case T_top:
487 break;
488
489 case T_bottom:
491 break;
492
493 case T_mirror:
494 aText->SetMirrored( true );
495 break;
496
497 default:
498 Expecting( "left, right, top, bottom, or mirror" );
499 }
500
501 }
502
503 break;
504
505 case T_hide:
506 aText->SetVisible( false );
507 break;
508
509 default:
510 Expecting( "font, justify, or hide" );
511 }
512 }
513
514 // Text size was not specified in file, force legacy default units
515 // 60mils is 1.524mm
516 if( !foundTextSize )
517 {
518 const double defaultTextSize = 1.524 * pcbIUScale.IU_PER_MM;
519
520 aText->SetTextSize( wxSize( defaultTextSize, defaultTextSize ) );
521 }
522}
bool IsItalic() const
Definition: eda_text.h:130
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:87
void SetMirrored(bool isMirrored)
Definition: eda_text.cpp:224
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition: eda_text.cpp:248
virtual void SetVisible(bool aVisible)
Definition: eda_text.cpp:217
void SetLineSpacing(double aLineSpacing)
Definition: eda_text.cpp:339
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition: eda_text.cpp:185
void SetBold(bool aBold)
Definition: eda_text.cpp:209
bool IsBold() const
Definition: eda_text.h:133
void SetTextSize(const VECTOR2I &aNewSize)
Definition: eda_text.cpp:347
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:163
void SetItalic(bool aItalic)
Definition: eda_text.cpp:201
void SetFont(KIFONT::FONT *aFont)
Definition: eda_text.cpp:331
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition: eda_text.cpp:240
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false)
Definition: font.cpp:65
wxString ConvertToNewOverbarNotation(const wxString &aOldStr)
Convert the old ~...~ overbar notation to the new ~{...} one.
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_V_ALIGN_BOTTOM
@ GR_TEXT_V_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_TOP

References ConvertToNewOverbarNotation(), KIFONT::FONT::GetFont(), EDA_TEXT::GetText(), GR_TEXT_H_ALIGN_CENTER, GR_TEXT_H_ALIGN_LEFT, GR_TEXT_H_ALIGN_RIGHT, GR_TEXT_V_ALIGN_BOTTOM, GR_TEXT_V_ALIGN_CENTER, GR_TEXT_V_ALIGN_TOP, EDA_TEXT::IsBold(), EDA_TEXT::IsItalic(), EDA_IU_SCALE::IU_PER_MM, m_requiredVersion, parseBoardUnits(), parseDouble(), pcbIUScale, EDA_TEXT::SetBold(), EDA_TEXT::SetFont(), EDA_TEXT::SetHorizJustify(), EDA_TEXT::SetItalic(), EDA_TEXT::SetLineSpacing(), EDA_TEXT::SetMirrored(), EDA_TEXT::SetText(), EDA_TEXT::SetTextSize(), EDA_TEXT::SetTextThickness(), EDA_TEXT::SetVertJustify(), and EDA_TEXT::SetVisible().

Referenced by parseFP_TEXT(), parseFP_TEXTBOX(), parsePCB_TEXT(), and parsePCB_TEXTBOX().

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

3567{
3568 try
3569 {
3570 return parseFOOTPRINT_unchecked( aInitialComments );
3571 }
3572 catch( const PARSE_ERROR& parse_error )
3573 {
3574 if( m_tooRecent )
3575 throw FUTURE_FORMAT_ERROR( parse_error, GetRequiredVersion() );
3576 else
3577 throw;
3578 }
3579}
FOOTPRINT * parseFOOTPRINT_unchecked(wxArrayString *aInitialComments=nullptr)

References GetRequiredVersion(), m_tooRecent, and parseFOOTPRINT_unchecked().

Referenced by Parse(), and parseBOARD_unchecked().

◆ parseFOOTPRINT_unchecked()

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

Definition at line 3582 of file pcb_parser.cpp.

3583{
3584 wxCHECK_MSG( CurTok() == T_module || CurTok() == T_footprint, nullptr,
3585 wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as FOOTPRINT." ) );
3586
3587 wxString name;
3588 VECTOR2I pt;
3589 T token;
3590 LIB_ID fpid;
3591 int attributes = 0;
3592
3593 std::unique_ptr<FOOTPRINT> footprint = std::make_unique<FOOTPRINT>( m_board );
3594
3595 std::map<wxString, wxString> properties;
3596
3597 footprint->SetInitialComments( aInitialComments );
3598
3599 token = NextTok();
3600
3601 if( !IsSymbol( token ) && token != T_NUMBER )
3602 Expecting( "symbol|number" );
3603
3604 name = FromUTF8();
3605
3606 if( !name.IsEmpty() && fpid.Parse( name, true ) >= 0 )
3607 {
3608 THROW_IO_ERROR( wxString::Format( _( "Invalid footprint ID in\nfile: %s\nline: %d\n"
3609 "offset: %d." ),
3610 CurSource(), CurLineNumber(), CurOffset() ) );
3611 }
3612
3613 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3614 {
3615 if( token == T_LEFT )
3616 token = NextTok();
3617
3618 switch( token )
3619 {
3620 case T_version:
3621 {
3622 // Theoretically a footprint nested in a PCB could declare its own version, though
3623 // as of writing this comment we don't do that. Just in case, take the greater
3624 // version.
3625 int this_version = parseInt( FromUTF8().mb_str( wxConvUTF8 ) );
3626 NeedRIGHT();
3627 m_requiredVersion = std::max( m_requiredVersion, this_version );
3629 footprint->SetFileFormatVersionAtLoad( this_version );
3630 break;
3631 }
3632
3633 case T_generator:
3634 // We currently ignore the generator when parsing. It is included in the file for manual
3635 // indication of where the footprint came from.
3636 NeedSYMBOL();
3637 NeedRIGHT();
3638 break;
3639
3640 case T_locked:
3641 footprint->SetLocked( true );
3642 break;
3643
3644 case T_placed:
3645 footprint->SetIsPlaced( true );
3646 break;
3647
3648 case T_layer:
3649 {
3650 // Footprints can be only on the front side or the back side.
3651 // but because we can find some stupid layer in file, ensure a
3652 // acceptable layer is set for the footprint
3654 footprint->SetLayer( layer == B_Cu ? B_Cu : F_Cu );
3655 NeedRIGHT();
3656 break;
3657 }
3658
3659 case T_tedit:
3660 parseHex();
3661 NeedRIGHT();
3662 break;
3663
3664 case T_tstamp:
3665 NextTok();
3666 const_cast<KIID&>( footprint->m_Uuid ) = CurStrToKIID();
3667 NeedRIGHT();
3668 break;
3669
3670 case T_at:
3671 pt.x = parseBoardUnits( "X coordinate" );
3672 pt.y = parseBoardUnits( "Y coordinate" );
3673 footprint->SetPosition( pt );
3674 token = NextTok();
3675
3676 if( token == T_NUMBER )
3677 {
3678 footprint->SetOrientation( EDA_ANGLE( parseDouble(), DEGREES_T ) );
3679 NeedRIGHT();
3680 }
3681 else if( token != T_RIGHT )
3682 {
3683 Expecting( T_RIGHT );
3684 }
3685
3686 break;
3687
3688 case T_descr:
3689 NeedSYMBOLorNUMBER(); // some symbols can be 0508, so a number is also a symbol here
3690 footprint->SetDescription( FromUTF8() );
3691 NeedRIGHT();
3692 break;
3693
3694 case T_tags:
3695 NeedSYMBOLorNUMBER(); // some symbols can be 0508, so a number is also a symbol here
3696 footprint->SetKeywords( FromUTF8() );
3697 NeedRIGHT();
3698 break;
3699
3700 case T_property:
3701 properties.insert( parseProperty() );
3702 break;
3703
3704 case T_path:
3705 NeedSYMBOLorNUMBER(); // Paths can be numerical so a number is also a symbol here
3706 footprint->SetPath( KIID_PATH( FromUTF8() ) );
3707 NeedRIGHT();
3708 break;
3709
3710 case T_autoplace_cost90:
3711 case T_autoplace_cost180:
3712 parseInt( "legacy auto-place cost" );
3713 NeedRIGHT();
3714 break;
3715
3716 case T_private_layers:
3717 {
3718 LSET privateLayers;
3719
3720 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3721 {
3722 auto it = m_layerIndices.find( CurStr() );
3723
3724 if( it != m_layerIndices.end() )
3725 privateLayers.set( it->second );
3726 else
3727 Expecting( "layer name" );
3728 }
3729
3730 if( m_requiredVersion < 20220427 )
3731 {
3732 privateLayers.set( Edge_Cuts, false );
3733 privateLayers.set( Margin, false );
3734 }
3735
3736 footprint->SetPrivateLayers( privateLayers );
3737 break;
3738 }
3739
3740 case T_net_tie_pad_groups:
3741 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3742 footprint->AddNetTiePadGroup( CurStr() );
3743
3744 break;
3745
3746 case T_solder_mask_margin:
3747 footprint->SetLocalSolderMaskMargin( parseBoardUnits( "local solder mask margin "
3748 "value" ) );
3749 NeedRIGHT();
3750 break;
3751
3752 case T_solder_paste_margin:
3753 footprint->SetLocalSolderPasteMargin( parseBoardUnits( "local solder paste margin "
3754 "value" ) );
3755 NeedRIGHT();
3756 break;
3757
3758 case T_solder_paste_ratio:
3759 footprint->SetLocalSolderPasteMarginRatio( parseDouble( "local solder paste margin "
3760 "ratio value" ) );
3761 NeedRIGHT();
3762 break;
3763
3764 case T_clearance:
3765 footprint->SetLocalClearance( parseBoardUnits( "local clearance value" ) );
3766 NeedRIGHT();
3767 break;
3768
3769 case T_zone_connect:
3770 footprint->SetZoneConnection((ZONE_CONNECTION) parseInt( "zone connection value" ) );
3771 NeedRIGHT();
3772 break;
3773
3774 case T_thermal_width:
3775 case T_thermal_gap:
3776 // Interestingly, these have never been exposed in the GUI
3777 parseBoardUnits( token );
3778 NeedRIGHT();
3779 break;
3780
3781 case T_attr:
3782 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3783 {
3784 switch( token )
3785 {
3786 case T_virtual: // legacy token prior to version 20200826
3788 break;
3789
3790 case T_through_hole:
3791 attributes |= FP_THROUGH_HOLE;
3792 break;
3793
3794 case T_smd:
3795 attributes |= FP_SMD;
3796 break;
3797
3798 case T_board_only:
3799 attributes |= FP_BOARD_ONLY;
3800 break;
3801
3802 case T_exclude_from_pos_files:
3803 attributes |= FP_EXCLUDE_FROM_POS_FILES;
3804 break;
3805
3806 case T_exclude_from_bom:
3807 attributes |= FP_EXCLUDE_FROM_BOM;
3808 break;
3809
3810 case T_allow_missing_courtyard:
3811 attributes |= FP_ALLOW_MISSING_COURTYARD;
3812 break;
3813
3814 case T_allow_soldermask_bridges:
3815 attributes |= FP_ALLOW_SOLDERMASK_BRIDGES;
3816 break;
3817
3818 default:
3819 Expecting( "through_hole, smd, virtual, board_only, exclude_from_pos_files, "
3820 "exclude_from_bom or allow_solder_mask_bridges" );
3821 }
3822 }
3823
3824 break;
3825
3826 case T_fp_text:
3827 {
3829 text->SetParent( footprint.get() );
3830 EDA_ANGLE orientation = text->GetTextAngle();
3831 orientation -= footprint->GetOrientation();
3832 text->SetTextAngle( orientation );
3833 text->SetDrawCoord();
3834
3835 switch( text->GetType() )
3836 {
3838 footprint->Reference() = *text;
3839 const_cast<KIID&>( footprint->Reference().m_Uuid ) = text->m_Uuid;
3840 delete text;
3841 break;
3842
3844 footprint->Value() = *text;
3845 const_cast<KIID&>( footprint->Value().m_Uuid ) = text->m_Uuid;
3846 delete text;
3847 break;
3848
3849 default:
3850 footprint->Add( text, ADD_MODE::APPEND, true );
3851 }
3852
3853 break;
3854 }
3855
3856 case T_fp_text_box:
3857 {
3858 FP_TEXTBOX* textbox = parseFP_TEXTBOX();
3859 textbox->SetParent( footprint.get() );
3860 textbox->SetDrawCoord();
3861 footprint->Add( textbox, ADD_MODE::APPEND, true );
3862 break;
3863 }
3864
3865 case T_fp_arc:
3866 case T_fp_circle:
3867 case T_fp_curve:
3868 case T_fp_rect:
3869 case T_fp_line:
3870 case T_fp_poly:
3871 {
3872 FP_SHAPE* shape = parseFP_SHAPE();
3873 shape->SetParent( footprint.get() );
3874 shape->SetDrawCoord();
3875 footprint->Add( shape, ADD_MODE::APPEND, true );
3876 break;
3877 }
3878
3879 case T_image:
3880 {
3881 PCB_BITMAP* image = parsePCB_BITMAP( footprint.get() );
3882 footprint->Add( image, ADD_MODE::APPEND, true );
3883 break;
3884 }
3885
3886 case T_dimension:
3887 {
3888 PCB_DIMENSION_BASE* dimension = parseDIMENSION( footprint.get(), true );
3889 footprint->Add( dimension, ADD_MODE::APPEND, true );
3890 break;
3891 }
3892
3893 case T_pad:
3894 {
3895 if( PAD* pad = parsePAD( footprint.get() ) )
3896 {
3897 pt = pad->GetPos0();
3898 RotatePoint( pt, footprint->GetOrientation() );
3899 pad->SetPosition( pt + footprint->GetPosition() );
3900 footprint->Add( pad, ADD_MODE::APPEND, true );
3901 }
3902
3903 break;
3904 }
3905
3906 case T_model:
3907 {
3908 FP_3DMODEL* model = parse3DModel();
3909 footprint->Add3DModel( model );
3910 delete model;
3911 break;
3912 }
3913
3914 case T_zone:
3915 {
3916 ZONE* zone = parseZONE( footprint.get() );
3917 footprint->Add( zone, ADD_MODE::APPEND, true );
3918 break;
3919 }
3920
3921 case T_group:
3922 parseGROUP( footprint.get() );
3923 break;
3924
3925 default:
3926 Expecting( "locked, placed, tedit, tstamp, at, descr, tags, path, "
3927 "autoplace_cost90, autoplace_cost180, solder_mask_margin, "
3928 "solder_paste_margin, solder_paste_ratio, clearance, "
3929 "zone_connect, thermal_gap, attr, fp_text, "
3930 "fp_arc, fp_circle, fp_curve, fp_line, fp_poly, fp_rect, pad, "
3931 "zone, group, generator, version or model" );
3932 }
3933 }
3934
3935 // In legacy files the lack of attributes indicated a through-hole component which was by
3936 // default excluded from pos files. However there was a hack to look for SMD pads and
3937 // consider those "mislabeled through-hole components" and therefore include them in place
3938 // files. We probably don't want to get into that game so we'll just include them by
3939 // default and let the user change it if required.
3940 if( m_requiredVersion < 20200826 && attributes == 0 )
3941 attributes |= FP_THROUGH_HOLE;
3942
3944 {
3945 if( footprint->GetKeywords().StartsWith( wxT( "net tie" ) ) )
3946 {
3947 wxString padGroup;
3948
3949 for( PAD* pad : footprint->Pads() )
3950 {
3951 if( !padGroup.IsEmpty() )
3952 padGroup += wxS( ", " );
3953
3954 padGroup += pad->GetNumber();
3955 }
3956
3957 if( !padGroup.IsEmpty() )
3958 footprint->AddNetTiePadGroup( padGroup );
3959 }
3960 }
3961
3962 footprint->SetAttributes( attributes );
3963
3964 footprint->SetFPID( fpid );
3965 footprint->SetProperties( properties );
3966
3967 return footprint.release();
3968}
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:100
virtual void SetDrawCoord()
Set draw coordinates (absolute values ) from relative coordinates.
Definition: fp_shape.cpp:80
@ TEXT_is_REFERENCE
Definition: fp_text.h:49
@ TEXT_is_VALUE
Definition: fp_text.h:50
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:49
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:50
Definition: pad.h:59
Object to handle a bitmap image that can be inserted in a PCB.
Definition: pcb_bitmap.h:42
Abstract dimension API.
Definition: pcb_dimension.h:96
PAD * parsePAD(FOOTPRINT *aParent=nullptr)
FP_SHAPE * parseFP_SHAPE()
FP_TEXTBOX * parseFP_TEXTBOX()
FP_3DMODEL * parse3DModel()
Definition: pcb_parser.cpp:575
FP_TEXT * parseFP_TEXT()
Handle a list of polygons defining a copper zone.
Definition: zone.h:57
@ DEGREES_T
Definition: eda_angle.h:31
@ FP_SMD
Definition: footprint.h:69
@ FP_ALLOW_MISSING_COURTYARD
Definition: footprint.h:75
@ FP_EXCLUDE_FROM_POS_FILES
Definition: footprint.h:70
@ FP_BOARD_ONLY
Definition: footprint.h:72
@ FP_EXCLUDE_FROM_BOM
Definition: footprint.h:71
@ FP_THROUGH_HOLE
Definition: footprint.h:68
@ FP_ALLOW_SOLDERMASK_BRIDGES
Definition: footprint.h:74
@ Edge_Cuts
Definition: layer_ids.h:113
@ Margin
Definition: layer_ids.h:114
#define SEXPR_BOARD_FILE_VERSION
Current s-expression file format version. 2 was the last legacy format version.
Definition: pcb_plugin.h:133
#define LEGACY_NET_TIES
These were the last to use the keywords field to indicate a net-tie.
Definition: pcb_plugin.h:137
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Definition: trigo.cpp:183
ZONE_CONNECTION
How pads are covered by copper in zone.
Definition: zones.h:50

References _, APPEND, B_Cu, CurStrToKIID(), DEGREES_T, Edge_Cuts, F_Cu, Format(), FP_ALLOW_MISSING_COURTYARD, FP_ALLOW_SOLDERMASK_BRIDGES, FP_BOARD_ONLY, FP_EXCLUDE_FROM_BOM, FP_EXCLUDE_FROM_POS_FILES, FP_SMD, FP_THROUGH_HOLE, image, LEGACY_NET_TIES, m_board, m_layerIndices, m_requiredVersion, m_tooRecent, Margin, name, pad, LIB_ID::Parse(), parse3DModel(), parseBoardItemLayer(), parseBoardUnits(), parseDIMENSION(), parseDouble(), parseFP_SHAPE(), parseFP_TEXT(), parseFP_TEXTBOX(), parseGROUP(), parseHex(), parseInt(), parsePAD(), parsePCB_BITMAP(), parseProperty(), parseZONE(), RotatePoint(), FP_SHAPE::SetDrawCoord(), EDA_ITEM::SetParent(), SEXPR_BOARD_FILE_VERSION, text, FP_TEXT::TEXT_is_REFERENCE, FP_TEXT::TEXT_is_VALUE, THROW_IO_ERROR, VECTOR2< T >::x, and VECTOR2< T >::y.

Referenced by parseFOOTPRINT().

◆ parseFP_SHAPE()

FP_SHAPE * PCB_PARSER::parseFP_SHAPE ( )
private

Definition at line 4204 of file pcb_parser.cpp.

4205{
4206 wxCHECK_MSG( CurTok() == T_fp_arc || CurTok() == T_fp_circle || CurTok() == T_fp_curve ||
4207 CurTok() == T_fp_rect || CurTok() == T_fp_line || CurTok() == T_fp_poly, nullptr,
4208 wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as FP_SHAPE." ) );
4209
4210 VECTOR2I pt;
4212 T token;
4213
4214 std::unique_ptr<FP_SHAPE> shape = std::make_unique<FP_SHAPE>( nullptr );
4215
4216 switch( CurTok() )
4217 {
4218 case T_fp_arc:
4219 shape->SetShape( SHAPE_T::ARC );
4220 token = NextTok();
4221
4222 if( token == T_locked )
4223 {
4224 shape->SetLocked( true );
4225 token = NextTok();
4226 }
4227
4228 if( token != T_LEFT )
4229 Expecting( T_LEFT );
4230
4231 token = NextTok();
4232
4234 {
4235 // In legacy files the start keyword actually gives the arc center...
4236 if( token != T_start )
4237 Expecting( T_start );
4238
4239 pt.x = parseBoardUnits( "X coordinate" );
4240 pt.y = parseBoardUnits( "Y coordinate" );
4241 shape->SetCenter0( pt );
4242 NeedRIGHT();
4243 NeedLEFT();
4244 token = NextTok();
4245
4246 // ... and the end keyword gives the start point of the arc
4247 if( token != T_end )
4248 Expecting( T_end );
4249
4250 pt.x = parseBoardUnits( "X coordinate" );
4251 pt.y = parseBoardUnits( "Y coordinate" );
4252 shape->SetStart0( pt );
4253 NeedRIGHT();
4254 NeedLEFT();
4255 token = NextTok();
4256
4257 if( token != T_angle )
4258 Expecting( T_angle );
4259
4260 shape->SetArcAngleAndEnd0( EDA_ANGLE( parseDouble( "arc angle" ), DEGREES_T ), true );
4261 NeedRIGHT();
4262 }
4263 else
4264 {
4265 VECTOR2I arc_start, arc_mid, arc_end;
4266
4267 if( token != T_start )
4268 Expecting( T_start );
4269
4270 arc_start.x = parseBoardUnits( "X coordinate" );
4271 arc_start.y = parseBoardUnits( "Y coordinate" );
4272 NeedRIGHT();
4273 NeedLEFT();
4274 token = NextTok();
4275
4276 if( token != T_mid )
4277 Expecting( T_mid );
4278
4279 arc_mid.x = parseBoardUnits( "X coordinate" );
4280 arc_mid.y = parseBoardUnits( "Y coordinate" );
4281 NeedRIGHT();
4282 NeedLEFT();
4283 token = NextTok();
4284
4285 if( token != T_end )
4286 Expecting( T_end );
4287
4288 arc_end.x = parseBoardUnits( "X coordinate" );
4289 arc_end.y = parseBoardUnits( "Y coordinate" );
4290 NeedRIGHT();
4291
4292 shape->SetArcGeometry0( arc_start, arc_mid, arc_end );
4293 }
4294
4295 break;
4296
4297 case T_fp_circle:
4298 shape->SetShape( SHAPE_T::CIRCLE );
4299 token = NextTok();
4300
4301 if( token == T_locked )
4302 {
4303 shape->SetLocked( true );
4304 token = NextTok();
4305 }
4306
4307 if( token != T_LEFT )
4308 Expecting( T_LEFT );
4309
4310 token = NextTok();
4311
4312 if( token != T_center )
4313 Expecting( T_center );
4314
4315 pt.x = parseBoardUnits( "X coordinate" );
4316 pt.y = parseBoardUnits( "Y coordinate" );
4317 shape->SetStart0( pt );
4318 NeedRIGHT();
4319 NeedLEFT();
4320 token = NextTok();
4321
4322 if( token != T_end )
4323 Expecting( T_end );
4324
4325 pt.x = parseBoardUnits( "X coordinate" );
4326 pt.y = parseBoardUnits( "Y coordinate" );
4327 shape->SetEnd0( pt );
4328 NeedRIGHT();
4329 break;
4330
4331 case T_fp_curve:
4332 shape->SetShape( SHAPE_T::BEZIER );
4333 token = NextTok();
4334
4335 if( token == T_locked )
4336 {
4337 shape->SetLocked( true );
4338 token = NextTok();
4339 }
4340
4341 if( token != T_LEFT )
4342 Expecting( T_LEFT );
4343
4344 token = NextTok();
4345
4346 if( token != T_pts )
4347 Expecting( T_pts );
4348
4349 shape->SetStart0( parseXY() );
4350 shape->SetBezierC1_0( parseXY() );
4351 shape->SetBezierC2_0( parseXY() );
4352 shape->SetEnd0( parseXY() );
4353 NeedRIGHT();
4354 break;
4355
4356 case T_fp_rect:
4357 shape->SetShape( SHAPE_T::RECT );
4358 token = NextTok();
4359
4360 if( token == T_locked )
4361 {
4362 shape->SetLocked( true );
4363 token = NextTok();
4364 }
4365
4366 if( token != T_LEFT )
4367 Expecting( T_LEFT );
4368
4369 token = NextTok();
4370
4371 if( token != T_start )
4372 Expecting( T_start );
4373
4374 pt.x = parseBoardUnits( "X coordinate" );
4375 pt.y = parseBoardUnits( "Y coordinate" );
4376 shape->SetStart0( pt );
4377
4378 NeedRIGHT();
4379 NeedLEFT();
4380 token = NextTok();
4381
4382 if( token != T_end )
4383 Expecting( T_end );
4384
4385 pt.x = parseBoardUnits( "X coordinate" );
4386 pt.y = parseBoardUnits( "Y coordinate" );
4387 shape->SetEnd0( pt );
4388 NeedRIGHT();
4389 break;
4390
4391 case T_fp_line:
4392 // Default PCB_SHAPE type is S_SEGMENT.
4393 token = NextTok();
4394
4395 if( token == T_locked )
4396 {
4397 shape->SetLocked( true );
4398 token = NextTok();
4399 }
4400
4401 if( token != T_LEFT )
4402 Expecting( T_LEFT );
4403
4404 token = NextTok();
4405
4406 if( token != T_start )
4407 Expecting( T_start );
4408
4409 pt.x = parseBoardUnits( "X coordinate" );
4410 pt.y = parseBoardUnits( "Y coordinate" );
4411 shape->SetStart0( pt );
4412
4413 NeedRIGHT();
4414 NeedLEFT();
4415 token = NextTok();
4416
4417 if( token != T_end )
4418 Expecting( T_end );
4419
4420 pt.x = parseBoardUnits( "X coordinate" );
4421 pt.y = parseBoardUnits( "Y coordinate" );
4422 shape->SetEnd0( pt );
4423 NeedRIGHT();
4424 break;
4425
4426 case T_fp_poly:
4427 {
4428 shape->SetShape( SHAPE_T::POLY );
4429 shape->SetPolyPoints( {} );
4430 SHAPE_LINE_CHAIN& outline = shape->GetPolyShape().Outline( 0 );
4431
4432 token = NextTok();
4433
4434 if( token == T_locked )
4435 {
4436 shape->SetLocked( true );
4437 token = NextTok();
4438 }
4439
4440 if( token != T_LEFT )
4441 Expecting( T_LEFT );
4442
4443 token = NextTok();
4444
4445 if( token != T_pts )
4446 Expecting( T_pts );
4447
4448 while( (token = NextTok() ) != T_RIGHT )
4449 parseOutlinePoints( outline );
4450
4451 break;
4452 }
4453
4454 default:
4455 Expecting( "fp_arc, fp_circle, fp_curve, fp_line, fp_poly, or fp_rect" );
4456 }
4457
4458 bool foundFill = false;
4459
4460 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4461 {
4462 if( token != T_LEFT )
4463 Expecting( T_LEFT );
4464
4465 token = NextTok();
4466
4467 switch( token )
4468 {
4469 case T_layer:
4470 shape->SetLayer( parseBoardItemLayer() );
4471 NeedRIGHT();
4472 break;
4473
4474 case T_width: // legacy token
4475 stroke.SetWidth( parseBoardUnits( T_width ) );
4476 NeedRIGHT();
4477 break;
4478
4479 case T_stroke:
4480 {
4481 STROKE_PARAMS_PARSER strokeParser( reader, pcbIUScale.IU_PER_MM );
4482 strokeParser.SyncLineReaderWith( *this );
4483
4484 strokeParser.ParseStroke( stroke );
4485 SyncLineReaderWith( strokeParser );
4486 break;
4487 }
4488
4489 case T_tstamp:
4490 NextTok();
4491 const_cast<KIID&>( shape->m_Uuid ) = CurStrToKIID();
4492 NeedRIGHT();
4493 break;
4494
4495 case T_fill:
4496 foundFill = true;
4497
4498 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4499 {
4500 if( token == T_LEFT )
4501 token = NextTok();
4502
4503 switch( token )
4504 {
4505 // T_yes was used to indicate filling when first introduced,
4506 // so treat it like a solid fill since that was the only fill available
4507 case T_yes:
4508 case T_solid:
4509 shape->SetFilled( true );
4510 break;
4511
4512 case T_none:
4513 shape->SetFilled( false );
4514 break;
4515
4516 default:
4517 Expecting( "yes, none, solid" );
4518 }
4519 }
4520
4521 break;
4522
4523 // We continue to parse the status field but it is no longer written
4524 case T_status:
4525 shape->SetStatus( static_cast<EDA_ITEM_FLAGS>( parseHex() ) );
4526 NeedRIGHT();
4527 break;
4528
4529 // Continue to process "(locked)" format which was output during 5.99 development
4530 case T_locked:
4531 shape->SetLocked( true );
4532 NeedRIGHT();
4533 break;
4534
4535 default:
4536 Expecting( "layer, width, fill, tstamp, locked, or status" );
4537 }
4538 }
4539
4540 if( !foundFill )
4541 {
4542 // Legacy versions didn't have a filled flag but allowed some shapes to indicate they
4543 // should be filled by specifying a 0 stroke-width.
4544 if( stroke.GetWidth() == 0
4545 && ( shape->GetShape() == SHAPE_T::RECT || shape->GetShape() == SHAPE_T::CIRCLE ) )
4546 {
4547 shape->SetFilled( true );
4548 }
4549 // Polygons on non-Edge_Cuts layers were always filled
4550 else if( shape->GetShape() == SHAPE_T::POLY && shape->GetLayer() != Edge_Cuts )
4551 {
4552 shape->SetFilled( true );
4553 }
4554 }
4555
4556 // Only filled shapes may have a zero line-width. This is not permitted in KiCad but some
4557 // external tools can generate invalid files.
4558 if( stroke.GetWidth() <= 0 && !shape->IsFilled() )
4559 {
4560 stroke.SetWidth( pcbIUScale.mmToIU( DEFAULT_LINE_WIDTH ) );
4561 }
4562
4563 shape->SetStroke( stroke );
4564
4565 return shape.release();
4566}
#define DEFAULT_LINE_WIDTH
void parseOutlinePoints(SHAPE_LINE_CHAIN &aPoly)
Parses possible outline points and stores them into aPoly.
Definition: pcb_parser.cpp:272
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
Simple container to manage line stroke parameters.
Definition: stroke_params.h:88
#define LEGACY_ARC_FORMATTING
These were the last to use old arc formatting.
Definition: pcb_plugin.h:136
constexpr int mmToIU(double mm) const
Definition: base_units.h:89

References ARC, BEZIER, CIRCLE, CurStrToKIID(), DEFAULT_LINE_WIDTH, DEGREES_T, Edge_Cuts, STROKE_PARAMS::GetWidth(), EDA_IU_SCALE::IU_PER_MM, LEGACY_ARC_FORMATTING, m_requiredVersion, EDA_IU_SCALE::mmToIU(), parseBoardItemLayer(), parseBoardUnits(), parseDouble(), parseHex(), parseOutlinePoints(), STROKE_PARAMS_PARSER::ParseStroke(), parseXY(), pcbIUScale, POLY, RECT, STROKE_PARAMS::SetWidth(), SOLID, VECTOR2< T >::x, and VECTOR2< T >::y.

Referenced by parseFOOTPRINT_unchecked().

◆ parseFP_TEXT()

FP_TEXT * PCB_PARSER::parseFP_TEXT ( )
private

Definition at line 3971 of file pcb_parser.cpp.

3972{
3973 wxCHECK_MSG( CurTok() == T_fp_text, nullptr,
3974 wxString::Format( wxT( "Cannot parse %s as FP_TEXT at line %d, offset %d." ),
3975 GetTokenString( CurTok() ), CurLineNumber(), CurOffset() ) );
3976
3977 T token = NextTok();
3978
3979 std::unique_ptr<FP_TEXT> text = std::make_unique<FP_TEXT>( nullptr );
3980
3981 switch( token )
3982 {
3983 case T_reference:
3984 text->SetType( FP_TEXT::TEXT_is_REFERENCE );
3985 break;
3986
3987 case T_value:
3988 text->SetType( FP_TEXT::TEXT_is_VALUE );
3989 break;
3990
3991 case T_user:
3992 break; // Default type is user text.
3993
3994 default:
3995 THROW_IO_ERROR( wxString::Format( _( "Cannot handle footprint text type %s" ),
3996 FromUTF8() ) );
3997 }
3998
3999 token = NextTok();
4000
4001 if( token == T_locked )
4002 {
4003 text->SetLocked( true );
4004 token = NextTok();
4005 }
4006
4007 if( !IsSymbol( token ) && (int) token != DSN_NUMBER )
4008 Expecting( "text value" );
4009
4010 wxString value = FromUTF8();
4011 value.Replace( wxT( "%V" ), wxT( "${VALUE}" ) );
4012 value.Replace( wxT( "%R" ), wxT( "${REFERENCE}" ) );
4013 text->SetText( value );
4014 NeedLEFT();
4015 token = NextTok();
4016
4017 if( token != T_at )
4018 Expecting( T_at );
4019
4020 VECTOR2I pt;
4021
4022 pt.x = parseBoardUnits( "X coordinate" );
4023 pt.y = parseBoardUnits( "Y coordinate" );
4024 text->SetPos0( pt );
4025
4026 NextTok();
4027
4028 if( CurTok() == T_NUMBER )
4029 {
4030 text->SetTextAngle( EDA_ANGLE( parseDouble(), DEGREES_T ) );
4031 NextTok();
4032 }
4033
4034 if( CurTok() == T_unlocked )
4035 {
4036 text->SetKeepUpright( false );
4037 NextTok();
4038 }
4039
4040 if( CurTok() != T_RIGHT )
4041 {
4042 Unexpected( CurText() );
4043 }
4044
4045 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4046 {
4047 if( token == T_LEFT )
4048 token = NextTok();
4049
4050 switch( token )
4051 {
4052 case T_layer:
4053 text->SetLayer( parseBoardItemLayer() );
4054
4055 token = NextTok();
4056
4057 if( token == T_knockout )
4058 {
4059 text->SetIsKnockout( true );
4060 token = NextTok();
4061 }
4062
4063 if( (int) token != DSN_RIGHT )
4064 Expecting( DSN_RIGHT );
4065
4066 break;
4067
4068 case T_hide:
4069 text->SetVisible( false );
4070 break;
4071
4072 case T_effects:
4073 parseEDA_TEXT( static_cast<EDA_TEXT*>( text.get() ) );
4074 break;
4075
4076 case T_render_cache:
4077 parseRenderCache( static_cast<EDA_TEXT*>( text.get() ) );
4078 break;
4079
4080 case T_tstamp:
4081 NextTok();
4082 const_cast<KIID&>( text->m_Uuid ) = CurStrToKIID();
4083 NeedRIGHT();
4084 break;
4085
4086 default:
4087 Expecting( "layer, hide, effects, render_cache or tstamp" );
4088 }
4089 }
4090
4091 return text.release();
4092}
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:72
void parseRenderCache(EDA_TEXT *text)
Parse the render cache for any object derived from EDA_TEXT.
Definition: pcb_parser.cpp:525
void parseEDA_TEXT(EDA_TEXT *aText)
Parse the common settings for any object derived from EDA_TEXT.
Definition: pcb_parser.cpp:384
@ DSN_RIGHT
Definition: dsnlexer.h:66
@ DSN_NUMBER
Definition: dsnlexer.h:65

References _, CurStrToKIID(), DEGREES_T, DSN_NUMBER, DSN_RIGHT, Format(), parseBoardItemLayer(), parseBoardUnits(), parseDouble(), parseEDA_TEXT(), parseRenderCache(), text, FP_TEXT::TEXT_is_REFERENCE, FP_TEXT::TEXT_is_VALUE, THROW_IO_ERROR, VECTOR2< T >::x, and VECTOR2< T >::y.

Referenced by parseFOOTPRINT_unchecked().

◆ parseFP_TEXTBOX()

FP_TEXTBOX * PCB_PARSER::parseFP_TEXTBOX ( )
private

Definition at line 4095 of file pcb_parser.cpp.

4096{
4097 wxCHECK_MSG( CurTok() == T_fp_text_box, nullptr,
4098 wxString::Format( wxT( "Cannot parse %s as FP_TEXTBOX at line %d, offset %d." ),
4099 GetTokenString( CurTok() ), CurLineNumber(), CurOffset() ) );
4100
4101 std::unique_ptr<FP_TEXTBOX> textbox = std::make_unique<FP_TEXTBOX>( nullptr );
4102
4104 T token = NextTok();
4105
4106 if( token == T_locked )
4107 {
4108 textbox->SetLocked( true );
4109 token = NextTok();
4110 }
4111
4112 if( !IsSymbol( token ) && (int) token != DSN_NUMBER )
4113 Expecting( "text value" );
4114
4115 textbox->SetText( FromUTF8() );
4116
4117 NeedLEFT();
4118 token = NextTok();
4119
4120 if( token == T_start )
4121 {
4122 int x = parseBoardUnits( "X coordinate" );
4123 int y = parseBoardUnits( "Y coordinate" );
4124 textbox->SetStart0( VECTOR2I( x, y ) );
4125 NeedRIGHT();
4126
4127 NeedLEFT();
4128 token = NextTok();
4129
4130 if( token != T_end )
4131 Expecting( T_end );
4132
4133 x = parseBoardUnits( "X coordinate" );
4134 y = parseBoardUnits( "Y coordinate" );
4135 textbox->SetEnd0( VECTOR2I( x, y ) );
4136 NeedRIGHT();
4137 }
4138 else if( token == T_pts )
4139 {
4140 textbox->SetShape( SHAPE_T::POLY );
4141 textbox->GetPolyShape().RemoveAllContours();
4142 textbox->GetPolyShape().NewOutline();
4143
4144 while( (token = NextTok() ) != T_RIGHT )
4145 parseOutlinePoints( textbox->GetPolyShape().Outline( 0 ) );
4146 }
4147 else
4148 {
4149 Expecting( "start or pts" );
4150 }
4151
4152 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4153 {
4154 if( token == T_LEFT )
4155 token = NextTok();
4156
4157 switch( token )
4158 {
4159 case T_angle:
4160 textbox->SetTextAngle( EDA_ANGLE( parseDouble( "text box angle" ), DEGREES_T ) );
4161 NeedRIGHT();
4162 break;
4163
4164 case T_stroke:
4165 {
4166 STROKE_PARAMS_PARSER strokeParser( reader, pcbIUScale.IU_PER_MM );
4167 strokeParser.SyncLineReaderWith( *this );
4168
4169 strokeParser.ParseStroke( stroke );
4170 SyncLineReaderWith( strokeParser );
4171 break;
4172 }
4173
4174 case T_layer:
4175 textbox->SetLayer( parseBoardItemLayer() );
4176 NeedRIGHT();
4177 break;
4178
4179 case T_effects:
4180 parseEDA_TEXT( static_cast<EDA_TEXT*>( textbox.get() ) );
4181 break;
4182
4183 case T_render_cache:
4184 parseRenderCache( static_cast<EDA_TEXT*>( textbox.get() ) );
4185 break;
4186
4187 case T_tstamp:
4188 NextTok();
4189 const_cast<KIID&>( textbox->m_Uuid ) = CurStrToKIID();
4190 NeedRIGHT();
4191 break;
4192
4193 default:
4194 Expecting( "angle, width, layer, effects, render_cache or tstamp" );
4195 }
4196 }
4197
4198 textbox->SetStroke( stroke );
4199
4200 return textbox.release();
4201}
VECTOR2< int > VECTOR2I
Definition: vector2d.h:618

References CurStrToKIID(), DEGREES_T, DSN_NUMBER, Format(), EDA_IU_SCALE::IU_PER_MM, parseBoardItemLayer(), parseBoardUnits(), parseDouble(), parseEDA_TEXT(), parseOutlinePoints(), parseRenderCache(), STROKE_PARAMS_PARSER::ParseStroke(), pcbIUScale, POLY, and SOLID.

Referenced by parseFOOTPRINT_unchecked().

◆ parseGeneralSection()

void PCB_PARSER::parseGeneralSection ( )
private

Definition at line 1127 of file pcb_parser.cpp.

1128{
1129 wxCHECK_RET( CurTok() == T_general,
1130 wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
1131 wxT( " as a general section." ) );
1132
1133 T token;
1134
1135 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1136 {
1137 if( token != T_LEFT )
1138 Expecting( T_LEFT );
1139
1140 token = NextTok();
1141
1142 switch( token )
1143 {
1144 case T_thickness:
1146 NeedRIGHT();
1147 break;
1148
1149 default: // Skip everything but the board thickness.
1150 while( ( token = NextTok() ) != T_RIGHT )
1151 {
1152 if( !IsSymbol( token ) && token != T_NUMBER )
1153 Expecting( "symbol or number" );
1154 }
1155 }
1156 }
1157}
void SetBoardThickness(int aThickness)

References BOARD::GetDesignSettings(), m_board, parseBoardUnits(), and BOARD_DESIGN_SETTINGS::SetBoardThickness().

Referenced by parseBOARD_unchecked().

◆ parseGROUP()

void PCB_PARSER::parseGROUP ( BOARD_ITEM aParent)
private

Definition at line 5155 of file pcb_parser.cpp.

5156{
5157 wxCHECK_RET( CurTok() == T_group,
5158 wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PCB_GROUP." ) );
5159
5160 VECTOR2I pt;
5161 T token;
5162
5163 m_groupInfos.push_back( GROUP_INFO() );
5164 GROUP_INFO& groupInfo = m_groupInfos.back();
5165 groupInfo.parent = aParent;
5166
5167 while( ( token = NextTok() ) != T_LEFT )
5168 {
5169 if( token == T_STRING )
5170 groupInfo.name = FromUTF8();
5171 else if( token == T_locked )
5172 groupInfo.locked = true;
5173 else
5174 Expecting( "group name or locked" );
5175 }
5176
5177 token = NextTok();
5178
5179 if( token != T_id )
5180 Expecting( T_id );
5181
5182 NextTok();
5183 groupInfo.uuid = CurStrToKIID();
5184 NeedRIGHT();
5185
5186 NeedLEFT();
5187 token = NextTok();
5188
5189 if( token != T_members )
5190 Expecting( T_members );
5191
5192 while( ( token = NextTok() ) != T_RIGHT )
5193 {
5194 // This token is the Uuid of the item in the group.
5195 // Since groups are serialized at the end of the file/footprint, the Uuid should already
5196 // have been seen and exist in the board.
5197 KIID uuid( CurStr() );
5198 groupInfo.memberUuids.push_back( uuid );
5199 }
5200
5201 NeedRIGHT();
5202}

References CurStrToKIID(), PCB_PARSER::GROUP_INFO::locked, m_groupInfos, PCB_PARSER::GROUP_INFO::memberUuids, PCB_PARSER::GROUP_INFO::name, PCB_PARSER::GROUP_INFO::parent, and PCB_PARSER::GROUP_INFO::uuid.

Referenced by parseBOARD_unchecked(), and parseFOOTPRINT_unchecked().

◆ parseHeader()

void PCB_PARSER::parseHeader ( )
private

Definition at line 1101 of file pcb_parser.cpp.

1102{
1103 wxCHECK_RET( CurTok() == T_kicad_pcb,
1104 wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a header." ) );
1105
1106 NeedLEFT();
1107
1108 T tok = NextTok();
1109
1110 if( tok == T_version )
1111 {
1112 m_requiredVersion = parseInt( FromUTF8().mb_str( wxConvUTF8 ) );
1114 NeedRIGHT();
1115 }
1116 else
1117 {
1118 m_requiredVersion = 20201115; // Last version before we started writing version #s
1119 // in footprint files as well as board files.
1121 }
1122
1124}
void SetFileFormatVersionAtLoad(int aVersion)
Definition: board.h:362

References m_board, m_requiredVersion, m_tooRecent, parseInt(), BOARD::SetFileFormatVersionAtLoad(), and SEXPR_BOARD_FILE_VERSION.

Referenced by parseBOARD_unchecked().

◆ parseHex()

long PCB_PARSER::parseHex ( )
inlineprivate

Definition at line 306 of file pcb_parser.h.

307 {
308 NextTok();
309 return strtol( CurText(), nullptr, 16 );
310 }

Referenced by parseARC(), parseFOOTPRINT_unchecked(), parseFP_SHAPE(), parsePCB_SHAPE(), parsePCB_TRACK(), parsePCB_VIA(), and parseSetup().

◆ parseInt() [1/2]

int PCB_PARSER::parseInt ( )
inlineprivate

Definition at line 295 of file pcb_parser.h.

296 {
297 return (int)strtol( CurText(), nullptr, 10 );
298 }

Referenced by parseARC(), parseDefaults(), parseDIMENSION(), parseFOOTPRINT_unchecked(), parseHeader(), parseInt(), parseLayer(), parseNETINFO_ITEM(), parsePAD(), parsePCB_TRACK(), parsePCB_VIA(), parseTITLE_BLOCK(), and parseZONE().

◆ parseInt() [2/2]

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

Definition at line 300 of file pcb_parser.h.

301 {
302 NeedNUMBER( aExpected );
303 return parseInt();
304 }

References parseInt().

◆ parseLayer()

void PCB_PARSER::parseLayer ( LAYER aLayer)
private

Definition at line 1326 of file pcb_parser.cpp.

1327{
1328 T token;
1329
1330 std::string name;
1331 std::string userName;
1332 std::string type;
1333 bool isVisible = true;
1334
1335 aLayer->clear();
1336
1337 if( CurTok() != T_LEFT )
1338 Expecting( T_LEFT );
1339
1340 // this layer_num is not used, we DO depend on LAYER_T however.
1341 int layer_num = parseInt( "layer index" );
1342
1343 NeedSYMBOLorNUMBER();
1344 name = CurText();
1345
1346 NeedSYMBOL();
1347 type = CurText();
1348
1349 token = NextTok();
1350
1351 // @todo Figure out why we are looking for a hide token in the layer definition.
1352 if( token == T_hide )
1353 {
1354 isVisible = false;
1355 NeedRIGHT();
1356 }
1357 else if( token == T_STRING )
1358 {
1359 userName = CurText();
1360 NeedRIGHT();
1361 }
1362 else if( token != T_RIGHT )
1363 {
1364 Expecting( "hide, user defined name, or )" );
1365 }
1366
1367 aLayer->m_name = FROM_UTF8( name.c_str() );
1368 aLayer->m_type = LAYER::ParseType( type.c_str() );
1369 aLayer->m_number = layer_num;
1370 aLayer->m_visible = isVisible;
1371
1372 if( !userName.empty() )
1373 aLayer->m_userName = FROM_UTF8( userName.c_str() );
1374
1375 // The canonical name will get reset back to the default for copper layer on the next
1376 // save. The user defined name is now a separate optional layer token from the canonical
1377 // name.
1378 if( aLayer->m_name != LSET::Name( static_cast<PCB_LAYER_ID>( aLayer->m_number ) ) )
1379 aLayer->m_userName = aLayer->m_name;
1380}
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
static LAYER_T ParseType(const char *aType)
Convert a string to a LAYER_T.
Definition: board.cpp:530
void clear()
Definition: board.h:162
LAYER_T m_type
The type of the layer.
Definition: board.h:184
wxString m_name
The canonical name of the layer.
Definition: board.h:182
wxString m_userName
The user defined name of the layer.
Definition: board.h:183
bool m_visible
Definition: board.h:185
int m_number
The layer ID.
Definition: board.h:186

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().

Referenced by parseLayers().

◆ parseLayers()

void PCB_PARSER::parseLayers ( )
private

Definition at line 1654 of file pcb_parser.cpp.

1655{
1656 wxCHECK_RET( CurTok() == T_layers,
1657 wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as layers." ) );
1658
1659 T token;
1660 LSET visibleLayers;
1661 LSET enabledLayers;
1662 int copperLayerCount = 0;
1663 LAYER layer;
1664 bool anyHidden = false;
1665
1666 std::unordered_map< std::string, std::string > v3_layer_names;
1667 std::vector<LAYER> cu;
1668
1669 createOldLayerMapping( v3_layer_names );
1670
1671 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1672 {
1673 parseLayer( &layer );
1674
1675 if( layer.m_type == LT_UNDEFINED ) // it's a non-copper layer
1676 break;
1677
1678 cu.push_back( layer ); // it's copper
1679 }
1680
1681 // All Cu layers are parsed, but not the non-cu layers here.
1682
1683 // The original *.kicad_pcb file format and the inverted
1684 // Cu stack format both have all the Cu layers first, so use this
1685 // trick to handle either. The layer number in the (layers ..)
1686 // s-expression element are ignored.
1687 if( cu.size() )
1688 {
1689 // Rework the layer numbers, which changed when the Cu stack
1690 // was flipped. So we instead use position in the list.
1691 cu[cu.size()-1].m_number = B_Cu;
1692
1693 for( unsigned i=0; i < cu.size()-1; ++i )
1694 {
1695 cu[i].m_number = i;
1696 }
1697
1698 for( std::vector<LAYER>::const_iterator it = cu.begin(); it<cu.end(); ++it )
1699 {
1700 enabledLayers.set( it->m_number );
1701
1702 if( it->m_visible )
1703 visibleLayers.set( it->m_number );
1704 else
1705 anyHidden = true;
1706
1707 m_board->SetLayerDescr( PCB_LAYER_ID( it->m_number ), *it );
1708
1709 UTF8 name = it->m_name;
1710
1711 m_layerIndices[ name ] = PCB_LAYER_ID( it->m_number );
1712 m_layerMasks[ name ] = LSET( PCB_LAYER_ID( it->m_number ) );
1713 }
1714
1715 copperLayerCount = cu.size();
1716 }
1717
1718 // process non-copper layers
1719 while( token != T_RIGHT )
1720 {
1721 LAYER_ID_MAP::const_iterator it = m_layerIndices.find( UTF8( layer.m_name ) );
1722
1723 if( it == m_layerIndices.end() )
1724 {
1725 auto new_layer_it = v3_layer_names.find( layer.m_name.ToStdString() );
1726
1727 if( new_layer_it != v3_layer_names.end() )
1728 it = m_layerIndices.find( new_layer_it->second );
1729
1730 if( it == m_layerIndices.end() )
1731 {
1732 wxString error;
1733 error.Printf( _( "Layer '%s' in file '%s' at line %d is not in fixed layer hash." ),
1734 layer.m_name,
1735 CurSource(),
1736 CurLineNumber(),
1737 CurOffset() );
1738
1739 THROW_IO_ERROR( error );
1740 }
1741
1742 // If we are here, then we have found a translated layer name. Put it in the maps
1743 // so that items on this layer get the appropriate layer ID number.
1744 m_layerIndices[ UTF8( layer.m_name ) ] = it->second;
1745 m_layerMasks[ UTF8( layer.m_name ) ] = it->second;
1746 layer.m_name = it->first;
1747 }
1748
1749 layer.m_number = it->second;
1750 enabledLayers.set( layer.m_number );
1751
1752 if( layer.m_visible )
1753 visibleLayers.set( layer.m_number );
1754 else
1755 anyHidden = true;
1756
1757 m_board->SetLayerDescr( it->second, layer );
1758
1759 token = NextTok();
1760
1761 if( token != T_LEFT )
1762 break;
1763
1764 parseLayer( &layer );
1765 }
1766
1767 // We need at least 2 copper layers and there must be an even number of them.
1768 if( copperLayerCount < 2 || (copperLayerCount % 2) != 0 )
1769 {
1770 wxString err = wxString::Format( _( "%d is not a valid layer count" ), copperLayerCount );
1771
1772 THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
1773 }
1774
1775 m_board->SetCopperLayerCount( copperLayerCount );
1776 m_board->SetEnabledLayers( enabledLayers );
1777
1778 // Only set this if any layers were explicitly marked as hidden. Otherwise, we want to leave
1779 // this alone; default visibility will show everything
1780 if( anyHidden )
1781 m_board->m_LegacyVisibleLayers = visibleLayers;
1782}
@ LT_UNDEFINED
Definition: board.h:144
void SetEnabledLayers(LSET aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:589
bool SetLayerDescr(PCB_LAYER_ID aIndex, const LAYER &aLayer)
Return the type of the copper layer given by aLayer.
Definition: board.cpp:424
LSET m_LegacyVisibleLayers
Visibility settings stored in board prior to 6.0, only used for loading legacy files.
Definition: board.h:338
void SetCopperLayerCount(int aCount)
Definition: board.cpp:551
void createOldLayerMapping(std::unordered_map< std::string, std::string > &aMap)
Create a mapping from the (short-lived) bug where layer names were translated.
void parseLayer(LAYER *aLayer)
An 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to and fro...
Definition: utf8.h:71
Container to hold information pertinent to a layer of a BOARD.
Definition: board.h:156

References _, B_Cu, createOldLayerMapping(), Format(), LT_UNDEFINED, m_board, m_layerIndices, m_layerMasks, BOARD::m_LegacyVisibleLayers, LAYER::m_name, LAYER::m_number, LAYER::m_type, LAYER::m_visible, name, parseLayer(), BOARD::SetCopperLayerCount(), BOARD::SetEnabledLayers(), BOARD::SetLayerDescr(), THROW_IO_ERROR, and THROW_PARSE_ERROR.

Referenced by parseBOARD_unchecked().

◆ parseNETCLASS()

void PCB_PARSER::parseNETCLASS ( )
private

Definition at line 2361 of file pcb_parser.cpp.

2362{
2363 wxCHECK_RET( CurTok() == T_net_class,
2364 wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as net class." ) );
2365
2366 T token;
2367
2368 std::shared_ptr<NETCLASS> nc = std::make_shared<NETCLASS>( wxEmptyString );
2369
2370 // Read netclass name (can be a name or just a number like track width)
2371 NeedSYMBOLorNUMBER();
2372 nc->SetName( FromUTF8() );
2373 NeedSYMBOL();
2374 nc->SetDescription( FromUTF8() );
2375
2376 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2377 {
2378 if( token != T_LEFT )
2379 Expecting( T_LEFT );
2380
2381 token = NextTok();
2382
2383 switch( token )
2384 {
2385 case T_clearance:
2386 nc->SetClearance( parseBoardUnits( T_clearance ) );
2387 break;
2388
2389 case T_trace_width:
2390 nc->SetTrackWidth( parseBoardUnits( T_trace_width ) );
2391 break;
2392
2393 case T_via_dia:
2394 nc->SetViaDiameter( parseBoardUnits( T_via_dia ) );
2395 break;
2396
2397 case T_via_drill:
2398 nc->SetViaDrill( parseBoardUnits( T_via_drill ) );
2399 break;
2400
2401 case T_uvia_dia:
2402 nc->SetuViaDiameter( parseBoardUnits( T_uvia_dia ) );
2403 break;
2404
2405 case T_uvia_drill:
2406 nc->SetuViaDrill( parseBoardUnits( T_uvia_drill ) );
2407 break;
2408
2409 case T_diff_pair_width:
2410 nc->SetDiffPairWidth( parseBoardUnits( T_diff_pair_width ) );
2411 break;
2412
2413 case T_diff_pair_gap:
2414 nc->SetDiffPairGap( parseBoardUnits( T_diff_pair_gap ) );
2415 break;
2416
2417 case T_add_net:
2418 {
2419 NeedSYMBOLorNUMBER();
2420
2421 wxString netName = FromUTF8();
2422
2423 // Convert overbar syntax from `~...~` to `~{...}`. These were left out of the
2424 // first merge so the version is a bit later.
2425 if( m_requiredVersion < 20210606 )
2426 netName = ConvertToNewOverbarNotation( FromUTF8() );
2427
2428 m_board->GetDesignSettings().m_NetSettings->m_NetClassPatternAssignments.push_back(
2429 {
2430 std::make_unique<EDA_COMBINED_MATCHER>( netName, CTX_NETCLASS ),
2431 nc->GetName()
2432 } );
2433
2434 break;
2435 }
2436
2437 default:
2438 Expecting( "clearance, trace_width, via_dia, via_drill, uvia_dia, uvia_drill, "
2439 "diff_pair_width, diff_pair_gap or add_net" );
2440 }
2441
2442 NeedRIGHT();
2443 }
2444
2445 std::shared_ptr<NET_SETTINGS>& netSettings = m_board->GetDesignSettings().m_NetSettings;
2446
2447 if( netSettings->m_NetClasses.count( nc->GetName() ) )
2448 {
2449 // Must have been a name conflict, this is a bad board file.
2450 // User may have done a hand edit to the file.
2451 wxString error;
2452 error.Printf( _( "Duplicate NETCLASS name '%s' in file '%s' at line %d, offset %d." ),
2453 nc->GetName().GetData(), CurSource().GetData(), CurLineNumber(),
2454 CurOffset() );
2455 THROW_IO_ERROR( error );
2456 }
2457 else if( nc->GetName() == netSettings->m_DefaultNetClass->GetName() )
2458 {
2459 netSettings->m_DefaultNetClass = nc;
2460 }
2461 else
2462 {
2463 netSettings->m_NetClasses[ nc->GetName() ] = nc;
2464 }
2465}
std::shared_ptr< NET_SETTINGS > m_NetSettings
@ CTX_NETCLASS

References _, ConvertToNewOverbarNotation(), CTX_NETCLASS, BOARD::GetDesignSettings(), m_board, BOARD_DESIGN_SETTINGS::m_NetSettings, m_requiredVersion, parseBoardUnits(), and THROW_IO_ERROR.

Referenced by parseBOARD_unchecked().

◆ parseNETINFO_ITEM()

void PCB_PARSER::parseNETINFO_ITEM ( )
private

Definition at line 2330 of file pcb_parser.cpp.

2331{
2332 wxCHECK_RET( CurTok() == T_net,
2333 wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as net." ) );
2334
2335 int netCode = parseInt( "net number" );
2336
2337 NeedSYMBOLorNUMBER();
2338 wxString name = FromUTF8();
2339
2340 // Convert overbar syntax from `~...~` to `~{...}`. These were left out of the first merge
2341 // so the version is a bit later.
2342 if( m_requiredVersion < 20210606 )
2344
2345 NeedRIGHT();
2346
2347 // net 0 should be already in list, so store this net
2348 // if it is not the net 0, or if the net 0 does not exists.
2349 // (TODO: a better test.)
2351 {
2352 NETINFO_ITEM* net = new NETINFO_ITEM( m_board, name, netCode );
2353 m_board->Add( net, ADD_MODE::INSERT, true );
2354
2355 // Store the new code mapping
2356 pushValueIntoMap( netCode, net->GetNetCode() );
2357 }
2358}
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1460
Handle the data for a net.
Definition: netinfo.h:67
int GetNetCode() const
Definition: netinfo.h:114
static const int UNCONNECTED
Constant that forces initialization of a netinfo item to the NETINFO_ITEM ORPHANED (typically -1) whe...
Definition: netinfo.h:382
void pushValueIntoMap(int aIndex, int aValue)
Add aValue value in netcode mapping (m_netCodes) at aIndex.
Definition: pcb_parser.cpp:166

References BOARD::Add(), ConvertToNewOverbarNotation(), BOARD::FindNet(), NETINFO_ITEM::GetNetCode(), INSERT, m_board, m_requiredVersion, name, parseInt(), pushValueIntoMap(), and NETINFO_LIST::UNCONNECTED.

Referenced by parseBOARD_unchecked().

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

273{
274 if( CurTok() != T_LEFT )
275 NeedLEFT();
276
277 T token = NextTok();
278
279 switch( token )
280 {
281 case T_xy:
282 {
283 int x = parseBoardUnits( "X coordinate" );
284 int y = parseBoardUnits( "Y coordinate" );
285
286 NeedRIGHT();
287
288 aPoly.Append( x, y );
289 break;
290 }
291 case T_arc:
292 {
293 bool has_start = false;
294 bool has_mid = false;
295 bool has_end = false;
296
297 VECTOR2I arc_start, arc_mid, arc_end;
298
299 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
300 {
301 if( token != T_LEFT )
302 Expecting( T_LEFT );
303
304 token = NextTok();
305
306 switch( token )
307 {
308 case T_start:
309 arc_start.x = parseBoardUnits( "start x" );
310 arc_start.y = parseBoardUnits( "start y" );
311 has_start = true;
312 break;
313
314 case T_mid:
315 arc_mid.x = parseBoardUnits( "mid x" );
316 arc_mid.y = parseBoardUnits( "mid y" );
317 has_mid = true;
318 break;
319
320 case T_end:
321 arc_end.x = parseBoardUnits( "end x" );
322 arc_end.y = parseBoardUnits( "end y" );
323 has_end = true;
324 break;
325
326 default:
327 Expecting( "start, mid or end" );
328 }
329
330 NeedRIGHT();
331 }
332
333 if( !has_start )
334 Expecting( "start" );
335
336 if( !has_mid )
337 Expecting( "mid" );
338
339 if( !has_end )
340 Expecting( "end" );
341
342 SHAPE_ARC arc( arc_start, arc_mid, arc_end, 0 );
343
344 aPoly.Append( arc );
345
346 if( token != T_RIGHT )
347 Expecting( T_RIGHT );
348
349 break;
350 }
351 default:
352 Expecting( "xy or arc" );
353 }
354}
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(), parseBoardUnits(), VECTOR2< T >::x, and VECTOR2< T >::y.

Referenced by parseFP_SHAPE(), parseFP_TEXTBOX(), parsePCB_SHAPE(), parsePCB_TEXTBOX(), parseRenderCache(), and parseZONE().

◆ parsePAD()

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

Definition at line 4569 of file pcb_parser.cpp.

4570{
4571 wxCHECK_MSG( CurTok() == T_pad, nullptr,
4572 wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PAD." ) );
4573
4574 VECTOR2I sz;
4575 VECTOR2I pt;
4576
4577 std::unique_ptr<PAD> pad = std::make_unique<PAD>( aParent );
4578
4579 // File only contains a token if KeepTopBottom is true
4580 pad->SetKeepTopBottom( false );
4581
4582 NeedSYMBOLorNUMBER();
4583 pad->SetNumber( FromUTF8() );
4584
4585 T token = NextTok();
4586
4587 switch( token )
4588 {
4589 case T_thru_hole:
4590 pad->SetAttribute( PAD_ATTRIB::PTH );
4591 break;
4592
4593 case T_smd:
4594 pad->SetAttribute( PAD_ATTRIB::SMD );
4595
4596 // Default PAD object is thru hole with drill.
4597 // SMD pads have no hole
4598 pad->SetDrillSize( VECTOR2I( 0, 0 ) );
4599 break;
4600
4601 case T_connect:
4602 pad->SetAttribute( PAD_ATTRIB::CONN );
4603
4604 // Default PAD object is thru hole with drill.
4605 // CONN pads have no hole
4606 pad->SetDrillSize( VECTOR2I( 0, 0 ) );
4607 break;
4608
4609 case T_np_thru_hole:
4610 pad->SetAttribute( PAD_ATTRIB::NPTH );
4611 break;
4612
4613 default:
4614 Expecting( "thru_hole, smd, connect, or np_thru_hole" );
4615 }
4616
4617 token = NextTok();
4618
4619 switch( token )
4620 {
4621 case T_circle:
4622 pad->SetShape( PAD_SHAPE::CIRCLE );
4623 break;
4624
4625 case T_rect:
4626 pad->SetShape( PAD_SHAPE::RECT );
4627 break;
4628
4629 case T_oval:
4630 pad->SetShape( PAD_SHAPE::OVAL );
4631 break;
4632
4633 case T_trapezoid:
4634 pad->SetShape( PAD_SHAPE::TRAPEZOID );
4635 break;
4636
4637 case T_roundrect:
4638 // Note: the shape can be PAD_SHAPE::ROUNDRECT or PAD_SHAPE::CHAMFERED_RECT
4639 // (if chamfer parameters are found later in pad descr.)
4640 pad->SetShape( PAD_SHAPE::ROUNDRECT );
4641 break;
4642
4643 case T_custom:
4644 pad->SetShape( PAD_SHAPE::CUSTOM );
4645 break;
4646
4647 default:
4648 Expecting( "circle, rectangle, roundrect, oval, trapezoid or custom" );
4649 }
4650
4651 if( pad->GetShape() == PAD_SHAPE::CIRCLE )
4652 pad->SetThermalSpokeAngle( ANGLE_45 );
4653 else if( pad->GetShape() == PAD_SHAPE::CUSTOM && pad->GetAnchorPadShape() == PAD_SHAPE::CIRCLE )
4654 pad->SetThermalSpokeAngle( ANGLE_45 );
4655 else
4656 pad->SetThermalSpokeAngle( ANGLE_90 );
4657
4658 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4659 {
4660 if( token == T_locked )
4661 {
4662 // Pad locking is now a session preference
4663 token = NextTok();
4664 }
4665
4666 if( token != T_LEFT )
4667 Expecting( T_LEFT );
4668
4669 token = NextTok();
4670
4671 switch( token )
4672 {
4673 case T_size:
4674 sz.x = parseBoardUnits( "width value" );
4675 sz.y = parseBoardUnits( "height value" );
4676 pad->SetSize( sz );
4677 NeedRIGHT();
4678 break;
4679
4680 case T_at:
4681 pt.x = parseBoardUnits( "X coordinate" );
4682 pt.y = parseBoardUnits( "Y coordinate" );
4683 pad->SetPos0( pt );
4684 token = NextTok();
4685
4686 if( token == T_NUMBER )
4687 {
4688 pad->SetOrientation( EDA_ANGLE( parseDouble(), DEGREES_T ) );
4689 NeedRIGHT();
4690 }
4691 else if( token != T_RIGHT )
4692 {
4693 Expecting( ") or angle value" );
4694 }
4695
4696 break;
4697
4698 case T_rect_delta:
4699 {
4700 wxSize delta;
4701 delta.SetWidth( parseBoardUnits( "rectangle delta width" ) );
4702 delta.SetHeight( parseBoardUnits( "rectangle delta height" ) );
4703 pad->SetDelta( delta );
4704 NeedRIGHT();
4705 break;
4706 }
4707
4708 case T_drill:
4709 {
4710 bool haveWidth = false;
4711 VECTOR2I drillSize = pad->GetDrillSize();
4712
4713 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4714 {
4715 if( token == T_LEFT )
4716 token = NextTok();
4717
4718 switch( token )
4719 {
4720 case T_oval: pad->SetDrillShape( PAD_DRILL_SHAPE_OBLONG ); break;
4721
4722 case T_NUMBER:
4723 {
4724 if( !haveWidth )
4725 {
4726 drillSize.x = parseBoardUnits();
4727
4728 // If height is not defined the width and height are the same.
4729 drillSize.y = drillSize.x;
4730 haveWidth = true;
4731 }
4732 else
4733 {
4734 drillSize.y = parseBoardUnits();
4735 }
4736 }
4737
4738 break;
4739
4740 case T_offset:
4741 pt.x = parseBoardUnits( "drill offset x" );
4742 pt.y = parseBoardUnits( "drill offset y" );
4743 pad->SetOffset( pt );
4744 NeedRIGHT();
4745 break;
4746
4747 default:
4748 Expecting( "oval, size, or offset" );
4749 }
4750 }
4751
4752 // This fixes a bug caused by setting the default PAD drill size to a value other
4753 // than 0 used to fix a bunch of debug assertions even though it is defined as a
4754 // through hole pad. Wouldn't a though hole pad with no drill be a surface mount
4755 // pad (or a conn pad which is a smd pad with no solder paste)?
4756 if( ( pad->GetAttribute() != PAD_ATTRIB::SMD )
4757 && ( pad->GetAttribute() != PAD_ATTRIB::CONN ) )
4758 pad->SetDrillSize( drillSize );
4759 else
4760 pad->SetDrillSize( wxSize( 0, 0 ) );
4761
4762 break;
4763 }
4764
4765 case T_layers:
4766 {
4767 LSET layerMask = parseBoardItemLayersAsMask();
4768 pad->SetLayerSet( layerMask );
4769 break;
4770 }
4771
4772 case T_net:
4773 if( ! pad->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
4774 {
4775 wxLogError( _( "Invalid net ID in\nfile: %s\nline: %d offset: %d" ),
4776 CurSource(), CurLineNumber(), CurOffset() );
4777 }
4778
4779 NeedSYMBOLorNUMBER();
4780
4781 // Test validity of the netname in file for netcodes expected having a net name
4782 if( m_board && pad->GetNetCode() > 0 )
4783 {
4784 wxString netName( FromUTF8() );
4785
4786 // Convert overbar syntax from `~...~` to `~{...}`. These were left out of the
4787 // first merge so the version is a bit later.
4788 if( m_requiredVersion < 20210606 )
4789 netName = ConvertToNewOverbarNotation( netName );
4790
4791 if( netName != m_board->FindNet( pad->GetNetCode() )->GetNetname() )
4792 {
4793 pad->SetNetCode( NETINFO_LIST::ORPHANED, /* aNoAssert */ true );
4794 wxLogError( _( "Net name doesn't match ID in\nfile: %s\nline: %d offset: %d" ),
4795 CurSource(), CurLineNumber(), CurOffset() );
4796 }
4797 }
4798
4799 NeedRIGHT();
4800 break;
4801
4802 case T_pinfunction:
4803 NeedSYMBOLorNUMBER();
4804 pad->SetPinFunction( FromUTF8() );
4805 NeedRIGHT();
4806 break;
4807
4808 case T_pintype:
4809 NeedSYMBOLorNUMBER();
4810 pad->SetPinType( FromUTF8() );
4811 NeedRIGHT();
4812 break;
4813
4814 case T_die_length:
4815 pad->SetPadToDieLength( parseBoardUnits( T_die_length ) );
4816 NeedRIGHT();
4817 break;
4818
4819 case T_solder_mask_margin:
4820 pad->SetLocalSolderMaskMargin( parseBoardUnits( T_solder_mask_margin ) );
4821 NeedRIGHT();
4822 break;
4823
4824 case T_solder_paste_margin:
4825 pad->SetLocalSolderPasteMargin( parseBoardUnits( T_solder_paste_margin ) );
4826 NeedRIGHT();
4827 break;
4828
4829 case T_solder_paste_margin_ratio:
4830 pad->SetLocalSolderPasteMarginRatio(
4831 parseDouble( "pad local solder paste margin ratio value" ) );
4832 NeedRIGHT();
4833 break;
4834
4835 case T_clearance:
4836 pad->SetLocalClearance( parseBoardUnits( "local clearance value" ) );
4837 NeedRIGHT();
4838 break;
4839
4840 case T_zone_connect:
4841 pad->SetZoneConnection( (ZONE_CONNECTION) parseInt( "zone connection value" ) );
4842 NeedRIGHT();
4843 break;
4844
4845 case T_thermal_width: // legacy token
4846 case T_thermal_bridge_width:
4847 pad->SetThermalSpokeWidth( parseBoardUnits( token ) );
4848 NeedRIGHT();
4849 break;
4850
4851 case T_thermal_bridge_angle:
4852 pad->SetThermalSpokeAngle( EDA_ANGLE( parseDouble( "thermal spoke angle" ), DEGREES_T ) );
4853 NeedRIGHT();
4854 break;
4855
4856
4857 case T_thermal_gap:
4858 pad->SetThermalGap( parseBoardUnits( "thermal relief gap value" ) );
4859 NeedRIGHT();
4860 break;
4861
4862 case T_roundrect_rratio:
4863 pad->SetRoundRectRadiusRatio( parseDouble( "roundrect radius ratio" ) );
4864 NeedRIGHT();
4865 break;
4866
4867 case T_chamfer_ratio:
4868 pad->SetChamferRectRatio( parseDouble( "chamfer ratio" ) );
4869
4870 if( pad->GetChamferRectRatio() > 0 )
4871 pad->SetShape( PAD_SHAPE::CHAMFERED_RECT );
4872
4873 NeedRIGHT();
4874 break;
4875
4876 case T_chamfer:
4877 {
4878 int chamfers = 0;
4879 bool end_list = false;
4880
4881 while( !end_list )
4882 {
4883 token = NextTok();
4884
4885 switch( token )
4886 {
4887 case T_top_left:
4888 chamfers |= RECT_CHAMFER_TOP_LEFT;
4889 break;
4890
4891 case T_top_right:
4892 chamfers |= RECT_CHAMFER_TOP_RIGHT;
4893 break;
4894
4895 case T_bottom_left:
4896 chamfers |= RECT_CHAMFER_BOTTOM_LEFT;
4897 break;
4898
4899 case T_bottom_right:
4900 chamfers |= RECT_CHAMFER_BOTTOM_RIGHT;
4901 break;
4902
4903 case T_RIGHT:
4904 pad->SetChamferPositions( chamfers );
4905 end_list = true;
4906 break;
4907
4908 default:
4909 Expecting( "chamfer_top_left chamfer_top_right chamfer_bottom_left or "
4910 "chamfer_bottom_right" );
4911 }
4912 }
4913
4914 if( pad->GetChamferPositions() != RECT_NO_CHAMFER )
4915 pad->SetShape( PAD_SHAPE::CHAMFERED_RECT );
4916
4917 break;
4918 }
4919
4920 case T_property:
4921 while( token != T_RIGHT )
4922 {
4923 token = NextTok();
4924
4925 switch( token )
4926 {
4927 case T_pad_prop_bga: pad->SetProperty( PAD_PROP::BGA ); break;
4928 case T_pad_prop_fiducial_glob: pad->SetProperty( PAD_PROP::FIDUCIAL_GLBL ); break;
4929 case T_pad_prop_fiducial_loc: pad->SetProperty( PAD_PROP::FIDUCIAL_LOCAL ); break;
4930 case T_pad_prop_testpoint: pad->SetProperty( PAD_PROP::TESTPOINT ); break;
4931 case T_pad_prop_castellated: pad->SetProperty( PAD_PROP::CASTELLATED ); break;
4932 case T_pad_prop_heatsink: pad->SetProperty( PAD_PROP::HEATSINK ); break;
4933 case T_none: pad->SetProperty( PAD_PROP::NONE ); break;
4934 case T_RIGHT: break;
4935
4936 default:
4937#if 0 // Currently: skip unknown property
4938 Expecting( "pad_prop_bga pad_prop_fiducial_glob pad_prop_fiducial_loc"
4939 " pad_prop_heatsink or pad_prop_castellated" );
4940#endif
4941 break;
4942 }
4943 }
4944
4945 break;
4946
4947 case T_options:
4948 parsePAD_option( pad.get() );
4949 break;
4950
4951 case T_primitives:
4952 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4953 {
4954 if( token == T_LEFT )
4955 token = NextTok();
4956
4957 // Currently, I am using parsePCB_SHAPE() to read basic shapes parameters,
4958 // because they are the same as a PCB_SHAPE.
4959 // However it could be better to write a specific parser, to avoid possible issues
4960 // if the PCB_SHAPE parser is modified.
4961 PCB_SHAPE* dummyShape = nullptr;
4962
4963 switch( token )
4964 {
4965 case T_gr_arc:
4966 dummyShape = parsePCB_SHAPE();
4967 pad->AddPrimitiveArc( dummyShape->GetCenter(), dummyShape->GetStart(),
4968 dummyShape->GetArcAngle(), dummyShape->GetWidth() );
4969 break;
4970
4971 case T_gr_line:
4972 dummyShape = parsePCB_SHAPE();
4973 pad->AddPrimitiveSegment( dummyShape->GetStart(), dummyShape->GetEnd(),
4974 dummyShape->GetWidth() );
4975 break;
4976
4977 case T_gr_circle:
4978 dummyShape = parsePCB_SHAPE();
4979 pad->AddPrimitiveCircle( dummyShape->GetCenter(), dummyShape->GetRadius(),
4980 dummyShape->GetWidth(), dummyShape->IsFilled() );
4981 break;
4982
4983 case T_gr_rect:
4984 dummyShape = parsePCB_SHAPE();
4985 pad->AddPrimitiveRect( dummyShape->GetStart(), dummyShape->GetEnd(),
4986 dummyShape->GetWidth(), dummyShape->IsFilled() );
4987 break;
4988
4989 case T_gr_bbox:
4990 dummyShape = parsePCB_SHAPE();
4991 pad->AddPrimitiveAnnotationBox( dummyShape->GetStart(), dummyShape->GetEnd() );
4992 break;
4993
4994 case T_gr_poly:
4995 dummyShape = parsePCB_SHAPE();
4996 pad->AddPrimitivePoly( dummyShape->GetPolyShape(), dummyShape->GetWidth(),
4997 dummyShape->IsFilled() );
4998 break;
4999
5000 case T_gr_curve:
5001 dummyShape = parsePCB_SHAPE();
5002 pad->AddPrimitiveCurve( dummyShape->GetStart(), dummyShape->GetEnd(),
5003 dummyShape->GetBezierC1(), dummyShape->GetBezierC2(),
5004 dummyShape->GetWidth() );
5005 break;
5006
5007 default:
5008 Expecting( "gr_line, gr_arc, gr_circle, gr_curve, gr_rect, gr_bbox or gr_poly" );
5009 break;
5010 }
5011
5012 delete dummyShape;
5013 }
5014
5015 break;
5016
5017 case T_remove_unused_layers:
5018 pad->SetRemoveUnconnected( true );
5019 NeedRIGHT();
5020 break;
5021
5022 case T_keep_end_layers:
5023 pad->SetKeepTopBottom( true );
5024 NeedRIGHT();
5025 break;
5026
5027 case T_zone_layer_connections:
5028 for( PCB_LAYER_ID layer : pad->GetLayerSet().Seq() )
5029 pad->SetZoneLayerOverride( layer, ZLO_FORCE_NO_ZONE_CONNECTION );
5030
5031 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
5032 {
5033 PCB_LAYER_ID layer = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
5034
5035 if( layer < F_Cu || layer > B_Cu )
5036 Expecting( "copper layer name" );
5037
5038 pad->SetZoneLayerOverride( layer, ZLO_FORCE_FLASHED );
5039 }
5040
5041 break;
5042
5043 // Continue to process "(locked)" format which was output during 5.99 development
5044 case T_locked:
5045 // Pad locking is now a session preference
5046 NeedRIGHT();
5047 break;
5048
5049 case T_tstamp:
5050 NextTok();
5051 const_cast<KIID&>( pad->m_Uuid ) = CurStrToKIID();
5052 NeedRIGHT();
5053 break;
5054
5055 default:
5056 Expecting( "at, locked, drill, layers, net, die_length, roundrect_rratio, "
5057 "solder_mask_margin, solder_paste_margin, solder_paste_margin_ratio, "
5058 "clearance, tstamp, primitives, remove_unused_layers, keep_end_layers, "
5059 "pinfunction, pintype, zone_connect, thermal_width, or thermal_gap" );
5060 }
5061 }
5062
5063 if( !pad->CanHaveNumber() )
5064 {
5065 // At some point it was possible to assign a number to aperture pads so we need to clean
5066 // those out here.
5067 pad->SetNumber( wxEmptyString );
5068 }
5069
5070 // Zero-sized pads are likely algorithmically unsafe.
5071 if( pad->GetSizeX() <= 0 || pad->GetSizeY() <= 0 )
5072 {
5073 pad->SetSize( VECTOR2I( pcbIUScale.mmToIU( 0.001 ), pcbIUScale.mmToIU( 0.001 ) ) );
5074
5075 wxLogWarning( _( "Invalid zero-sized pad pinned to %s in\nfile: %s\nline: %d\noffset: %d" ),
5076 wxT( "1┬Ám" ), CurSource(), CurLineNumber(), CurOffset() );
5077 }
5078
5079 return pad.release();
5080}
@ ZLO_FORCE_NO_ZONE_CONNECTION
Definition: board_item.h:60
@ ZLO_FORCE_FLASHED
Definition: board_item.h:59
EDA_ANGLE GetArcAngle() const
Definition: eda_shape.cpp:585
const VECTOR2I & GetBezierC2() const
Definition: eda_shape.h:179
SHAPE_POLY_SET & GetPolyShape()
Definition: eda_shape.h:247
bool IsFilled() const
Definition: eda_shape.h:90
int GetRadius() const
Definition: eda_shape.cpp:523
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:145
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:120
int GetWidth() const
Definition: eda_shape.h:109
const VECTOR2I & GetBezierC1() const
Definition: eda_shape.h:176
const wxString & GetNetname() const
Definition: netinfo.h:120
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:386
bool parsePAD_option(PAD *aPad)
LSET parseBoardItemLayersAsMask()
Parse the layers definition of a BOARD_ITEM object.
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_shape.h:67
static constexpr EDA_ANGLE & ANGLE_45
Definition: eda_angle.h:424
static constexpr EDA_ANGLE & ANGLE_90
Definition: eda_angle.h:425
@ NPTH
like PAD_PTH, but not plated
@ SMD
Smd pad, appears on the solder paste layer (default)
@ PTH
Plated through hole pad.
@ CONN
Like smd, does not appear on the solder paste layer (default)
@ PAD_DRILL_SHAPE_OBLONG
Definition: pad_shapes.h:71
@ FIDUCIAL_LOCAL
a fiducial (usually a smd) local to the parent footprint
@ FIDUCIAL_GLBL
a fiducial (usually a smd) for the full board
@ HEATSINK
a pad used as heat sink, usually in SMD footprints
@ NONE
no special fabrication property
@ TESTPOINT
a test point pad
@ CASTELLATED
a pad with a castellated through hole
@ BGA
Smd pad, used in BGA footprints.

References _, ANGLE_45, ANGLE_90, B_Cu, BGA, CASTELLATED, CHAMFERED_RECT, CIRCLE, CONN, ConvertToNewOverbarNotation(), CurStrToKIID(), CUSTOM, DEGREES_T, delta, FIDUCIAL_GLBL, FIDUCIAL_LOCAL, BOARD::FindNet(), EDA_SHAPE::GetArcAngle(), EDA_SHAPE::GetBezierC1(), EDA_SHAPE::GetBezierC2(), PCB_SHAPE::GetCenter(), EDA_SHAPE::GetEnd(), getNetCode(), NETINFO_ITEM::GetNetname(), EDA_SHAPE::GetPolyShape(), EDA_SHAPE::GetRadius(), EDA_SHAPE::GetStart(), EDA_SHAPE::GetWidth(), HEATSINK, EDA_SHAPE::IsFilled(), m_board, m_layerIndices, m_requiredVersion, EDA_IU_SCALE::mmToIU(), NONE, NPTH, NETINFO_LIST::ORPHANED, OVAL, pad, PAD_DRILL_SHAPE_OBLONG, parseBoardItemLayersAsMask(), parseBoardUnits(), parseDouble(), parseInt(), parsePAD_option(), parsePCB_SHAPE(), pcbIUScale, PTH, RECT, RECT_CHAMFER_BOTTOM_LEFT, RECT_CHAMFER_BOTTOM_RIGHT, RECT_CHAMFER_TOP_LEFT, RECT_CHAMFER_TOP_RIGHT, RECT_NO_CHAMFER, ROUNDRECT, SMD, TESTPOINT, TRAPEZOID, VECTOR2< T >::x, VECTOR2< T >::y, ZLO_FORCE_FLASHED, and ZLO_FORCE_NO_ZONE_CONNECTION.

Referenced by parseFOOTPRINT_unchecked().

◆ parsePAD_option()

bool PCB_PARSER::parsePAD_option ( PAD aPad)
private

Definition at line 5083 of file pcb_parser.cpp.

5084{
5085 // Parse only the (option ...) inside a pad description
5086 for( T token = NextTok(); token != T_RIGHT; token = NextTok() )
5087 {
5088 if( token != T_LEFT )
5089 Expecting( T_LEFT );
5090
5091 token = NextTok();
5092
5093 switch( token )
5094 {
5095 case T_anchor:
5096 token = NextTok();
5097 // Custom shaped pads have a "anchor pad", which is the reference
5098 // for connection calculations.
5099 // Because this is an anchor, only the 2 very basic shapes are managed:
5100 // circle and rect. The default is circle
5101 switch( token )
5102 {
5103 case T_circle: // default
5104 break;
5105
5106 case T_rect:
5108 break;
5109
5110 default:
5111 // Currently, because pad options is a moving target
5112 // just skip unknown keywords
5113 break;
5114 }
5115 NeedRIGHT();
5116 break;
5117
5118 case T_clearance:
5119 token = NextTok();
5120 // Custom shaped pads have a clearance area that is the pad shape
5121 // (like usual pads) or the convex hull of the pad shape.
5122 switch( token )
5123 {
5124 case T_outline:
5126 break;
5127
5128 case T_convexhull:
5130 break;
5131
5132 default:
5133 // Currently, because pad options is a moving target
5134 // just skip unknown keywords
5135 break;
5136 }
5137
5138 NeedRIGHT();
5139 break;
5140
5141 default:
5142 // Currently, because pad options is a moving target
5143 // just skip unknown keywords
5144 while( (token = NextTok() ) != T_RIGHT )
5145 {}
5146
5147 break;
5148 }
5149 }
5150
5151 return true;
5152}
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:222
void SetAnchorPadShape(PAD_SHAPE aShape)
Set the shape of the anchor pad for custom shaped pads.
Definition: pad.h:233
@ CUST_PAD_SHAPE_IN_ZONE_OUTLINE
Definition: pad.h:44
@ CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL
Definition: pad.h:45

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

Referenced by parsePAD().

◆ parsePAGE_INFO()

void PCB_PARSER::parsePAGE_INFO ( )
private

Definition at line 1160 of file pcb_parser.cpp.

1161{
1162 wxCHECK_RET( ( CurTok() == T_page && m_requiredVersion <= 20200119 ) || CurTok() == T_paper,
1163 wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a PAGE_INFO." ) );
1164
1165 T token;
1166 PAGE_INFO pageInfo;
1167
1168 NeedSYMBOL();
1169
1170 wxString pageType = FromUTF8();
1171
1172 if( !pageInfo.SetType( pageType ) )
1173 {
1174 wxString err;
1175 err.Printf( _( "Page type '%s' is not valid." ), FromUTF8() );
1176 THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
1177 }
1178
1179 if( pageType == PAGE_INFO::Custom )
1180 {
1181 double width = parseDouble( "width" ); // width in mm
1182
1183 const double Mils2mm = 0.0254;
1184
1185 // Perform some controls to avoid crashes if the size is edited by hands
1186 if( width < MIN_PAGE_SIZE_MILS*Mils2mm )
1188 else if( width > MAX_PAGE_SIZE_PCBNEW_MILS*Mils2mm )
1190
1191 double height = parseDouble( "height" ); // height in mm
1192
1193 if( height < MIN_PAGE_SIZE_MILS*Mils2mm )
1194 height = MIN_PAGE_SIZE_MILS*Mils2mm;
1195 else if( height > MAX_PAGE_SIZE_PCBNEW_MILS*Mils2mm )
1197
1198 pageInfo.SetWidthMils( EDA_UNIT_UTILS::Mm2mils( width ) );
1199 pageInfo.SetHeightMils( EDA_UNIT_UTILS::Mm2mils( height ) );
1200 }
1201
1202 token = NextTok();
1203
1204 if( token == T_portrait )
1205 {
1206 pageInfo.SetPortrait( true );
1207 NeedRIGHT();
1208 }
1209 else if( token != T_RIGHT )
1210 {
1211 Expecting( "portrait|)" );
1212 }
1213
1214 m_board->SetPageSettings( pageInfo );
1215}
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition: board.h:627
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition: page_info.h:54
void SetWidthMils(int aWidthInMils)
Definition: page_info.cpp:244
void SetPortrait(bool aIsPortrait)
Rotate the paper page 90 degrees.
Definition: page_info.cpp:187
static const wxChar Custom[]
"User" defined page type
Definition: page_info.h:77
void SetHeightMils(int aHeightInMils)
Definition: page_info.cpp:258
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:120
int Mm2mils(double aVal)
Convert mm to mils.
Definition: eda_units.cpp:56
int Mils2mm(double aVal)
Convert mils to mm.
Definition: eda_units.cpp:62
#define MAX_PAGE_SIZE_PCBNEW_MILS
Definition: page_info.h:40
#define MIN_PAGE_SIZE_MILS
Min and max page sizes for clamping, in mils.
Definition: page_info.h:39

References _, PAGE_INFO::Custom, m_board, m_requiredVersion, MAX_PAGE_SIZE_PCBNEW_MILS, EDA_UNIT_UTILS::Mils2mm(), MIN_PAGE_SIZE_MILS, EDA_UNIT_UTILS::Mm2mils(), parseDouble(), PAGE_INFO::SetHeightMils(), BOARD::SetPageSettings(), PAGE_INFO::SetPortrait(), PAGE_INFO::SetType(), PAGE_INFO::SetWidthMils(), and THROW_PARSE_ERROR.

Referenced by parseBOARD_unchecked().

◆ parsePCB_BITMAP()

PCB_BITMAP * PCB_PARSER::parsePCB_BITMAP ( BOARD_ITEM aParent)
private

Definition at line 2846 of file pcb_parser.cpp.

2847{
2848 wxCHECK_MSG( CurTok() == T_image, nullptr,
2849 wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as an image." ) );
2850
2851 T token;
2852 std::unique_ptr<PCB_BITMAP> bitmap = std::make_unique<PCB_BITMAP>( aParent );
2853
2854 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2855 {
2856 if( token != T_LEFT )
2857 Expecting( T_LEFT );
2858
2859 token = NextTok();
2860
2861 switch( token )
2862 {
2863 case T_at:
2864 {
2865 VECTOR2I pos;
2866 pos.x = parseBoardUnits( "X coordinate" );
2867 pos.y = parseBoardUnits( "Y coordinate" );
2868 bitmap->SetPosition( pos );
2869 NeedRIGHT();
2870 break;
2871 }
2872
2873 case T_layer:
2874 bitmap->SetLayer( parseBoardItemLayer() );
2875 NeedRIGHT();
2876 break;
2877
2878 case T_scale:
2879 bitmap->GetImage()->SetScale( parseDouble( "image scale factor" ) );
2880
2881 if( !std::isnormal( bitmap->GetImage()->GetScale() ) )
2882 bitmap->GetImage()->SetScale( 1.0 );
2883
2884 NeedRIGHT();
2885 break;
2886
2887 case T_data:
2888 {
2889 token = NextTok();
2890
2891 wxString data;
2892
2893 // Reserve 128K because most image files are going to be larger than the default
2894 // 1K that wxString reserves.
2895 data.reserve( 1 << 17 );
2896
2897 while( token != T_RIGHT )
2898 {
2899 if( !IsSymbol( token ) )
2900 Expecting( "base64 image data" );
2901
2902 data += FromUTF8();
2903 token = NextTok();
2904 }
2905
2906 wxMemoryBuffer buffer = wxBase64Decode( data );
2907 wxMemoryOutputStream stream( buffer.GetData(), buffer.GetBufSize() );
2908 wxImage* image = new wxImage();
2909 wxMemoryInputStream istream( stream );
2910 image->LoadFile( istream, wxBITMAP_TYPE_PNG );
2911 bitmap->GetImage()->SetImage( image );
2912 break;
2913 }
2914
2915 default:
2916 Expecting( "at, layer, scale, data" );
2917 }
2918 }
2919
2920 return bitmap.release();
2921}

References image, parseBoardItemLayer(), parseBoardUnits(), parseDouble(), VECTOR2< T >::x, and VECTOR2< T >::y.

Referenced by parseBOARD_unchecked(), and parseFOOTPRINT_unchecked().

◆ parsePCB_SHAPE()

PCB_SHAPE * PCB_PARSER::parsePCB_SHAPE ( )
private

Definition at line 2468 of file pcb_parser.cpp.

2469{
2470 wxCHECK_MSG( CurTok() == T_gr_arc || CurTok() == T_gr_circle || CurTok() == T_gr_curve ||
2471 CurTok() == T_gr_rect || CurTok() == T_gr_bbox || CurTok() == T_gr_line ||
2472 CurTok() == T_gr_poly, nullptr,
2473 wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PCB_SHAPE." ) );
2474
2475 T token;
2476 VECTOR2I pt;
2478 std::unique_ptr<PCB_SHAPE> shape = std::make_unique<PCB_SHAPE>( nullptr );
2479
2480 switch( CurTok() )
2481 {
2482 case T_gr_arc:
2483 shape->SetShape( SHAPE_T::ARC );
2484 token = NextTok();
2485
2486 if( token == T_locked )
2487 {
2488 shape->SetLocked( true );
2489 token = NextTok();
2490 }
2491
2492 if( token != T_LEFT )
2493 Expecting( T_LEFT );
2494
2495 token = NextTok();
2496
2498 {
2499 // In legacy files the start keyword actually gives the arc center...
2500 if( token != T_start )
2501 Expecting( T_start );
2502
2503 pt.x = parseBoardUnits( "X coordinate" );
2504 pt.y = parseBoardUnits( "Y coordinate" );
2505 shape->SetCenter( pt );
2506 NeedRIGHT();
2507 NeedLEFT();
2508 token = NextTok();
2509
2510 // ... and the end keyword gives the start point of the arc
2511 if( token != T_end )
2512 Expecting( T_end );
2513
2514 pt.x = parseBoardUnits( "X coordinate" );
2515 pt.y = parseBoardUnits( "Y coordinate" );
2516 shape->SetStart( pt );
2517 NeedRIGHT();
2518 }
2519 else
2520 {
2521 VECTOR2I arc_start, arc_mid, arc_end;
2522
2523 if( token != T_start )
2524 Expecting( T_start );
2525
2526 arc_start.x = parseBoardUnits( "X coordinate" );
2527 arc_start.y = parseBoardUnits( "Y coordinate" );
2528 NeedRIGHT();
2529 NeedLEFT();
2530 token = NextTok();
2531
2532 if( token != T_mid )
2533 Expecting( T_mid );
2534
2535 arc_mid.x = parseBoardUnits( "X coordinate" );
2536 arc_mid.y = parseBoardUnits( "Y coordinate" );
2537 NeedRIGHT();
2538 NeedLEFT();
2539 token = NextTok();
2540
2541 if( token != T_end )
2542 Expecting( T_end );
2543
2544 arc_end.x = parseBoardUnits( "X coordinate" );
2545 arc_end.y = parseBoardUnits( "Y coordinate" );
2546 NeedRIGHT();
2547
2548 shape->SetArcGeometry( arc_start, arc_mid, arc_end );
2549 }
2550
2551 break;
2552
2553 case T_gr_circle:
2554 shape->SetShape( SHAPE_T::CIRCLE );
2555 token = NextTok();
2556
2557 if( token == T_locked )
2558 {
2559 shape->SetLocked( true );
2560 token = NextTok();
2561 }
2562
2563 if( token != T_LEFT )
2564 Expecting( T_LEFT );
2565
2566 token = NextTok();
2567
2568 if( token != T_center )
2569 Expecting( T_center );
2570
2571 pt.x = parseBoardUnits( "X coordinate" );
2572 pt.y = parseBoardUnits( "Y coordinate" );
2573 shape->SetStart( pt );
2574 NeedRIGHT();
2575 NeedLEFT();
2576
2577 token = NextTok();
2578
2579 if( token != T_end )
2580 Expecting( T_end );
2581
2582 pt.x = parseBoardUnits( "X coordinate" );
2583 pt.y = parseBoardUnits( "Y coordinate" );
2584 shape->SetEnd( pt );
2585 NeedRIGHT();
2586 break;
2587
2588 case T_gr_curve:
2589 shape->SetShape( SHAPE_T::BEZIER );
2590 token = NextTok();
2591
2592 if( token == T_locked )
2593 {
2594 shape->SetLocked( true );
2595 token = NextTok();
2596 }
2597
2598 if( token != T_LEFT )
2599 Expecting( T_LEFT );
2600
2601 token = NextTok();
2602
2603 if( token != T_pts )
2604 Expecting( T_pts );
2605
2606 shape->SetStart( parseXY() );
2607 shape->SetBezierC1( parseXY());
2608 shape->SetBezierC2( parseXY());
2609 shape->SetEnd( parseXY() );
2610 NeedRIGHT();
2611 break;
2612
2613 case T_gr_bbox:
2614 case T_gr_rect:
2615 shape->SetShape( SHAPE_T::RECT );
2616 token = NextTok();
2617
2618 if( token == T_locked )
2619 {
2620 shape->SetLocked( true );
2621 token = NextTok();
2622 }
2623
2624 if( token != T_LEFT )
2625 Expecting( T_LEFT );
2626
2627 token = NextTok();
2628
2629 if( token != T_start )
2630 Expecting( T_start );
2631
2632 pt.x = parseBoardUnits( "X coordinate" );
2633 pt.y = parseBoardUnits( "Y coordinate" );
2634 shape->SetStart( pt );
2635 NeedRIGHT();
2636 NeedLEFT();
2637 token = NextTok();
2638
2639 if( token != T_end )
2640 Expecting( T_end );
2641
2642 pt.x = parseBoardUnits( "X coordinate" );
2643 pt.y = parseBoardUnits( "Y coordinate" );
2644 shape->SetEnd( pt );
2645 shape->NormalizeRect();
2646 NeedRIGHT();
2647 break;
2648
2649 case T_gr_line:
2650 // Default PCB_SHAPE type is S_SEGMENT.
2651 token = NextTok();
2652
2653 if( token == T_locked )
2654 {
2655 shape->SetLocked( true );
2656 token = NextTok();
2657 }
2658
2659 if( token != T_LEFT )
2660 Expecting( T_LEFT );
2661
2662 token = NextTok();
2663
2664 if( token != T_start )
2665 Expecting( T_start );
2666
2667 pt.x = parseBoardUnits( "X coordinate" );
2668 pt.y = parseBoardUnits( "Y coordinate" );
2669 shape->SetStart( pt );
2670 NeedRIGHT();
2671 NeedLEFT();
2672 token = NextTok();
2673
2674 if( token != T_end )
2675 Expecting( T_end );
2676
2677 pt.x = parseBoardUnits( "X coordinate" );
2678 pt.y = parseBoardUnits( "Y coordinate" );
2679 shape->SetEnd( pt );
2680 NeedRIGHT();
2681 break;
2682
2683 case T_gr_poly:
2684 {
2685 shape->SetShape( SHAPE_T::POLY );
2686 shape->SetPolyPoints( {} );
2687
2688 SHAPE_LINE_CHAIN& outline = shape->GetPolyShape().Outline( 0 );
2689
2690 token = NextTok();
2691
2692 if( token == T_locked )
2693 {
2694 shape->SetLocked( true );
2695 token = NextTok();
2696 }
2697
2698 if( token != T_LEFT )
2699 Expecting( T_LEFT );
2700
2701 token = NextTok();
2702
2703 if( token != T_pts )
2704 Expecting( T_pts );
2705
2706 while( (token = NextTok() ) != T_RIGHT )
2707 {
2708 parseOutlinePoints( outline );
2709 }
2710
2711 break;
2712 }
2713
2714 default:
2715 Expecting( "gr_arc, gr_circle, gr_curve, gr_line, gr_poly, gr_rect or gr_bbox" );
2716 }
2717
2718 bool foundFill = false;
2719
2720 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2721 {
2722 if( token != T_LEFT )
2723 Expecting( T_LEFT );
2724
2725 token = NextTok();
2726
2727 switch( token )
2728 {
2729 case T_angle:
2731 {
2732 EDA_ANGLE angle( parseDouble( "arc angle" ), DEGREES_T );
2733
2734 if( shape->GetShape() == SHAPE_T::ARC )
2735 shape->SetArcAngleAndEnd( angle, true );
2736
2737 NeedRIGHT();
2738 }
2739 else
2740 {
2741 Unexpected( T_angle );
2742 }
2743
2744 break;
2745
2746 case T_layer:
2747 shape->SetLayer( parseBoardItemLayer() );
2748 NeedRIGHT();
2749 break;
2750
2751 case T_width: // legacy token
2752 stroke.SetWidth( parseBoardUnits( T_width ) );
2753 NeedRIGHT();
2754 break;
2755
2756 case T_stroke:
2757 {
2758 STROKE_PARAMS_PARSER strokeParser( reader, pcbIUScale.IU_PER_MM );
2759 strokeParser.SyncLineReaderWith( *this );
2760
2761 strokeParser.ParseStroke( stroke );
2762 SyncLineReaderWith( strokeParser );
2763 break;
2764 }
2765
2766 case T_tstamp:
2767 NextTok();
2768 const_cast<KIID&>( shape->m_Uuid ) = CurStrToKIID();
2769 NeedRIGHT();
2770 break;
2771
2772 case T_fill:
2773 foundFill = true;
2774
2775 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2776 {
2777 if( token == T_LEFT )
2778 token = NextTok();
2779
2780 switch( token )
2781 {
2782 // T_yes was used to indicate filling when first introduced,
2783 // so treat it like a solid fill since that was the only fill available
2784 case T_yes:
2785 case T_solid:
2786 shape->SetFilled( true );
2787 break;
2788
2789 case T_none:
2790 shape->SetFilled( false );
2791 break;
2792
2793 default:
2794 Expecting( "yes, none, solid" );
2795 }
2796 }
2797
2798 break;
2799
2800 // We continue to parse the status field but it is no longer written
2801 case T_status:
2802 shape->SetStatus( static_cast<EDA_ITEM_FLAGS>( parseHex() ) );
2803 NeedRIGHT();
2804 break;
2805
2806 // Continue to process "(locked)" format which was output during 5.99 development
2807 case T_locked:
2808 shape->SetLocked( true );
2809 NeedRIGHT();
2810 break;
2811
2812 default:
2813 Expecting( "layer, width, fill, tstamp, locked or status" );
2814 }
2815 }
2816
2817 if( !foundFill )
2818 {
2819 // Legacy versions didn't have a filled flag but allowed some shapes to indicate they
2820 // should be filled by specifying a 0 stroke-width.
2821 if( stroke.GetWidth() == 0
2822 && ( shape->GetShape() == SHAPE_T::RECT || shape->GetShape() == SHAPE_T::CIRCLE ) )
2823 {
2824 shape->SetFilled( true );
2825 }
2826 else if( shape->GetShape() == SHAPE_T::POLY && shape->GetLayer() != Edge_Cuts )
2827 {
2828 // Polygons on non-Edge_Cuts layers were always filled.
2829 shape->SetFilled( true );
2830 }
2831 }
2832
2833 // Only filled shapes may have a zero line-width. This is not permitted in KiCad but some
2834 // external tools can generate invalid files.
2835 if( stroke.GetWidth() <= 0 && !shape->IsFilled() )
2836 {
2837 stroke.SetWidth( pcbIUScale.mmToIU( DEFAULT_LINE_WIDTH ) );
2838 }
2839
2840 shape->SetStroke( stroke );
2841
2842 return shape.release();
2843}
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)

References PNS::angle(), ARC, BEZIER, CIRCLE, CurStrToKIID(), DEFAULT_LINE_WIDTH, DEGREES_T, Edge_Cuts, STROKE_PARAMS::GetWidth(), EDA_IU_SCALE::IU_PER_MM, LEGACY_ARC_FORMATTING, m_requiredVersion, EDA_IU_SCALE::mmToIU(), parseBoardItemLayer(), parseBoardUnits(), parseDouble(), parseHex(), parseOutlinePoints(), STROKE_PARAMS_PARSER::ParseStroke(), parseXY(), pcbIUScale, POLY, RECT, STROKE_PARAMS::SetWidth(), SOLID, VECTOR2< T >::x, and VECTOR2< T >::y.

Referenced by parseBOARD_unchecked(), and parsePAD().

◆ parsePCB_TARGET()

PCB_TARGET * PCB_PARSER::parsePCB_TARGET ( )
private

Definition at line 6150 of file pcb_parser.cpp.

6151{
6152 wxCHECK_MSG( CurTok() == T_target, nullptr,
6153 wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PCB_TARGET." ) );
6154
6155 VECTOR2I pt;
6156 T token;
6157
6158 std::unique_ptr<PCB_TARGET> target = std::make_unique<PCB_TARGET>( nullptr );
6159
6160 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
6161 {
6162 if( token == T_LEFT )
6163 token = NextTok();
6164
6165 switch( token )
6166 {
6167 case T_x:
6168 target->SetShape( 1 );
6169 break;
6170
6171 case T_plus:
6172 target->SetShape( 0 );
6173 break;
6174
6175 case T_at:
6176 pt.x = parseBoardUnits( "target x position" );
6177 pt.y = parseBoardUnits( "target y position" );
6178 target->SetPosition( pt );
6179 NeedRIGHT();
6180 break;
6181
6182 case T_size:
6183 target->SetSize( parseBoardUnits( "target size" ) );
6184 NeedRIGHT();
6185 break;
6186
6187 case T_width:
6188 target->SetWidth( parseBoardUnits( "target thickness" ) );
6189 NeedRIGHT();
6190 break;
6191
6192 case T_layer:
6193 target->SetLayer( parseBoardItemLayer() );
6194 NeedRIGHT();
6195 break;
6196
6197 case T_tstamp:
6198 NextTok();
6199 const_cast<KIID&>( target->m_Uuid ) = CurStrToKIID();
6200 NeedRIGHT();
6201 break;
6202
6203 default:
6204 Expecting( "x, plus, at, size, width, layer or tstamp" );
6205 }
6206 }
6207
6208 return target.release();
6209}

References CurStrToKIID(), parseBoardItemLayer(), parseBoardUnits(), VECTOR2< T >::x, and VECTOR2< T >::y.

Referenced by parseBOARD_unchecked().

◆ parsePCB_TEXT()

PCB_TEXT * PCB_PARSER::parsePCB_TEXT ( )
private

Definition at line 2924 of file pcb_parser.cpp.

2925{
2926 wxCHECK_MSG( CurTok() == T_gr_text, nullptr,
2927 wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PCB_TEXT." ) );
2928
2929 std::unique_ptr<PCB_TEXT> text = std::make_unique<PCB_TEXT>( m_board );
2930
2931 T token = NextTok();
2932
2933 if( token == T_locked )
2934 {
2935 text->SetLocked( true );
2936 token = NextTok();
2937 }
2938
2939 if( !IsSymbol( token ) && (int) token != DSN_NUMBER )
2940 Expecting( "text value" );
2941
2942 text->SetText( FromUTF8() );
2943
2944 NeedLEFT();
2945 token = NextTok();
2946
2947 if( token != T_at )
2948 Expecting( T_at );
2949
2950 VECTOR2I pt;
2951
2952 pt.x = parseBoardUnits( "X coordinate" );
2953 pt.y = parseBoardUnits( "Y coordinate" );
2954 text->SetTextPos( pt );
2955
2956 // If there is no orientation defined, then it is the default value of 0 degrees.
2957 token = NextTok();
2958
2959 if( token == T_NUMBER )
2960 {
2961 text->SetTextAngle( EDA_ANGLE( parseDouble(), DEGREES_T ) );
2962 NeedRIGHT();
2963 }
2964 else if( token != T_RIGHT )
2965 {
2966 Unexpected( CurText() );
2967 }
2968
2969 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2970 {
2971 if( token != T_LEFT )
2972 Expecting( T_LEFT );
2973
2974 token = NextTok();
2975
2976 switch( token )
2977 {
2978 case T_layer:
2979 text->SetLayer( parseBoardItemLayer() );
2980
2981 token = NextTok();
2982
2983 if( token == T_knockout )
2984 {
2985 text->SetIsKnockout( true );
2986 token = NextTok();
2987 }
2988
2989 if( (int) token != DSN_RIGHT )
2990 Expecting( DSN_RIGHT );
2991
2992 break;
2993
2994 case T_tstamp:
2995 NextTok();
2996 const_cast<KIID&>( text->m_Uuid ) = CurStrToKIID();
2997 NeedRIGHT();
2998 break;
2999
3000 case T_effects:
3001 parseEDA_TEXT( static_cast<EDA_TEXT*>( text.get() ) );
3002 break;
3003
3004 case T_render_cache:
3005 parseRenderCache( static_cast<EDA_TEXT*>( text.get() ) );
3006 break;
3007
3008 default:
3009 Expecting( "layer, effects, locked, render_cache or tstamp" );
3010 }
3011 }
3012
3013 return text.release();
3014}

References CurStrToKIID(), DEGREES_T, DSN_NUMBER, DSN_RIGHT, m_board, parseBoardItemLayer(), parseBoardUnits(), parseDouble(), parseEDA_TEXT(), parseRenderCache(), text, VECTOR2< T >::x, and VECTOR2< T >::y.

Referenced by parseBOARD_unchecked(), and parseDIMENSION().

◆ parsePCB_TEXTBOX()

PCB_TEXTBOX * PCB_PARSER::parsePCB_TEXTBOX ( )
private

Definition at line 3017 of file pcb_parser.cpp.

3018{
3019 wxCHECK_MSG( CurTok() == T_gr_text_box, nullptr,
3020 wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PCB_TEXTBOX." ) );
3021
3022 std::unique_ptr<PCB_TEXTBOX> textbox = std::make_unique<PCB_TEXTBOX>( m_board );
3023
3025 T token = NextTok();
3026
3027 if( token == T_locked )
3028 {
3029 textbox->SetLocked( true );
3030 token = NextTok();
3031 }
3032
3033 if( !IsSymbol( token ) && (int) token != DSN_NUMBER )
3034 Expecting( "text value" );
3035
3036 textbox->SetText( FromUTF8() );
3037
3038 NeedLEFT();
3039 token = NextTok();
3040
3041 if( token == T_start )
3042 {
3043 int x = parseBoardUnits( "X coordinate" );
3044 int y = parseBoardUnits( "Y coordinate" );
3045 textbox->SetStart( VECTOR2I( x, y ) );
3046 NeedRIGHT();
3047
3048 NeedLEFT();
3049 token = NextTok();
3050
3051 if( token != T_end )
3052 Expecting( T_end );
3053
3054 x = parseBoardUnits( "X coordinate" );
3055 y = parseBoardUnits( "Y coordinate" );
3056 textbox->SetEnd( VECTOR2I( x, y ) );
3057 NeedRIGHT();
3058 }
3059 else if( token == T_pts )
3060 {
3061 textbox->SetShape( SHAPE_T::POLY );
3062 textbox->GetPolyShape().RemoveAllContours();
3063 textbox->GetPolyShape().NewOutline();
3064
3065 while( (token = NextTok() ) != T_RIGHT )
3066 parseOutlinePoints( textbox->GetPolyShape().Outline( 0 ) );
3067 }
3068 else
3069 {
3070 Expecting( "start or pts" );
3071 }
3072
3073 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3074 {
3075 if( token != T_LEFT )
3076 Expecting( T_LEFT );
3077
3078 token = NextTok();
3079
3080 switch( token )
3081 {
3082 case T_angle:
3083 textbox->SetTextAngle( EDA_ANGLE( parseDouble( "text box angle" ), DEGREES_T ) );
3084 NeedRIGHT();
3085 break;
3086
3087 case T_stroke:
3088 {
3089 STROKE_PARAMS_PARSER strokeParser( reader, pcbIUScale.IU_PER_MM );
3090 strokeParser.SyncLineReaderWith( *this );
3091
3092 strokeParser.ParseStroke( stroke );
3093 SyncLineReaderWith( strokeParser );
3094 break;
3095 }
3096
3097 case T_layer:
3098 textbox->SetLayer( parseBoardItemLayer() );
3099 NeedRIGHT();
3100 break;
3101
3102 case T_tstamp:
3103 NextTok();
3104 const_cast<KIID&>( textbox->m_Uuid ) = CurStrToKIID();
3105 NeedRIGHT();
3106 break;
3107
3108 case T_effects:
3109 parseEDA_TEXT( static_cast<EDA_TEXT*>( textbox.get() ) );
3110 break;
3111
3112 case T_render_cache:
3113 parseRenderCache( static_cast<EDA_TEXT*>( textbox.get() ) );
3114 break;
3115
3116 default:
3117 Expecting( "angle, width, layer, effects, render_cache or tstamp" );
3118 }
3119 }
3120
3121 textbox->SetStroke( stroke );
3122
3123 return textbox.release();
3124}

References CurStrToKIID(), DEGREES_T, DSN_NUMBER, EDA_IU_SCALE::IU_PER_MM, m_board, parseBoardItemLayer(), parseBoardUnits(), parseDouble(), parseEDA_TEXT(), parseOutlinePoints(), parseRenderCache(), STROKE_PARAMS_PARSER::ParseStroke(), pcbIUScale, POLY, and SOLID.

Referenced by parseBOARD_unchecked().

◆ parsePCB_TRACK()

PCB_TRACK * PCB_PARSER::parsePCB_TRACK ( )
private

Definition at line 5290 of file pcb_parser.cpp.

5291{
5292 wxCHECK_MSG( CurTok() == T_segment, nullptr,
5293 wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PCB_TRACK." ) );
5294
5295 VECTOR2I pt;
5296 T token;
5297
5298 std::unique_ptr<PCB_TRACK> track = std::make_unique<PCB_TRACK>( m_board );
5299
5300 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
5301 {
5302 if( token == T_locked )
5303 {
5304 track->SetLocked( true );
5305 token = NextTok();
5306 }
5307
5308 if( token != T_LEFT )
5309 Expecting( T_LEFT );
5310
5311 token = NextTok();
5312
5313 switch( token )
5314 {
5315 case T_start:
5316 pt.x = parseBoardUnits( "start x" );
5317 pt.y = parseBoardUnits( "start y" );
5318 track->SetStart( pt );
5319 break;
5320
5321 case T_end:
5322 pt.x = parseBoardUnits( "end x" );
5323 pt.y = parseBoardUnits( "end y" );
5324 track->SetEnd( pt );
5325 break;
5326
5327 case T_width:
5328 track->SetWidth( parseBoardUnits( "width" ) );
5329 break;
5330
5331 case T_layer:
5332 track->SetLayer( parseBoardItemLayer() );
5333 break;
5334
5335 case T_net:
5336 if( !track->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
5337 {
5338 wxLogError( _( "Invalid net ID in\nfile: '%s'\nline: %d\noffset: %d." ),
5339 CurSource(), CurLineNumber(), CurOffset() );
5340 }
5341 break;
5342
5343 case T_tstamp:
5344 NextTok();
5345 const_cast<KIID&>( track->m_Uuid ) = CurStrToKIID();
5346 break;
5347
5348 // We continue to parse the status field but it is no longer written
5349 case T_status:
5350 track->SetStatus( static_cast<EDA_ITEM_FLAGS>( parseHex() ) );
5351 break;
5352
5353 // Continue to process "(locked)" format which was output during 5.99 development
5354 case T_locked:
5355 track->SetLocked( true );
5356 break;
5357
5358 default:
5359 Expecting( "start, end, width, layer, net, tstamp, or locked" );
5360 }
5361
5362 NeedRIGHT();
5363 }
5364
5365 return track.release();
5366}

References _, CurStrToKIID(), getNetCode(), m_board, parseBoardItemLayer(), parseBoardUnits(), parseHex(), parseInt(), VECTOR2< T >::x, and VECTOR2< T >::y.

Referenced by parseBOARD_unchecked().

◆ parsePCB_VIA()

PCB_VIA * PCB_PARSER::parsePCB_VIA ( )
private

Definition at line 5369 of file pcb_parser.cpp.

5370{
5371 wxCHECK_MSG( CurTok() == T_via, nullptr,
5372 wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PCB_VIA." ) );
5373
5374 VECTOR2I pt;
5375 T token;
5376
5377 std::unique_ptr<PCB_VIA> via = std::make_unique<PCB_VIA>( m_board );
5378
5379 // File format default is no-token == no-feature.
5380 via->SetRemoveUnconnected( false );
5381 via->SetKeepStartEnd( false );
5382
5383 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
5384 {
5385 if( token == T_locked )
5386 {
5387 via->SetLocked( true );
5388 token = NextTok();
5389 }
5390
5391 if( token == T_LEFT )
5392 token = NextTok();
5393
5394 switch( token )
5395 {
5396 case T_blind:
5397 via->SetViaType( VIATYPE::BLIND_BURIED );
5398 break;
5399
5400 case T_micro:
5401 via->SetViaType( VIATYPE::MICROVIA );
5402 break;
5403
5404 case T_at:
5405 pt.x = parseBoardUnits( "start x" );
5406 pt.y = parseBoardUnits( "start y" );
5407 via->SetStart( pt );
5408 via->SetEnd( pt );
5409 NeedRIGHT();
5410 break;
5411
5412 case T_size:
5413 via->SetWidth( parseBoardUnits( "via width" ) );
5414 NeedRIGHT();
5415 break;
5416
5417 case T_drill:
5418 via->SetDrill( parseBoardUnits( "drill diameter" ) );
5419 NeedRIGHT();
5420 break;
5421
5422 case T_layers:
5423 {
5424 PCB_LAYER_ID layer1, layer2;
5425 NextTok();
5426 layer1 = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
5427 NextTok();
5428 layer2 = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
5429 via->SetLayerPair( layer1, layer2 );
5430 NeedRIGHT();
5431 break;
5432 }
5433
5434 case T_net:
5435 if( !via->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
5436 {
5437 wxLogError( _( "Invalid net ID in\nfile: %s\nline: %d\noffset: %d" ),
5438 CurSource(), CurLineNumber(), CurOffset() );
5439 }
5440
5441 NeedRIGHT();
5442 break;
5443
5444 case T_remove_unused_layers:
5445 via->SetRemoveUnconnected( true );
5446 NeedRIGHT();
5447 break;
5448
5449 case T_keep_end_layers:
5450 via->SetKeepStartEnd( true );
5451 NeedRIGHT();
5452 break;
5453
5454 case T_zone_layer_connections:
5455 for( PCB_LAYER_ID layer : via->GetLayerSet().Seq() )
5456 via->SetZoneLayerOverride( layer, ZLO_FORCE_NO_ZONE_CONNECTION );
5457
5458 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
5459 {
5460 PCB_LAYER_ID layer = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
5461
5462 if( layer < F_Cu || layer > B_Cu )
5463 Expecting( "copper layer name" );
5464
5465 via->SetZoneLayerOverride( layer, ZLO_FORCE_FLASHED );
5466 }
5467
5468 break;
5469
5470 case T_tstamp:
5471 NextTok();
5472 const_cast<KIID&>( via->m_Uuid ) = CurStrToKIID();
5473 NeedRIGHT();
5474 break;
5475
5476 // We continue to parse the status field but it is no longer written
5477 case T_status:
5478 via->SetStatus( static_cast<EDA_ITEM_FLAGS>( parseHex() ) );
5479 NeedRIGHT();
5480 break;
5481
5482 // Continue to process "(locked)" format which was output during 5.99 development
5483 case T_locked:
5484 via->SetLocked( true );
5485 NeedRIGHT();
5486 break;
5487
5488 case T_free:
5489 via->SetIsFree();
5490 NeedRIGHT();
5491 break;
5492
5493 default:
5494 Expecting( "blind, micro, at, size, drill, layers, net, free, tstamp, or status" );
5495 }
5496 }
5497
5498 return via.release();
5499}
@ BLIND_BURIED

References _, B_Cu, BLIND_BURIED, CurStrToKIID(), getNetCode(), m_board, m_layerIndices, MICROVIA, parseBoardUnits(), parseHex(), parseInt(), via, VECTOR2< T >::x, VECTOR2< T >::y, ZLO_FORCE_FLASHED, and ZLO_FORCE_NO_ZONE_CONNECTION.

Referenced by parseBOARD_unchecked().

◆ parseProperty()

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

Definition at line 369 of file pcb_parser.cpp.

370{
371 wxString pName;
372 wxString pValue;
373
374 NeedSYMBOL();
375 pName = FromUTF8();
376 NeedSYMBOL();
377 pValue = FromUTF8();
378 NeedRIGHT();
379
380 return { pName, pValue };
381}

Referenced by parseBOARD_unchecked(), and parseFOOTPRINT_unchecked().

◆ parseRenderCache()

void PCB_PARSER::parseRenderCache ( EDA_TEXT text)
private

Parse the render cache for any object derived from EDA_TEXT.

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

Definition at line 525 of file pcb_parser.cpp.

526{
527 T token;
528
529 NeedSYMBOLorNUMBER();
530 wxString cacheText = FROM_UTF8( CurText() );
531 EDA_ANGLE cacheAngle( parseDouble( "render cache angle" ), DEGREES_T );
532
533 text->SetupRenderCache( cacheText, cacheAngle );
534
535 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
536 {
537 if( token != T_LEFT )
538 Expecting( T_LEFT );
539
540 token = NextTok();
541
542 if( token != T_polygon )
543 Expecting( T_polygon );
544
545 SHAPE_POLY_SET poly;
546
547 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
548 {
549 if( token != T_LEFT )
550 Expecting( T_LEFT );
551
552 token = NextTok();
553
554 if( token != T_pts )
555 Expecting( T_pts );
556
557 SHAPE_LINE_CHAIN lineChain;
558
559 while( (token = NextTok() ) != T_RIGHT )
560 parseOutlinePoints( lineChain );
561
562 lineChain.SetClosed( true );
563
564 if( poly.OutlineCount() == 0 )
565 poly.AddOutline( lineChain );
566 else
567 poly.AddHole( lineChain );
568 }
569
570 text->AddRenderCacheGlyph( poly );
571 }
572}
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
Represent a set of closed polygons.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new hole to the given outline (default: last) and returns its index.
int AddHole(const SHAPE_LINE_CHAIN &aHole, int aOutline=-1)
Return the area of this poly set.
int OutlineCount() const
Return the number of vertices in a given outline/hole.

References SHAPE_POLY_SET::AddHole(), SHAPE_POLY_SET::AddOutline(), DEGREES_T, FROM_UTF8(), SHAPE_POLY_SET::OutlineCount(), parseDouble(), parseOutlinePoints(), SHAPE_LINE_CHAIN::SetClosed(), and text.

Referenced by parseFP_TEXT(), parseFP_TEXTBOX(), parsePCB_TEXT(), and parsePCB_TEXTBOX().

◆ parseSetup()

void PCB_PARSER::parseSetup ( )
private

Definition at line 1837 of file pcb_parser.cpp.

1838{
1839 wxCHECK_RET( CurTok() == T_setup,
1840 wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as setup." ) );
1841
1843 std::shared_ptr<NETCLASS>& defaultNetClass = bds.m_NetSettings->m_DefaultNetClass;
1844 ZONE_SETTINGS& zoneSettings = bds.GetDefaultZoneSettings();
1845
1846 // Missing soldermask min width value means that the user has set the value to 0 and
1847 // not the default value (0.25mm)
1848 bds.m_SolderMaskMinWidth = 0;
1849
1850 for( T token = NextTok(); token != T_RIGHT; token = NextTok() )
1851 {
1852 if( token != T_LEFT )
1853 Expecting( T_LEFT );
1854
1855 token = NextTok();
1856
1857 switch( token )
1858 {
1859 case T_stackup:
1861 break;
1862
1863 case T_last_trace_width: // not used now
1864 /* lastTraceWidth =*/ parseBoardUnits( T_last_trace_width );
1865 NeedRIGHT();
1866 break;
1867
1868 case T_user_trace_width:
1869 {
1870 // Make room for the netclass value
1871 if( bds.m_TrackWidthList.empty() )
1872 bds.m_TrackWidthList.emplace_back( 0 );
1873
1874 int trackWidth = parseBoardUnits( T_user_trace_width );
1875
1876 if( !m_appendToExisting || !alg::contains( bds.m_TrackWidthList, trackWidth ) )
1877 bds.m_TrackWidthList.push_back( trackWidth );
1878
1880 NeedRIGHT();
1881 break;
1882 }
1883
1884 case T_trace_clearance:
1885 defaultNetClass->SetClearance( parseBoardUnits( T_trace_clearance ) );
1887 NeedRIGHT();
1888 break;
1889
1890 case T_zone_clearance:
1891 zoneSettings.m_ZoneClearance = parseBoardUnits( T_zone_clearance );
1893 NeedRIGHT();
1894 break;
1895
1896 case T_zone_45_only: // legacy setting
1897 /* zoneSettings.m_Zone_45_Only = */ parseBool();
1899 NeedRIGHT();
1900 break;
1901
1902 case T_clearance_min:
1903 bds.m_MinClearance = parseBoardUnits( T_clearance_min );
1905 NeedRIGHT();
1906 break;
1907
1908 case T_trace_min:
1909 bds.m_TrackMinWidth = parseBoardUnits( T_trace_min );
1911 NeedRIGHT();
1912 break;
1913
1914 case T_via_size:
1915 defaultNetClass->SetViaDiameter( parseBoardUnits( T_via_size ) );
1917 NeedRIGHT();
1918 break;
1919
1920 case T_via_drill:
1921 defaultNetClass->SetViaDrill( parseBoardUnits( T_via_drill ) );
1923 NeedRIGHT();
1924 break;
1925
1926 case T_via_min_annulus:
1927 bds.m_ViasMinAnnularWidth = parseBoardUnits( T_via_min_annulus );
1929 NeedRIGHT();
1930 break;
1931
1932 case T_via_min_size:
1933 bds.m_ViasMinSize = parseBoardUnits( T_via_min_size );
1935 NeedRIGHT();
1936 break;
1937
1938 case T_through_hole_min:
1939 bds.m_MinThroughDrill = parseBoardUnits( T_through_hole_min );
1941 NeedRIGHT();
1942 break;
1943
1944 // Legacy token for T_through_hole_min
1945 case T_via_min_drill:
1946 bds.m_MinThroughDrill = parseBoardUnits( T_via_min_drill );
1948 NeedRIGHT();
1949 break;
1950
1951 case T_hole_to_hole_min:
1952 bds.m_HoleToHoleMin = parseBoardUnits( T_hole_to_hole_min );
1954 NeedRIGHT();
1955 break;
1956
1957 case T_user_via:
1958 {
1959 int viaSize = parseBoardUnits( "user via size" );
1960 int viaDrill = parseBoardUnits( "user via drill" );
1961 VIA_DIMENSION via( viaSize, viaDrill );
1962
1963 // Make room for the netclass value
1964 if( bds.m_ViasDimensionsList.empty() )
1965 bds.m_ViasDimensionsList.emplace_back( VIA_DIMENSION( 0, 0 ) );
1966
1968 bds.m_ViasDimensionsList.emplace_back( via );
1969
1971 NeedRIGHT();
1972 break;
1973 }
1974
1975 case T_uvia_size:
1976 defaultNetClass->SetuViaDiameter( parseBoardUnits( T_uvia_size ) );
1978 NeedRIGHT();
1979 break;
1980
1981 case T_uvia_drill:
1982 defaultNetClass->SetuViaDrill( parseBoardUnits( T_uvia_drill ) );
1984 NeedRIGHT();
1985 break;
1986
1987 case T_uvias_allowed:
1988 parseBool();
1990 NeedRIGHT();
1991 break;
1992
1993 case T_blind_buried_vias_allowed:
1994 parseBool();
1996 NeedRIGHT();
1997 break;
1998
1999 case T_uvia_min_size:
2000 bds.m_MicroViasMinSize = parseBoardUnits( T_uvia_min_size );
2002 NeedRIGHT();
2003 break;
2004
2005 case T_uvia_min_drill:
2006 bds.m_MicroViasMinDrill = parseBoardUnits( T_uvia_min_drill );
2008 NeedRIGHT();
2009 break;
2010
2011 case T_user_diff_pair:
2012 {
2013 int width = parseBoardUnits( "user diff-pair width" );
2014 int gap = parseBoardUnits( "user diff-pair gap" );
2015 int viaGap = parseBoardUnits( "user diff-pair via gap" );
2016 DIFF_PAIR_DIMENSION diffPair( width, gap, viaGap );
2017
2019 bds.m_DiffPairDimensionsList.emplace_back( diffPair );
2020
2022 NeedRIGHT();
2023 break;
2024 }
2025
2026 case T_segment_width: // note: legacy (pre-6.0) token
2027 bds.m_LineThickness[ LAYER_CLASS_COPPER ] = parseBoardUnits( T_segment_width );
2029 NeedRIGHT();
2030 break;
2031
2032 case T_edge_width: // note: legacy (pre-6.0) token
2033 bds.m_LineThickness[ LAYER_CLASS_EDGES ] = parseBoardUnits( T_edge_width );
2035 NeedRIGHT();
2036 break;
2037
2038 case T_mod_edge_width: // note: legacy (pre-6.0) token
2039 bds.m_LineThickness[ LAYER_CLASS_SILK ] = parseBoardUnits( T_mod_edge_width );
2041 NeedRIGHT();
2042 break;
2043
2044 case T_pcb_text_width: // note: legacy (pre-6.0) token
2045 bds.m_TextThickness[ LAYER_CLASS_COPPER ] = parseBoardUnits( T_pcb_text_width );
2047 NeedRIGHT();
2048 break;
2049
2050 case T_mod_text_width: // note: legacy (pre-6.0) token
2051 bds.m_TextThickness[ LAYER_CLASS_SILK ] = parseBoardUnits( T_mod_text_width );
2053 NeedRIGHT();
2054 break;
2055
2056 case T_pcb_text_size: // note: legacy (pre-6.0) token
2057 bds.m_TextSize[ LAYER_CLASS_COPPER ].x = parseBoardUnits( "pcb text width" );
2058 bds.m_TextSize[ LAYER_CLASS_COPPER ].y = parseBoardUnits( "pcb text height" );
2060 NeedRIGHT();
2061 break;
2062
2063 case T_mod_text_size: // note: legacy (pre-6.0) token
2064 bds.m_TextSize[ LAYER_CLASS_SILK ].x = parseBoardUnits( "footprint text width" );
2065 bds.m_TextSize[ LAYER_CLASS_SILK ].y = parseBoardUnits( "footprint text height" );
2067 NeedRIGHT();
2068 break;
2069
2070 case T_defaults:
2071 parseDefaults( bds );
2073 break;
2074
2075 case T_pad_size:
2076 {
2077 wxSize sz;
2078 sz.SetWidth( parseBoardUnits( "master pad width" ) );
2079 sz.SetHeight( parseBoardUnits( "master pad height" ) );
2080 bds.m_Pad_Master->SetSize( sz );
2082 NeedRIGHT();
2083 break;
2084 }
2085
2086 case T_pad_drill:
2087 {
2088 int drillSize = parseBoardUnits( T_pad_drill );
2089 bds.m_Pad_Master->SetDrillSize( wxSize( drillSize, drillSize ) );
2091 NeedRIGHT();
2092 break;
2093 }
2094
2095 case T_pad_to_mask_clearance:
2096 bds.m_SolderMaskExpansion = parseBoardUnits( T_pad_to_mask_clearance );
2097 NeedRIGHT();
2098 break;
2099
2100 case T_solder_mask_min_width:
2101 bds.m_SolderMaskMinWidth = parseBoardUnits( T_solder_mask_min_width );
2102 NeedRIGHT();
2103 break;
2104
2105 case T_pad_to_paste_clearance:
2106 bds.m_SolderPasteMargin = parseBoardUnits( T_pad_to_paste_clearance );
2107 NeedRIGHT();
2108 break;
2109
2110 case T_pad_to_paste_clearance_ratio:
2111 bds.m_SolderPasteMarginRatio = parseDouble( T_pad_to_paste_clearance_ratio );
2112 NeedRIGHT();
2113 break;
2114
2115 case T_allow_soldermask_bridges_in_footprints:
2117 NeedRIGHT();
2118 break;
2119
2120 case T_aux_axis_origin:
2121 {
2122 int x = parseBoardUnits( "auxiliary origin X" );
2123 int y = parseBoardUnits( "auxiliary origin Y" );
2124 bds.SetAuxOrigin( VECTOR2I( x, y ) );
2125
2126 // Aux origin still stored in board for the moment
2127 //m_board->m_LegacyDesignSettingsLoaded = true;
2128 NeedRIGHT();
2129 break;
2130 }
2131
2132 case T_grid_origin:
2133 {
2134 int x = parseBoardUnits( "grid origin X" );
2135 int y = parseBoardUnits( "grid origin Y" );
2136 bds.SetGridOrigin( VECTOR2I( x, y ) );
2137 // Grid origin still stored in board for the moment
2138 //m_board->m_LegacyDesignSettingsLoaded = true;
2139 NeedRIGHT();
2140 break;
2141 }
2142
2143 // Stored in board prior to 6.0
2144 case T_visible_elements:
2145 {
2146 // Make sure to start with DefaultVisible so all new layers are set
2148
2149 int visible = parseHex() | MIN_VISIBILITY_MASK;
2150
2151 for( size_t i = 0; i < sizeof( int ) * CHAR_BIT; i++ )
2152 m_board->m_LegacyVisibleItems.set( i, visible & ( 1u << i ) );
2153
2154 NeedRIGHT();
2155 break;
2156 }
2157
2158 case T_max_error:
2159 bds.m_MaxError = parseBoardUnits( T_max_error );
2161 NeedRIGHT();
2162 break;
2163
2164 case T_filled_areas_thickness:
2165 if( parseBool() )
2166 {
2168 {
2169 // Thick outline fill mode no longer supported. Make sure user is OK with
2170 // converting fills.
2171 KIDIALOG dlg( nullptr, _( "The legacy zone fill strategy is no longer "
2172 "supported.\nConvert zones to smoothed polygon "
2173 "fills?" ),
2174 _( "Legacy Zone Warning" ), wxYES_NO | wxICON_WARNING );
2175
2176 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
2177
2178 if( dlg.ShowModal() == wxID_NO )
2179 THROW_IO_ERROR( wxT( "CANCEL" ) );
2180
2182 }
2183 }
2184
2185 NeedRIGHT();
2186 break;
2187
2188 case T_pcbplotparams:
2189 {
2190 PCB_PLOT_PARAMS plotParams;
2191 PCB_PLOT_PARAMS_PARSER parser( reader );
2192 // parser must share the same current line as our current PCB parser
2193 // synchronize it.
2194 parser.SyncLineReaderWith( *this );
2195
2196 plotParams.Parse( &parser );
2197 SyncLineReaderWith( parser );
2198
2199 m_board->SetPlotOptions( plotParams );
2200 break;
2201 }
2202
2203 default:
2204 Unexpected( CurText() );
2205 }
2206 }
2207}
Container for design settings for a BOARD object.
void SetGridOrigin(const VECTOR2I &aOrigin)
std::vector< DIFF_PAIR_DIMENSION > m_DiffPairDimensionsList
std::unique_ptr< PAD > m_Pad_Master
void SetAuxOrigin(const VECTOR2I &aOrigin)
std::vector< int > m_TrackWidthList
int m_LineThickness[LAYER_CLASS_COUNT]
ZONE_SETTINGS & GetDefaultZoneSettings()
std::vector< VIA_DIMENSION > m_ViasDimensionsList
void SetPlotOptions(const PCB_PLOT_PARAMS &aOptions)
Definition: board.h:630
bool m_LegacyDesignSettingsLoaded
True if the legacy board design settings were loaded from a file.
Definition: board.h:342
GAL_SET m_LegacyVisibleItems
Definition: board.h:339
GAL_SET & set()
Definition: layer_ids.h:311
static GAL_SET DefaultVisible()
Definition: lset.cpp:960
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition: confirm.h:46
void parseBoardStackup()
void parseDefaults(BOARD_DESIGN_SETTINGS &aSettings)
bool parseBool()
Definition: pcb_parser.cpp:213
The parser for PCB_PLOT_PARAMS.
Parameters and options when plotting/printing a board.
void Parse(PCB_PLOT_PARAMS_PARSER *aParser)
ZONE_SETTINGS handles zones parameters.
Definition: zone_settings.h:70
#define MIN_VISIBILITY_MASK
Definition: layer_ids.h:463
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition: kicad_algo.h:99
Container to handle a stock of specific differential pairs each with unique track width,...
Container to handle a stock of specific vias each with unique diameter and drill sizes in the BOARD c...

References _, alg::contains(), GAL_SET::DefaultVisible(), KIDIALOG::DoNotShowCheckbox(), BOARD_DESIGN_SETTINGS::GetDefaultZoneSettings(), BOARD::GetDesignSettings(), LAYER_CLASS_COPPER, LAYER_CLASS_EDGES, LAYER_CLASS_SILK, BOARD_DESIGN_SETTINGS::m_AllowSoldermaskBridgesInFPs, m_appendToExisting, m_board, BOARD_DESIGN_SETTINGS::m_DiffPairDimensionsList, BOARD_DESIGN_SETTINGS::m_HoleToHoleMin, BOARD::m_LegacyDesignSettingsLoaded, BOARD::m_LegacyVisibleItems, BOARD_DESIGN_SETTINGS::m_LineThickness, BOARD_DESIGN_SETTINGS::m_MaxError, BOARD_DESIGN_SETTINGS::m_MicroViasMinDrill, BOARD_DESIGN_SETTINGS::m_MicroViasMinSize, BOARD_DESIGN_SETTINGS::m_MinClearance, BOARD_DESIGN_SETTINGS::m_MinThroughDrill, BOARD_DESIGN_SETTINGS::m_NetSettings, BOARD_DESIGN_SETTINGS::m_Pad_Master, m_showLegacy5ZoneWarning, BOARD_DESIGN_SETTINGS::m_SolderMaskExpansion, BOARD_DESIGN_SETTINGS::m_SolderMaskMinWidth, BOARD_DESIGN_SETTINGS::m_SolderPasteMargin, BOARD_DESIGN_SETTINGS::m_SolderPasteMarginRatio, BOARD_DESIGN_SETTINGS::m_TextSize, BOARD_DESIGN_SETTINGS::m_TextThickness, BOARD_DESIGN_SETTINGS::m_TrackMinWidth, BOARD_DESIGN_SETTINGS::m_TrackWidthList, BOARD_DESIGN_SETTINGS::m_ViasDimensionsList, BOARD_DESIGN_SETTINGS::m_ViasMinAnnularWidth, BOARD_DESIGN_SETTINGS::m_ViasMinSize, ZONE_SETTINGS::m_ZoneClearance, MIN_VISIBILITY_MASK, PCB_PLOT_PARAMS::Parse(), parseBoardStackup(), parseBoardUnits(), parseBool(), parseDefaults(), parseDouble(), parseHex(), GAL_SET::set(), BOARD_DESIGN_SETTINGS::SetAuxOrigin(), BOARD_DESIGN_SETTINGS::SetGridOrigin(), BOARD::SetPlotOptions(), KIDIALOG::ShowModal(), THROW_IO_ERROR, and via.

Referenced by parseBOARD_unchecked().

◆ parseTITLE_BLOCK()

void PCB_PARSER::parseTITLE_BLOCK ( )
private

Definition at line 1218 of file pcb_parser.cpp.

1219{
1220 wxCHECK_RET( CurTok() == T_title_block,
1221 wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as TITLE_BLOCK." ) );
1222
1223 T token;
1224 TITLE_BLOCK titleBlock;
1225
1226 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1227 {
1228 if( token != T_LEFT )
1229 Expecting( T_LEFT );
1230
1231 token = NextTok();
1232
1233 switch( token )
1234 {
1235 case T_title:
1236 NextTok();
1237 titleBlock.SetTitle( FromUTF8() );
1238 break;
1239
1240 case T_date:
1241 NextTok();
1242 titleBlock.SetDate( FromUTF8() );
1243 break;
1244
1245 case T_rev:
1246 NextTok();
1247 titleBlock.SetRevision( FromUTF8() );
1248 break;
1249
1250 case T_company:
1251 NextTok();
1252 titleBlock.SetCompany( FromUTF8() );
1253 break;
1254
1255 case T_comment:
1256 {
1257 int commentNumber = parseInt( "comment" );
1258
1259 switch( commentNumber )
1260 {
1261 case 1:
1262 NextTok();
1263 titleBlock.SetComment( 0, FromUTF8() );
1264 break;
1265
1266 case 2:
1267 NextTok();
1268 titleBlock.SetComment( 1, FromUTF8() );
1269 break;
1270
1271 case 3:
1272 NextTok();
1273 titleBlock.SetComment( 2, FromUTF8() );
1274 break;
1275
1276 case 4:
1277 NextTok();
1278 titleBlock.SetComment( 3, FromUTF8() );
1279 break;
1280
1281 case 5:
1282 NextTok();
1283 titleBlock.SetComment( 4, FromUTF8() );
1284 break;
1285
1286 case 6:
1287 NextTok();
1288 titleBlock.SetComment( 5, FromUTF8() );
1289 break;
1290
1291 case 7:
1292 NextTok();
1293 titleBlock.SetComment( 6, FromUTF8() );
1294 break;
1295
1296 case 8:
1297 NextTok();
1298 titleBlock.SetComment( 7, FromUTF8() );
1299 break;
1300
1301 case 9:
1302 NextTok();
1303 titleBlock.SetComment( 8, FromUTF8() );
1304 break;
1305
1306 default:
1307 wxString err;
1308 err.Printf( wxT( "%d is not a valid title block comment number" ), commentNumber );
1309 THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
1310 }
1311
1312 break;
1313 }
1314
1315 default:
1316 Expecting( "title, date, rev, company, or comment" );
1317 }
1318
1319 NeedRIGHT();
1320 }
1321
1322 m_board->SetTitleBlock( titleBlock );
1323}
void SetTitleBlock(const TITLE_BLOCK &aTitleBlock)
Definition: board.h:634
Hold the information shown in the lower right corner of a plot, printout, or editing view.
Definition: title_block.h:41
void SetRevision(const wxString &aRevision)
Definition: title_block.h:81
void SetComment(int aIdx, const wxString &aComment)
Definition: title_block.h:101
void SetTitle(const wxString &aTitle)
Definition: title_block.h:58
void SetCompany(const wxString &aCompany)
Definition: title_block.h:91
void SetDate(const wxString &aDate)
Set the date field, and defaults to the current time and date.
Definition: title_block.h:71

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

Referenced by parseBOARD_unchecked().

◆ parseXY() [1/2]

VECTOR2I PCB_PARSER::parseXY ( )
private

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

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

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

Definition at line 252 of file pcb_parser.cpp.

253{
254 if( CurTok() != T_LEFT )
255 NeedLEFT();
256
257 VECTOR2I pt;
258 T token = NextTok();
259
260 if( token != T_xy )
261 Expecting( T_xy );
262
263 pt.x = parseBoardUnits( "X coordinate" );
264 pt.y = parseBoardUnits( "Y coordinate" );
265
266 NeedRIGHT();
267
268 return pt;
269}

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

Referenced by parseDIMENSION(), parseFP_SHAPE(), parsePCB_SHAPE(), parseXY(), and parseZONE().

◆ parseXY() [2/2]

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

Definition at line 357 of file pcb_parser.cpp.

358{
359 VECTOR2I pt = parseXY();
360
361 if( aX )
362 *aX = pt.x;
363
364 if( aY )
365 *aY = pt.y;
366}

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

◆ parseZONE()

ZONE * PCB_PARSER::parseZONE ( BOARD_ITEM_CONTAINER aParent)
private

Definition at line 5502 of file pcb_parser.cpp.

5503{
5504 wxCHECK_MSG( CurTok() == T_zone, nullptr,
5505 wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as ZONE." ) );
5506
5508
5509 int hatchPitch = ZONE::GetDefaultHatchPitch();
5510 VECTOR2I pt;
5511 T token;
5512 int tmp;
5513 wxString netnameFromfile; // the zone net name find in file
5514
5515 // bigger scope since each filled_polygon is concatenated in here
5516 std::map<PCB_LAYER_ID, SHAPE_POLY_SET> pts;
5517 bool inFootprint = false;
5518 PCB_LAYER_ID filledLayer;
5519 bool addedFilledPolygons = false;
5520 bool dropFilledPolygons = false;
5521
5522 if( dynamic_cast<FOOTPRINT*>( aParent ) ) // The zone belongs a footprint
5523 inFootprint = true;
5524
5525 std::unique_ptr<ZONE> zone;
5526
5527 if( inFootprint )
5528 zone = std::make_unique<FP_ZONE>( aParent );
5529 else
5530 zone = std::make_unique<ZONE>( aParent );
5531
5532 zone->SetAssignedPriority( 0 );
5533
5534 // This is the default for board files:
5535 zone->SetIslandRemovalMode( ISLAND_REMOVAL_MODE::ALWAYS );
5536
5537 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
5538 {
5539 if( token == T_locked )
5540 {
5541 zone->SetLocked( true );
5542 token = NextTok();
5543 }
5544
5545 if( token == T_LEFT )
5546 token = NextTok();
5547
5548 switch( token )
5549 {
5550 case T_net:
5551 // Init the net code only, not the netname, to be sure
5552 // the zone net name is the name read in file.
5553 // (When mismatch, the user will be prompted in DRC, to fix the actual name)
5554 tmp = getNetCode( parseInt( "net number" ) );
5555
5556 if( tmp < 0 )
5557 tmp = 0;
5558
5559 if( !zone->SetNetCode( tmp, /* aNoAssert */ true ) )
5560 {
5561 wxLogError( _( "Invalid net ID in\nfile: %s;\nline: %d\noffset: %d." ),
5562 CurSource(), CurLineNumber(), CurOffset() );
5563 }
5564
5565 NeedRIGHT();
5566 break;
5567
5568 case T_net_name:
5569 NeedSYMBOLorNUMBER();
5570 netnameFromfile = FromUTF8();
5571 NeedRIGHT();
5572 break;
5573
5574 case T_layer: // keyword for zones that are on only one layer
5575 zone->SetLayer( parseBoardItemLayer() );
5576 NeedRIGHT();
5577 break;
5578
5579 case T_layers: // keyword for zones that can live on a set of layers
5580 zone->SetLayerSet( parseBoardItemLayersAsMask() );
5581 break;
5582
5583 case T_tstamp:
5584 NextTok();
5585 const_cast<KIID&>( zone->m_Uuid ) = CurStrToKIID();
5586 NeedRIGHT();
5587 break;
5588
5589 case T_hatch:
5590 token = NextTok();
5591
5592 if( token != T_none && token != T_edge && token != T_full )
5593 Expecting( "none, edge, or full" );
5594
5595 switch( token )
5596 {
5597 default:
5598 case T_none: hatchStyle = ZONE_BORDER_DISPLAY_STYLE::NO_HATCH; break;
5599 case T_edge: hatchStyle = ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_EDGE; break;
5600 case T_full: hatchStyle = ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_FULL; break;
5601 }
5602
5603 hatchPitch = parseBoardUnits( "hatch pitch" );
5604 NeedRIGHT();
5605 break;
5606
5607 case T_priority:
5608 zone->SetAssignedPriority( parseInt( "zone priority" ) );
5609 NeedRIGHT();
5610 break;
5611
5612 case T_connect_pads:
5613 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
5614 {
5615 if( token == T_LEFT )
5616 token = NextTok();
5617
5618 switch( token )
5619 {
5620 case T_yes:
5621 zone->SetPadConnection( ZONE_CONNECTION::FULL );
5622 break;
5623
5624