From a71857baaa520e9ddf21f5e3d4381a8e3c8b2aef Mon Sep 17 00:00:00 2001 From: Dick Hollenbeck Date: Sun, 10 Jun 2012 20:47:15 -0400 Subject: [PATCH] Commit Dick's Pcbnew s-expression file parser bug fixes. * Apply Dick's patch along with a few minor changes to fix some clashes with changes in my branch. Thanks Dick! * Added missing DRAWSEGMENT line angle. * Fix thru hole pad layer mask issue. --- CMakeLists.txt | 10 +- common/eda_text.cpp | 790 +++--- common/pcb.keywords | 1 + pcbnew/class_board_item.cpp | 22 +- pcbnew/class_zone.h | 3 +- pcbnew/kicad_plugin.cpp | 20 +- pcbnew/pcb_parser.cpp | 5079 ++++++++++++++++++----------------- pcbnew/pcb_parser.h | 430 +-- pcbnew/pcb_plot_params.cpp | 4 +- 9 files changed, 3232 insertions(+), 3127 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d89804dab9..b60bbbc28c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,11 +70,11 @@ else (KICAD_STABLE_VERSION ) endif(KICAD_STABLE_VERSION ) # Nanometers must be enabled when USE_PCBNEW_SEXPR_FILE_FORMAT=ON. -if( USE_PCBNEW_SEXPR_FILE_FORMAT AND NOT USE_PCBNEW_NANOMETRES ) - set( TMP "The Pcbnew s-expression file format requires nano-meter internal units to be " ) - set( TMP "${TMP} enabled using -DUSE_PCBNEW_NANOMETRES=ON." ) - message( FATAL_ERROR ${TMP} ) -endif( USE_PCBNEW_SEXPR_FILE_FORMAT AND NOT USE_PCBNEW_NANOMETRES ) +#if( USE_PCBNEW_SEXPR_FILE_FORMAT AND NOT USE_PCBNEW_NANOMETRES ) +# set( TMP "The Pcbnew s-expression file format requires nano-meter internal units to be " ) +# set( TMP "${TMP} enabled using -DUSE_PCBNEW_NANOMETRES=ON." ) +# message( FATAL_ERROR ${TMP} ) +#endif( USE_PCBNEW_SEXPR_FILE_FORMAT AND NOT USE_PCBNEW_NANOMETRES ) #================================================ # Set flags for GCC. diff --git a/common/eda_text.cpp b/common/eda_text.cpp index b1073f847e..2a60aa2605 100644 --- a/common/eda_text.cpp +++ b/common/eda_text.cpp @@ -1,395 +1,395 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2004 Jean-Pierre Charras, jean-pierre.charras@gipsa-lab.inpg.com - * Copyright (C) 2004-2011 KiCad Developers, see change_log.txt for contributors. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you may find one here: - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * or you may search the http://www.gnu.org website for the version 2 license, - * or you may write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -/** - * @file eda_text.cpp - * @brief Implementation of base KiCad text object. - */ - -#include -#include -#include // MAX -#include // RotatePoint -#include // EDA_DRAW_PANEL - - -// Conversion to application internal units defined at build time. -#if defined( PCBNEW ) -#include -#define MILS_TO_IU( x ) ( x * IU_PER_MILS ); -#elif defined( EESCHEMA ) -#include -#define MILS_TO_IU( x ) ( x ) -#else -#error "Cannot resolve units formatting due to no definition of EESCHEMA or PCBNEW." -#endif - - -EDA_TEXT::EDA_TEXT( const wxString& text ) -{ - m_Size.x = m_Size.y = MILS_TO_IU( DEFAULT_SIZE_TEXT ); // Width and height of font. - m_Orient = 0; // Rotation angle in 0.1 degrees. - m_Attributs = 0; - m_Mirror = false; // display mirror if true - m_HJustify = GR_TEXT_HJUSTIFY_CENTER; // Default horizontal justification is centered. - m_VJustify = GR_TEXT_VJUSTIFY_CENTER; // Default vertical justification is centered. - m_Thickness = 0; // thickness - m_Italic = false; // true = italic shape. - m_Bold = false; - m_MultilineAllowed = false; // Set to true for multiline text. - m_Text = text; -} - - -EDA_TEXT::EDA_TEXT( const EDA_TEXT& aText ) -{ - m_Pos = aText.m_Pos; - m_Size = aText.m_Size; - m_Orient = aText.m_Orient; - m_Attributs = aText.m_Attributs; - m_Mirror = aText.m_Mirror; - m_HJustify = aText.m_HJustify; - m_VJustify = aText.m_VJustify; - m_Thickness = aText.m_Thickness; - m_Italic = aText.m_Italic; - m_Bold = aText.m_Bold; - m_MultilineAllowed = aText.m_MultilineAllowed; - m_Text = aText.m_Text; -} - - -EDA_TEXT::~EDA_TEXT() -{ -} - - -int EDA_TEXT::LenSize( const wxString& aLine ) const -{ - return ReturnGraphicTextWidth( aLine, m_Size.x, m_Italic, m_Bold ); -} - - -EDA_RECT EDA_TEXT::GetTextBox( int aLine, int aThickness, bool aInvertY ) const -{ - EDA_RECT rect; - wxPoint pos; - wxArrayString* list = NULL; - wxString text = m_Text; - int thickness = ( aThickness < 0 ) ? m_Thickness : aThickness; - - if( m_MultilineAllowed ) - { - list = wxStringSplit( m_Text, '\n' ); - - if ( list->GetCount() ) // GetCount() == 0 for void strings - { - if( aLine >= 0 && (aLine < (int)list->GetCount()) ) - text = list->Item( aLine ); - else - text = list->Item( 0 ); - } - } - - // calculate the H and V size - int dx = LenSize( text ); - int dy = GetInterline(); - - /* Creates bounding box (rectangle) for an horizontal text */ - wxSize textsize = wxSize( dx, dy ); - - if( aInvertY ) - rect.SetOrigin( m_Pos.x, -m_Pos.y ); - else - rect.SetOrigin( m_Pos ); - - // extra dy interval for letters like j and y and ] - int extra_dy = dy - m_Size.y; - rect.Move( wxPoint( 0, -extra_dy / 2 ) ); // move origin by the half extra interval - - // for multiline texts and aLine < 0, merge all rectangles - if( m_MultilineAllowed && list && aLine < 0 ) - { - for( unsigned ii = 1; ii < list->GetCount(); ii++ ) - { - text = list->Item( ii ); - dx = LenSize( text ); - textsize.x = MAX( textsize.x, dx ); - textsize.y += dy; - } - } - - delete list; - - rect.SetSize( textsize ); - - /* Now, calculate the rect origin, according to text justification - * At this point the rectangle origin is the text origin (m_Pos). - * This is true only for left and top text justified texts (using top to bottom Y axis - * orientation). and must be recalculated for others justifications - * also, note the V justification is relative to the first line - */ - switch( m_HJustify ) - { - case GR_TEXT_HJUSTIFY_LEFT: - if( m_Mirror ) - rect.SetX( rect.GetX() - rect.GetWidth() ); - break; - - case GR_TEXT_HJUSTIFY_CENTER: - rect.SetX( rect.GetX() - (rect.GetWidth() / 2) ); - break; - - case GR_TEXT_HJUSTIFY_RIGHT: - if( !m_Mirror ) - rect.SetX( rect.GetX() - rect.GetWidth() ); - break; - } - - dy = m_Size.y + thickness; - - switch( m_VJustify ) - { - case GR_TEXT_VJUSTIFY_TOP: - break; - - case GR_TEXT_VJUSTIFY_CENTER: - rect.SetY( rect.GetY() - (dy / 2) ); - break; - - case GR_TEXT_VJUSTIFY_BOTTOM: - rect.SetY( rect.GetY() - dy ); - break; - } - - rect.Inflate( thickness / 2 ); - rect.Normalize(); // Make h and v sizes always >= 0 - - return rect; -} - - -bool EDA_TEXT::TextHitTest( const wxPoint& aPoint, int aAccuracy ) const -{ - EDA_RECT rect = GetTextBox( -1 ); // Get the full text area. - wxPoint location = aPoint; - - rect.Inflate( aAccuracy ); - RotatePoint( &location, m_Pos, -m_Orient ); - - return rect.Contains( location ); -} - - -bool EDA_TEXT::TextHitTest( const EDA_RECT& aRect, bool aContains, int aAccuracy ) const -{ - EDA_RECT rect = aRect; - - rect.Inflate( aAccuracy ); - - if( aContains ) - return rect.Contains( GetTextBox( -1 ) ); - - return rect.Intersects( GetTextBox( -1 ) ); -} - - -void EDA_TEXT::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, - EDA_COLOR_T aColor, int aDrawMode, - EDA_DRAW_MODE_T aFillMode, EDA_COLOR_T aAnchor_color ) -{ - if( m_MultilineAllowed ) - { - wxPoint pos = m_Pos; - wxArrayString* list = wxStringSplit( m_Text, '\n' ); - wxPoint offset; - - offset.y = GetInterline(); - - RotatePoint( &offset, m_Orient ); - - for( unsigned i = 0; iCount(); i++ ) - { - wxString txt = list->Item( i ); - DrawOneLineOfText( aPanel, - aDC, - aOffset, - aColor, - aDrawMode, - aFillMode, - i ? UNSPECIFIED : aAnchor_color, - txt, - pos ); - pos += offset; - } - - delete (list); - } - else - DrawOneLineOfText( aPanel, - aDC, - aOffset, - aColor, - aDrawMode, - aFillMode, - aAnchor_color, - m_Text, - m_Pos ); -} - - -void EDA_TEXT::DrawOneLineOfText( EDA_DRAW_PANEL* aPanel, wxDC* aDC, - const wxPoint& aOffset, EDA_COLOR_T aColor, - int aDrawMode, EDA_DRAW_MODE_T aFillMode, - EDA_COLOR_T aAnchor_color, - wxString& aText, wxPoint aPos ) -{ - int width = m_Thickness; - - if( aFillMode == LINE ) - width = 0; - - if( aDrawMode != -1 ) - GRSetDrawMode( aDC, aDrawMode ); - - /* Draw text anchor, if allowed */ - if( aAnchor_color != UNSPECIFIED ) - { - - int anchor_size = aDC->DeviceToLogicalXRel( 2 ); - - aAnchor_color = (EDA_COLOR_T) ( aAnchor_color & MASKCOLOR ); - - int cX = aPos.x + aOffset.x; - int cY = aPos.y + aOffset.y; - - GRLine( aPanel->GetClipBox(), aDC, cX - anchor_size, cY, - cX + anchor_size, cY, 0, aAnchor_color ); - - GRLine( aPanel->GetClipBox(), aDC, cX, cY - anchor_size, - cX, cY + anchor_size, 0, aAnchor_color ); - } - - if( aFillMode == SKETCH ) - width = -width; - - wxSize size = m_Size; - - if( m_Mirror ) - size.x = -size.x; - - DrawGraphicText( aPanel, aDC, aOffset + aPos, aColor, aText, m_Orient, size, - m_HJustify, m_VJustify, width, m_Italic, m_Bold ); -} - - -wxString EDA_TEXT::GetTextStyleName() -{ - int style = 0; - - if( m_Italic ) - style = 1; - - if( m_Bold ) - style += 2; - - wxString stylemsg[4] = { - _("Normal"), - _("Italic"), - _("Bold"), - _("Bold+Italic") - }; - - return stylemsg[style]; -} - - -bool EDA_TEXT::IsDefaultFormatting() const -{ - return ( ( m_Size.x == DEFAULT_SIZE_TEXT ) - && ( m_Size.y == DEFAULT_SIZE_TEXT ) - && ( m_Attributs == 0 ) - && ( m_Mirror == false ) - && ( m_HJustify == GR_TEXT_HJUSTIFY_CENTER ) - && ( m_VJustify == GR_TEXT_VJUSTIFY_CENTER ) - && ( m_Thickness == 0 ) - && ( m_Italic == false ) - && ( m_Bold == false ) - && ( m_MultilineAllowed == false ) ); -} - - -void EDA_TEXT::Format( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aControlBits ) const - throw( IO_ERROR ) -{ - if( !IsDefaultFormatting() ) - { - aFormatter->Print( aNestLevel+1, "(effects\n" ); - - if( ( m_Size.x != DEFAULT_SIZE_TEXT ) || ( m_Size.y != DEFAULT_SIZE_TEXT ) || m_Bold - || m_Italic ) - { - aFormatter->Print( aNestLevel+2, "(font" ); - - // Add font support here at some point in the future. - - if( ( m_Size.x != DEFAULT_SIZE_TEXT ) || ( m_Size.y != DEFAULT_SIZE_TEXT ) ) - aFormatter->Print( 0, " (size %s %s)", FMT_IU( m_Size.GetHeight() ).c_str(), - FMT_IU( m_Size.GetWidth() ).c_str() ); - - if( m_Thickness != 0 ) - aFormatter->Print( 0, " (thickness %s)", FMT_IU( m_Thickness ).c_str() ); - - if( m_Bold ) - aFormatter->Print( 0, " bold" ); - - if( m_Bold ) - aFormatter->Print( 0, " italic" ); - - aFormatter->Print( 0, ")\n"); - } - - if( m_Mirror || ( m_HJustify != GR_TEXT_HJUSTIFY_CENTER ) - || ( m_VJustify != GR_TEXT_VJUSTIFY_CENTER ) ) - { - aFormatter->Print( aNestLevel+2, "(justify"); - - if( m_HJustify != GR_TEXT_HJUSTIFY_CENTER ) - aFormatter->Print( 0, (m_HJustify == GR_TEXT_HJUSTIFY_LEFT) ? " left" : " right" ); - - if( m_VJustify != GR_TEXT_VJUSTIFY_CENTER ) - aFormatter->Print( 0, (m_VJustify == GR_TEXT_VJUSTIFY_TOP) ? " top" : " bottom" ); - - if( m_Mirror ) - aFormatter->Print( 0, " mirror" ); - - aFormatter->Print( 0, ")\n" ); - } - - // As of now the only place this is used is in Eeschema to hide or show the text. - if( m_Attributs ) - aFormatter->Print( aNestLevel+2, "hide\n" ); - - aFormatter->Print( aNestLevel+1, ")\n" ); - } -} +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jean-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2004-2011 KiCad Developers, see change_log.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * @file eda_text.cpp + * @brief Implementation of base KiCad text object. + */ + +#include +#include +#include // MAX +#include // RotatePoint +#include // EDA_DRAW_PANEL + + +// Conversion to application internal units defined at build time. +#if defined( PCBNEW ) +#include +#define MILS_TO_IU( x ) ( x * IU_PER_MILS ); +#elif defined( EESCHEMA ) +#include +#define MILS_TO_IU( x ) ( x ) +#else +#error "Cannot resolve units formatting due to no definition of EESCHEMA or PCBNEW." +#endif + + +EDA_TEXT::EDA_TEXT( const wxString& text ) +{ + m_Size.x = m_Size.y = MILS_TO_IU( DEFAULT_SIZE_TEXT ); // Width and height of font. + m_Orient = 0; // Rotation angle in 0.1 degrees. + m_Attributs = 0; + m_Mirror = false; // display mirror if true + m_HJustify = GR_TEXT_HJUSTIFY_CENTER; // Default horizontal justification is centered. + m_VJustify = GR_TEXT_VJUSTIFY_CENTER; // Default vertical justification is centered. + m_Thickness = 0; // thickness + m_Italic = false; // true = italic shape. + m_Bold = false; + m_MultilineAllowed = false; // Set to true for multiline text. + m_Text = text; +} + + +EDA_TEXT::EDA_TEXT( const EDA_TEXT& aText ) +{ + m_Pos = aText.m_Pos; + m_Size = aText.m_Size; + m_Orient = aText.m_Orient; + m_Attributs = aText.m_Attributs; + m_Mirror = aText.m_Mirror; + m_HJustify = aText.m_HJustify; + m_VJustify = aText.m_VJustify; + m_Thickness = aText.m_Thickness; + m_Italic = aText.m_Italic; + m_Bold = aText.m_Bold; + m_MultilineAllowed = aText.m_MultilineAllowed; + m_Text = aText.m_Text; +} + + +EDA_TEXT::~EDA_TEXT() +{ +} + + +int EDA_TEXT::LenSize( const wxString& aLine ) const +{ + return ReturnGraphicTextWidth( aLine, m_Size.x, m_Italic, m_Bold ); +} + + +EDA_RECT EDA_TEXT::GetTextBox( int aLine, int aThickness, bool aInvertY ) const +{ + EDA_RECT rect; + wxPoint pos; + wxArrayString* list = NULL; + wxString text = m_Text; + int thickness = ( aThickness < 0 ) ? m_Thickness : aThickness; + + if( m_MultilineAllowed ) + { + list = wxStringSplit( m_Text, '\n' ); + + if ( list->GetCount() ) // GetCount() == 0 for void strings + { + if( aLine >= 0 && (aLine < (int)list->GetCount()) ) + text = list->Item( aLine ); + else + text = list->Item( 0 ); + } + } + + // calculate the H and V size + int dx = LenSize( text ); + int dy = GetInterline(); + + /* Creates bounding box (rectangle) for an horizontal text */ + wxSize textsize = wxSize( dx, dy ); + + if( aInvertY ) + rect.SetOrigin( m_Pos.x, -m_Pos.y ); + else + rect.SetOrigin( m_Pos ); + + // extra dy interval for letters like j and y and ] + int extra_dy = dy - m_Size.y; + rect.Move( wxPoint( 0, -extra_dy / 2 ) ); // move origin by the half extra interval + + // for multiline texts and aLine < 0, merge all rectangles + if( m_MultilineAllowed && list && aLine < 0 ) + { + for( unsigned ii = 1; ii < list->GetCount(); ii++ ) + { + text = list->Item( ii ); + dx = LenSize( text ); + textsize.x = MAX( textsize.x, dx ); + textsize.y += dy; + } + } + + delete list; + + rect.SetSize( textsize ); + + /* Now, calculate the rect origin, according to text justification + * At this point the rectangle origin is the text origin (m_Pos). + * This is true only for left and top text justified texts (using top to bottom Y axis + * orientation). and must be recalculated for others justifications + * also, note the V justification is relative to the first line + */ + switch( m_HJustify ) + { + case GR_TEXT_HJUSTIFY_LEFT: + if( m_Mirror ) + rect.SetX( rect.GetX() - rect.GetWidth() ); + break; + + case GR_TEXT_HJUSTIFY_CENTER: + rect.SetX( rect.GetX() - (rect.GetWidth() / 2) ); + break; + + case GR_TEXT_HJUSTIFY_RIGHT: + if( !m_Mirror ) + rect.SetX( rect.GetX() - rect.GetWidth() ); + break; + } + + dy = m_Size.y + thickness; + + switch( m_VJustify ) + { + case GR_TEXT_VJUSTIFY_TOP: + break; + + case GR_TEXT_VJUSTIFY_CENTER: + rect.SetY( rect.GetY() - (dy / 2) ); + break; + + case GR_TEXT_VJUSTIFY_BOTTOM: + rect.SetY( rect.GetY() - dy ); + break; + } + + rect.Inflate( thickness / 2 ); + rect.Normalize(); // Make h and v sizes always >= 0 + + return rect; +} + + +bool EDA_TEXT::TextHitTest( const wxPoint& aPoint, int aAccuracy ) const +{ + EDA_RECT rect = GetTextBox( -1 ); // Get the full text area. + wxPoint location = aPoint; + + rect.Inflate( aAccuracy ); + RotatePoint( &location, m_Pos, -m_Orient ); + + return rect.Contains( location ); +} + + +bool EDA_TEXT::TextHitTest( const EDA_RECT& aRect, bool aContains, int aAccuracy ) const +{ + EDA_RECT rect = aRect; + + rect.Inflate( aAccuracy ); + + if( aContains ) + return rect.Contains( GetTextBox( -1 ) ); + + return rect.Intersects( GetTextBox( -1 ) ); +} + + +void EDA_TEXT::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset, + EDA_COLOR_T aColor, int aDrawMode, + EDA_DRAW_MODE_T aFillMode, EDA_COLOR_T aAnchor_color ) +{ + if( m_MultilineAllowed ) + { + wxPoint pos = m_Pos; + wxArrayString* list = wxStringSplit( m_Text, '\n' ); + wxPoint offset; + + offset.y = GetInterline(); + + RotatePoint( &offset, m_Orient ); + + for( unsigned i = 0; iCount(); i++ ) + { + wxString txt = list->Item( i ); + DrawOneLineOfText( aPanel, + aDC, + aOffset, + aColor, + aDrawMode, + aFillMode, + i ? UNSPECIFIED : aAnchor_color, + txt, + pos ); + pos += offset; + } + + delete (list); + } + else + DrawOneLineOfText( aPanel, + aDC, + aOffset, + aColor, + aDrawMode, + aFillMode, + aAnchor_color, + m_Text, + m_Pos ); +} + + +void EDA_TEXT::DrawOneLineOfText( EDA_DRAW_PANEL* aPanel, wxDC* aDC, + const wxPoint& aOffset, EDA_COLOR_T aColor, + int aDrawMode, EDA_DRAW_MODE_T aFillMode, + EDA_COLOR_T aAnchor_color, + wxString& aText, wxPoint aPos ) +{ + int width = m_Thickness; + + if( aFillMode == LINE ) + width = 0; + + if( aDrawMode != -1 ) + GRSetDrawMode( aDC, aDrawMode ); + + /* Draw text anchor, if allowed */ + if( aAnchor_color != UNSPECIFIED ) + { + + int anchor_size = aDC->DeviceToLogicalXRel( 2 ); + + aAnchor_color = (EDA_COLOR_T) ( aAnchor_color & MASKCOLOR ); + + int cX = aPos.x + aOffset.x; + int cY = aPos.y + aOffset.y; + + GRLine( aPanel->GetClipBox(), aDC, cX - anchor_size, cY, + cX + anchor_size, cY, 0, aAnchor_color ); + + GRLine( aPanel->GetClipBox(), aDC, cX, cY - anchor_size, + cX, cY + anchor_size, 0, aAnchor_color ); + } + + if( aFillMode == SKETCH ) + width = -width; + + wxSize size = m_Size; + + if( m_Mirror ) + size.x = -size.x; + + DrawGraphicText( aPanel, aDC, aOffset + aPos, aColor, aText, m_Orient, size, + m_HJustify, m_VJustify, width, m_Italic, m_Bold ); +} + + +wxString EDA_TEXT::GetTextStyleName() +{ + int style = 0; + + if( m_Italic ) + style = 1; + + if( m_Bold ) + style += 2; + + wxString stylemsg[4] = { + _("Normal"), + _("Italic"), + _("Bold"), + _("Bold+Italic") + }; + + return stylemsg[style]; +} + + +bool EDA_TEXT::IsDefaultFormatting() const +{ + return ( ( m_Size.x == DEFAULT_SIZE_TEXT ) + && ( m_Size.y == DEFAULT_SIZE_TEXT ) + && ( m_Attributs == 0 ) + && ( m_Mirror == false ) + && ( m_HJustify == GR_TEXT_HJUSTIFY_CENTER ) + && ( m_VJustify == GR_TEXT_VJUSTIFY_CENTER ) + && ( m_Thickness == 0 ) + && ( m_Italic == false ) + && ( m_Bold == false ) + && ( m_MultilineAllowed == false ) ); +} + + +void EDA_TEXT::Format( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aControlBits ) const + throw( IO_ERROR ) +{ + if( !IsDefaultFormatting() ) + { + aFormatter->Print( aNestLevel+1, "(effects\n" ); + + if( ( m_Size.x != DEFAULT_SIZE_TEXT ) || ( m_Size.y != DEFAULT_SIZE_TEXT ) || m_Bold + || m_Italic ) + { + aFormatter->Print( aNestLevel+2, "(font" ); + + // Add font support here at some point in the future. + + if( ( m_Size.x != DEFAULT_SIZE_TEXT ) || ( m_Size.y != DEFAULT_SIZE_TEXT ) ) + aFormatter->Print( 0, " (size %s %s)", FMT_IU( m_Size.GetHeight() ).c_str(), + FMT_IU( m_Size.GetWidth() ).c_str() ); + + if( m_Thickness != 0 ) + aFormatter->Print( 0, " (thickness %s)", FMT_IU( GetThickness() ).c_str() ); + + if( m_Bold ) + aFormatter->Print( 0, " bold" ); + + if( m_Bold ) + aFormatter->Print( 0, " italic" ); + + aFormatter->Print( 0, ")\n"); + } + + if( m_Mirror || ( m_HJustify != GR_TEXT_HJUSTIFY_CENTER ) + || ( m_VJustify != GR_TEXT_VJUSTIFY_CENTER ) ) + { + aFormatter->Print( aNestLevel+2, "(justify"); + + if( m_HJustify != GR_TEXT_HJUSTIFY_CENTER ) + aFormatter->Print( 0, (m_HJustify == GR_TEXT_HJUSTIFY_LEFT) ? " left" : " right" ); + + if( m_VJustify != GR_TEXT_VJUSTIFY_CENTER ) + aFormatter->Print( 0, (m_VJustify == GR_TEXT_VJUSTIFY_TOP) ? " top" : " bottom" ); + + if( m_Mirror ) + aFormatter->Print( 0, " mirror" ); + + aFormatter->Print( 0, ")\n" ); + } + + // As of now the only place this is used is in Eeschema to hide or show the text. + if( m_Attributs ) + aFormatter->Print( aNestLevel+2, "hide\n" ); + + aFormatter->Print( aNestLevel+1, ")\n" ); + } +} diff --git a/common/pcb.keywords b/common/pcb.keywords index 1896b02039..d80500bd69 100644 --- a/common/pcb.keywords +++ b/common/pcb.keywords @@ -120,6 +120,7 @@ page path pcb_text_size pcb_text_width +pcbplotparams placed plus polygon diff --git a/pcbnew/class_board_item.cpp b/pcbnew/class_board_item.cpp index 38352ea57d..be9891554f 100644 --- a/pcbnew/class_board_item.cpp +++ b/pcbnew/class_board_item.cpp @@ -93,13 +93,23 @@ std::string BOARD_ITEM::FormatInternalUnits( int aValue ) { char buf[50]; -#if defined( USE_PCBNEW_NANOMETRES ) - int nm = aValue; -#else - int nm = KIROUND( ( aValue / 10000.0 ) * 25.4 * 1e6 ); -#endif + double mm = aValue / IU_PER_MM; - int len = snprintf( buf, 49, "%g", nm / 1e6 ); + int len; + + if( mm != 0.0 && fabs( mm ) <= 0.0001 ) + { + len = sprintf( buf, "%.10f", mm ); + + while( --len > 0 && buf[len] == '0' ) + buf[len] = '\0'; + + ++len; + } + else + { + len = sprintf( buf, "%.10g", mm ); + } return std::string( buf, len ); } diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h index 376c330c4c..0e78d20895 100644 --- a/pcbnew/class_zone.h +++ b/pcbnew/class_zone.h @@ -209,6 +209,7 @@ public: const wxString& GetNetName() const { return m_Netname; }; void SetNetName( const wxString& aName ) { m_Netname = aName; } + /// How to fill areas: 0 = use filled polygons, 1 => fill with segments. void SetFillMode( int aFillMode ) { m_FillMode = aFillMode; } int GetFillMode() const { return m_FillMode; } @@ -550,7 +551,7 @@ public: int m_ZoneClearance; // clearance value int m_ZoneMinThickness; // Min thickness value in filled areas - // How to fill areas: 0 = use filled polygons, != 0 fill with segments. + /// How to fill areas: 0 => use filled polygons, 1 => fill with segments. int m_FillMode; // number of segments to convert a circle to a polygon (uses diff --git a/pcbnew/kicad_plugin.cpp b/pcbnew/kicad_plugin.cpp index a2a307f3e3..4a685c70e8 100644 --- a/pcbnew/kicad_plugin.cpp +++ b/pcbnew/kicad_plugin.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -324,6 +325,8 @@ void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const m_out->Print( aNestLevel+1, "(visible_elements %X)\n", aBoard->GetDesignSettings().GetVisibleElements() ); +// aBoard->GetPlotOptions().Format( m_out, aNestLevel+1 ); + m_out->Print( aNestLevel, ")\n\n" ); @@ -448,9 +451,10 @@ void PCB_IO::format( DRAWSEGMENT* aSegment, int aNestLevel ) const switch( aSegment->GetShape() ) { case S_SEGMENT: // Line - m_out->Print( aNestLevel, "(gr_line (pts (xy %s) (xy %s))", + m_out->Print( aNestLevel, "(gr_line (pts (xy %s) (xy %s)) (angle %s)", FMT_IU( aSegment->GetStart() ).c_str(), - FMT_IU( aSegment->GetEnd() ).c_str() ); + FMT_IU( aSegment->GetEnd() ).c_str(), + FMT_ANGLE( aSegment->GetAngle() ).c_str() ); break; case S_CIRCLE: // Circle @@ -863,11 +867,17 @@ void PCB_IO::format( TEXTE_MODULE* aText, int aNestLevel ) const if( parent ) orient += parent->GetOrientation(); - m_out->Print( aNestLevel, "(fp_text %s %s (at %s %s)%s\n", + m_out->Print( aNestLevel, "(fp_text %s %s (at %s %s)", m_out->Quotew( type ).c_str(), m_out->Quotew( aText->GetText() ).c_str(), - FMT_IU( aText->GetPos0() ).c_str(), FMT_ANGLE( orient ).c_str(), - (!aText->IsVisible()) ? " hide" : "" ); + FMT_IU( aText->GetPos0() ).c_str(), FMT_ANGLE( orient ).c_str() ); + + formatLayer( aText ); + + if( !aText->IsVisible() ) + m_out->Print( 0, " hide" ); + + m_out->Print( 0, "\n" ); aText->EDA_TEXT::Format( m_out, aNestLevel, m_ctl ); diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp index 7117aa5971..42989f85bd 100644 --- a/pcbnew/pcb_parser.cpp +++ b/pcbnew/pcb_parser.cpp @@ -1,2499 +1,2580 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2012 CERN - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you may find one here: - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * or you may search the http://www.gnu.org website for the version 2 license, - * or you may write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -/** - * @file pcb_parser.cpp - * @brief Pcbnew s-expression file format parser implementation. - */ - -#include -#include -#include -#include -#include <3d_struct.h> -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - - -double PCB_PARSER::parseDouble() throw( IO_ERROR ) -{ - char* tmp; - - errno = 0; - - double fval = strtod( CurText(), &tmp ); - - if( errno ) - { - wxString error; - error.Printf( _( "invalid floating point number in\nfile: '%s'\nline: %d\noffset: %d" ), - GetChars( CurSource() ), CurLineNumber(), CurOffset() ); - - THROW_IO_ERROR( error ); - } - - if( CurText() == tmp ) - { - wxString error; - error.Printf( _( "missing floating point number in\nfile: '%s'\nline: %d\noffset: %d" ), - GetChars( CurSource() ), CurLineNumber(), CurOffset() ); - - THROW_IO_ERROR( error ); - } - - return fval; -} - - -bool PCB_PARSER::parseBool() throw( PARSE_ERROR ) -{ - T token = NextTok(); - - if( token == T_yes ) - return true; - else if( token == T_no ) - return false; - else - Expecting( "yes or no" ); - - return false; -} - - -wxPoint PCB_PARSER::parseXY() throw( PARSE_ERROR ) -{ - if( CurTok() != T_LEFT ) - NeedLEFT(); - - wxPoint pt; - T token = NextTok(); - - if( token != T_xy ) - Expecting( T_xy ); - - pt.x = parseBoardUnits( "X coordinate" ); - pt.y = parseBoardUnits( "Y coordinate" ); - - NeedRIGHT(); - - return pt; -} - - -void PCB_PARSER::parseXY( int* aX, int* aY ) throw( PARSE_ERROR ) -{ - wxPoint pt = parseXY(); - - if( aX ) - *aX = pt.x; - - if( aY ) - *aY = pt.y; -} - - -void PCB_PARSER::parseEDA_TEXT( EDA_TEXT* aText ) throw( PARSE_ERROR ) -{ - wxCHECK_RET( CurTok() == T_effects, - wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as EDA_TEXT." ) ); - - T token; - - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - if( token != T_LEFT ) - Expecting( T_LEFT ); - - token = NextTok(); - - switch( token ) - { - case T_font: - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - if( token == T_LEFT ) - continue; - - switch( token ) - { - case T_size: - { - wxSize sz; - sz.SetHeight( parseBoardUnits( "text height" ) ); - sz.SetWidth( parseBoardUnits( "text width" ) ); - aText->SetSize( sz ); - NeedRIGHT(); - break; - } - - case T_thickness: - aText->SetThickness( parseBoardUnits( "text thickness" ) ); - NeedRIGHT(); - break; - - case T_bold: - aText->SetBold( true ); - break; - - case T_italic: - aText->SetItalic( true ); - break; - - default: - Expecting( "size, bold, or italic" ); - } - } - - break; - - case T_justify: - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - if( token == T_LEFT ) - continue; - - switch( token ) - { - case T_left: - aText->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT ); - break; - - case T_right: - aText->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT ); - break; - - case T_top: - aText->SetVertJustify( GR_TEXT_VJUSTIFY_TOP ); - break; - - case T_bottom: - aText->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM ); - break; - - case T_mirror: - aText->SetMirrored( true ); - break; - - default: - Expecting( "left, right, top, bottom, or mirror" ); - } - - } - break; - - case T_hide: - aText->SetVisible( false ); - break; - - default: - Expecting( "font, justify, or hide" ); - } - } -} - - -S3D_MASTER* PCB_PARSER::parse3DModel() throw( PARSE_ERROR ) -{ - wxCHECK_MSG( CurTok() == T_model, NULL, - wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as S3D_MASTER." ) ); - - T token; - - auto_ptr< S3D_MASTER > n3D( new S3D_MASTER( NULL ) ); - - NeedSYMBOL(); - n3D->m_Shape3DName = FromUTF8(); - - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - if( token != T_LEFT ) - Expecting( T_LEFT ); - - token = NextTok(); - - switch( token ) - { - case T_at: - NeedLEFT(); - token = NextTok(); - - if( token != T_xyz ) - Expecting( T_xyz ); - - n3D->m_MatPosition.x = parseDouble( "x value" ); - n3D->m_MatPosition.y = parseDouble( "y value" ); - n3D->m_MatPosition.z = parseDouble( "z value" ); - NeedRIGHT(); - break; - - case T_scale: - NeedLEFT(); - token = NextTok(); - - if( token != T_xyz ) - Expecting( T_xyz ); - - n3D->m_MatScale.x = parseDouble( "x value" ); - n3D->m_MatScale.y = parseDouble( "y value" ); - n3D->m_MatScale.z = parseDouble( "z value" ); - NeedRIGHT(); - break; - - case T_rotate: - NeedLEFT(); - token = NextTok(); - - if( token != T_xyz ) - Expecting( T_xyz ); - - n3D->m_MatRotation.x = parseDouble( "x value" ); - n3D->m_MatRotation.y = parseDouble( "y value" ); - n3D->m_MatRotation.z = parseDouble( "z value" ); - NeedRIGHT(); - break; - - default: - Expecting( "at, scale, or rotate" ); - } - - NeedRIGHT(); - } - - return n3D.release(); -} - - -BOARD_ITEM* PCB_PARSER::Parse() throw( IO_ERROR, PARSE_ERROR ) -{ - T token; - BOARD_ITEM* item; - - token = NextTok(); - - if( token != T_LEFT ) - Expecting( T_LEFT ); - - switch( NextTok() ) - { - case T_kicad_pcb: - if( m_board == NULL ) - m_board = new BOARD(); - - item = (BOARD_ITEM*) parseBOARD(); - break; - - default: - wxString err; - err.Printf( _( "unknown token \"%s\" " ), GetChars( FromUTF8() ) ); - THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() ); - } - - return item; -} - - -BOARD* PCB_PARSER::parseBOARD() throw( IO_ERROR, PARSE_ERROR ) -{ - T token; - - parseHeader(); - - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - if( token != T_LEFT ) - Expecting( T_LEFT ); - - token = NextTok(); - - switch( token ) - { - case T_general: - parseGeneralSection(); - break; - - case T_page: - parsePAGE_INFO(); - break; - - case T_title_block: - parseTITLE_BLOCK(); - break; - - case T_layers: - parseLayers(); - break; - - case T_setup: - parseSetup(); - break; - - case T_net: - parseNETINFO_ITEM(); - break; - - case T_net_class: - parseNETCLASS(); - break; - - case T_gr_arc: - case T_gr_circle: - case T_gr_curve: - case T_gr_line: - case T_gr_poly: - parseDRAWSEGMENT(); - break; - - case T_gr_text: - parseTEXTE_PCB(); - break; - - case T_dimension: - parseDIMENSION(); - break; - - case T_module: - parseMODULE(); - break; - - case T_segment: - m_board->Add( parseTRACK(), ADD_APPEND ); - break; - - case T_via: - m_board->Add( parseSEGVIA(), ADD_APPEND ); - break; - - case T_zone: - m_board->Add( parseZONE_CONTAINER(), ADD_APPEND ); - break; - - case T_target: - m_board->Add( parsePCB_TARGET(), ADD_APPEND ); - break; - - default: - wxString err; - err.Printf( _( "unknown token \"%s\"" ), GetChars( FromUTF8() ) ); - THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() ); - } - } - - return m_board; -} - - -void PCB_PARSER::parseHeader() throw( IO_ERROR, PARSE_ERROR ) -{ - wxCHECK_RET( CurTok() == T_kicad_pcb, - wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a header." ) ); - - T token; - - NeedLEFT(); - token = NextTok(); - - if( token != T_version ) - Expecting( GetTokenText( T_version ) ); - - // Get the file version. - m_board->SetFileFormatVersionAtLoad( NeedNUMBER( GetTokenText( T_version ) ) ); - - // Skip the host name and host build version information. - NeedRIGHT(); - NeedLEFT(); - NeedSYMBOL(); - NeedSYMBOL(); - NeedSYMBOL(); - NeedRIGHT(); -} - - -void PCB_PARSER::parseGeneralSection() throw( IO_ERROR, PARSE_ERROR ) -{ - wxCHECK_RET( CurTok() == T_general, - wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + - wxT( " as a general section." ) ); - - T token; - - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - if( token != T_LEFT ) - Expecting( T_LEFT ); - - token = NextTok(); - - switch( token ) - { - case T_thickness: - m_board->GetDesignSettings().SetBoardThickness( parseBoardUnits( T_thickness ) ); - NeedRIGHT(); - break; - - case T_no_connects: - m_board->m_NbNoconnect = parseInt( "no connect count" ); - NeedRIGHT(); - break; - - default: // Skip everything but the board thickness. - wxLogDebug( wxT( "Skipping general section token %s " ), GetTokenString( token ) ); - - while( ( token = NextTok() ) != T_RIGHT ) - { - if( !IsSymbol( token ) && token != T_NUMBER ) - Expecting( "symbol or number" ); - } - } - } -} - - -void PCB_PARSER::parsePAGE_INFO() throw( IO_ERROR, PARSE_ERROR ) -{ - wxCHECK_RET( CurTok() == T_page, - wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a PAGE_INFO." ) ); - - T token; - bool isPortrait = false; - - NeedSYMBOL(); - - wxString pageType = FromUTF8(); - - if( pageType == PAGE_INFO::Custom ) - { - PAGE_INFO::SetCustomWidthMils( Iu2Mils( NeedNUMBER( "width" ) ) ); - PAGE_INFO::SetCustomHeightMils( Iu2Mils( NeedNUMBER( "height" ) ) ); - } - - token = NextTok(); - - if( token == T_portrait ) - { - isPortrait = true; - NeedRIGHT(); - } - else if( token != T_RIGHT ) - { - Expecting( "portrait|)" ); - } - - PAGE_INFO pageInfo; - - if( !pageInfo.SetType( pageType, isPortrait ) ) - { - wxString err; - err.Printf( _( "page type \"%s\" is not valid " ), GetChars( FromUTF8() ) ); - THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() ); - } - - m_board->SetPageSettings( pageInfo ); -} - - -void PCB_PARSER::parseTITLE_BLOCK() throw( IO_ERROR, PARSE_ERROR ) -{ - wxCHECK_RET( CurTok() == T_title_block, - wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + - wxT( " as TITLE_BLOCK." ) ); - - T token; - TITLE_BLOCK titleBlock; - - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - if( token != T_LEFT ) - Expecting( T_LEFT ); - - token = NextTok(); - - switch( token ) - { - case T_title: - NeedSYMBOL(); - titleBlock.SetTitle( FromUTF8() ); - break; - - case T_date: - NeedSYMBOL(); - titleBlock.SetDate( FromUTF8() ); - break; - - case T_rev: - NeedSYMBOL(); - titleBlock.SetRevision( FromUTF8() ); - break; - - case T_comment: - { - int commentNumber = NeedNUMBER( "comment" ); - - switch( commentNumber ) - { - case 1: - NeedSYMBOL(); - titleBlock.SetComment1( FromUTF8() ); - break; - - case 2: - NeedSYMBOL(); - titleBlock.SetComment2( FromUTF8() ); - break; - - case 3: - NeedSYMBOL(); - titleBlock.SetComment3( FromUTF8() ); - break; - - case 4: - NeedSYMBOL(); - titleBlock.SetComment4( FromUTF8() ); - break; - - default: - wxString err; - err.Printf( _( "%d is not a valid title block comment number" ), commentNumber ); - THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() ); - } - - break; - } - - default: - Expecting( "title, date, rev, company, or comment" ); - } - - NeedRIGHT(); - } - - m_board->SetTitleBlock( titleBlock ); -} - - -void PCB_PARSER::parseLayers() throw( IO_ERROR, PARSE_ERROR ) -{ - wxCHECK_RET( CurTok() == T_layers, - wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as layers." ) ); - - T token; - wxString name; - wxString type; - bool isVisible; - int visibleLayers = 0; - int enabledLayers = 0; - std::vector< LAYER > layers; - - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - if( token != T_LEFT ) - Expecting( T_LEFT ); - -#if !USE_LAYER_NAMES - NeedNUMBER( "layer index" ); -#endif - - NeedSYMBOL(); - name = FromUTF8(); - NeedSYMBOL(); - type = FromUTF8(); - - token = NextTok(); - - if( token == T_hide ) - { - isVisible = false; - NeedRIGHT(); - } - else if( token == T_RIGHT ) - { - isVisible = true; - } - else - { - Expecting( "hide or )" ); - } - - layers.push_back( LAYER( name, LAYER::ParseType( type.c_str() ), isVisible ) ); - } - - int copperLayerCount = 0; - - for( unsigned i = 0; i < layers.size(); i++ ) - { - if( layers[i].m_Type != LT_UNDEFINED ) - copperLayerCount++; - } - - // We need at least 2 copper layers and there must be an even number of them. - if( (copperLayerCount < 2) || ((copperLayerCount % 2) != 0) ) - { - wxString err; - err.Printf( _( "%d is not a valid layer count" ), layers.size() ); - THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() ); - } - - m_board->SetCopperLayerCount( copperLayerCount ); - - // Copper layers are sequential from front to back in the file but the current layer - // design uses sequential layers from back to front except for the front layer which - // is always vector index 15. - for( unsigned i = 0; i < layers.size(); i++ ) - { - int layerIndex = i; - - // The copper layers can have different names but they always are at the beginning - // and have a valid layer type. Non-copper layer name cannot be changed so the - // list index can be looked up by name. - if( layers[i].m_Type != LT_UNDEFINED ) - { - if( i == 0 ) - layerIndex = LAYER_N_FRONT; - else - layerIndex = copperLayerCount - 1 - i; - } - else - { - layerIndex = LAYER::GetDefaultIndex( layers[i].m_Name ); - - if( layerIndex == UNDEFINED_LAYER ) - { - wxString error; - error.Printf( _( "Cannot determine fixed layer list index of layer name \"%s\"" ), - layers[i].m_Name ); - THROW_IO_ERROR( error ); - } - } - - enabledLayers |= 1 << layerIndex; - - if( layers[i].IsVisible() ) - visibleLayers |= 1 << layerIndex; - - layers[i].SetFixedListIndex( layerIndex ); - m_board->SetLayer( layerIndex, layers[i] ); - m_layerMap[ layers[i].m_Name ] = layerIndex; - wxLogDebug( wxT( "Mapping layer %s index index %d" ), - GetChars( layers[i].m_Name ), layerIndex ); - } - - m_board->SetVisibleLayers( visibleLayers ); - m_board->SetEnabledLayers( enabledLayers ); -} - - -int PCB_PARSER::lookUpLayer() throw( PARSE_ERROR, IO_ERROR ) -{ -#if USE_LAYER_NAMES - wxString name = FromUTF8(); - const LAYER_HASH_MAP::iterator it = m_layerMap.find( name ); - - if( it == m_layerMap.end() ) - { - wxString error; - error.Printf( _( "Layer %s in file <%s> at line %d, position %d was not defined in the layers section" ), - GetChars( name ), GetChars( CurSource() ), CurLineNumber(), CurOffset() ); - THROW_IO_ERROR( error ); - } - - return m_layerMap[ name ]; -#else - if( CurTok() != T_NUMBER ) - Expecting( T_NUMBER ); - - int layerIndex = parseInt(); - - if( !m_board->IsLayerEnabled( layerIndex ) ) - { - wxString error; - error.Printf( _( "Layer index %d in file <%s> at line, offset %d was not defined in the layers section" ), - layerIndex, GetChars( CurSource() ), CurLineNumber(), CurOffset() ); - THROW_IO_ERROR( error ); - } - - return layerIndex; -#endif -} - - -int PCB_PARSER::parseBoardItemLayer() throw( PARSE_ERROR, IO_ERROR ) -{ - wxCHECK_MSG( CurTok() == T_layer, UNDEFINED_LAYER, - wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as layer." ) ); - - NextTok(); - - int layerIndex = lookUpLayer(); - - // Handle closing ) in object parser. - - return layerIndex; -} - - -int PCB_PARSER::parseBoardItemLayersAsMask() throw( PARSE_ERROR, IO_ERROR ) -{ - wxCHECK_MSG( CurTok() == T_layers, 0, - wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + - wxT( " as item layer mask." ) ); - - int layerIndex; - int layerMask = 0; - T token; - - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - layerIndex = lookUpLayer(); - layerMask |= ( 1 << layerIndex ); - } - - return layerMask; -} - - -void PCB_PARSER::parseSetup() throw( IO_ERROR, PARSE_ERROR ) -{ - wxCHECK_RET( CurTok() == T_setup, - wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as setup." ) ); - - T token; - int lastTraceWidth; - NETCLASS* defaultNetclass = m_board->m_NetClasses.GetDefault(); - BOARD_DESIGN_SETTINGS designSettings = m_board->GetDesignSettings(); - ZONE_SETTINGS zoneSettings = m_board->GetZoneSettings(); - - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - if( token != T_LEFT ) - Expecting( T_LEFT ); - - token = NextTok(); - - switch( token ) - { - case T_last_trace_width: - lastTraceWidth = parseBoardUnits( T_last_trace_width ); - break; - - case T_user_trace_width: - m_board->m_TrackWidthList.push_back( parseBoardUnits( T_user_trace_width ) ); - break; - - case T_trace_clearance: - defaultNetclass->SetClearance( parseBoardUnits( T_trace_clearance ) ); - break; - - case T_zone_clearance: - zoneSettings.m_ZoneClearance = parseBoardUnits( T_zone_clearance ); - break; - - case T_zone_45_only: - zoneSettings.m_Zone_45_Only = parseBool(); - break; - - case T_trace_min: - designSettings.m_TrackMinWidth = parseBoardUnits( T_trace_min ); - break; - - case T_segment_width: - designSettings.m_DrawSegmentWidth = parseBoardUnits( T_segment_width ); - break; - - case T_edge_width: - designSettings.m_EdgeSegmentWidth = parseBoardUnits( T_edge_width ); - break; - - case T_via_size: - defaultNetclass->SetViaDiameter( parseBoardUnits( T_via_size ) ); - break; - - case T_via_drill: - defaultNetclass->SetViaDrill( parseBoardUnits( T_via_drill ) ); - break; - - case T_via_min_size: - designSettings.m_ViasMinSize = parseBoardUnits( T_via_min_size ); - break; - - case T_via_min_drill: - designSettings.m_ViasMinDrill = parseBoardUnits( T_via_min_drill ); - break; - - case T_user_via: - { - int viaSize = parseBoardUnits( "user via size" ); - int viaDrill = parseBoardUnits( "user via drill" ); - m_board->m_ViasDimensionsList.push_back( VIA_DIMENSION( viaSize, viaDrill ) ); - } - break; - - case T_uvia_size: - defaultNetclass->SetuViaDiameter( parseBoardUnits( T_uvia_size ) ); - break; - - case T_uvia_drill: - defaultNetclass->SetuViaDrill( parseBoardUnits( T_uvia_drill ) ); - break; - - case T_uvias_allowed: - designSettings.m_MicroViasAllowed = parseBool(); - break; - - case T_uvia_min_size: - designSettings.m_MicroViasMinSize = parseBoardUnits( T_uvia_min_size ); - break; - - case T_uvia_min_drill: - designSettings.m_MicroViasMinDrill = parseBoardUnits( T_uvia_min_drill ); - break; - - case T_pcb_text_width: - designSettings.m_PcbTextWidth = parseBoardUnits( T_pcb_text_width ); - break; - - case T_pcb_text_size: - designSettings.m_PcbTextSize.x = parseBoardUnits( "pcb text width" ); - designSettings.m_PcbTextSize.y = parseBoardUnits( "pcb text height" ); - break; - - case T_mod_edge_width: - designSettings.m_ModuleSegmentWidth = parseBoardUnits( T_mod_edge_width ); - break; - - case T_mod_text_size: - designSettings.m_ModuleTextSize.x = parseBoardUnits( "module text width" ); - designSettings.m_ModuleTextSize.y = parseBoardUnits( "module text height" ); - break; - - case T_mod_text_width: - designSettings.m_ModuleTextWidth = parseBoardUnits( T_mod_text_width ); - break; - - case T_pad_size: - { - wxSize sz; - sz.SetHeight( parseBoardUnits( "master pad height" ) ); - sz.SetWidth( parseBoardUnits( "master pad width" ) ); - designSettings.m_Pad_Master.SetSize( sz ); - break; - } - - case T_pad_drill: - { - int drillSize = parseBoardUnits( T_pad_drill ); - designSettings.m_Pad_Master.SetDrillSize( wxSize( drillSize, drillSize ) ); - } - break; - - case T_pad_to_mask_clearance: - designSettings.m_SolderMaskMargin = parseBoardUnits( T_pad_to_mask_clearance ); - break; - - case T_pad_to_paste_clearance: - designSettings.m_SolderPasteMargin = parseBoardUnits( T_pad_to_paste_clearance ); - break; - - case T_pad_to_paste_clearance_ratio: - designSettings.m_SolderPasteMarginRatio = parseDouble( T_pad_to_paste_clearance_ratio ); - break; - - case T_aux_axis_origin: - m_board->SetOriginAxisPosition( wxPoint( parseBoardUnits( "auxilary origin X" ), - parseBoardUnits( "auxilary origin Y" ) ) ); - break; - - case T_visible_elements: - designSettings.SetVisibleElements( parseHex() ); - break; - - default: - Expecting( "valid setup token" ); - } - - NeedRIGHT(); - } - - m_board->SetDesignSettings( designSettings ); - m_board->SetZoneSettings( zoneSettings ); - - // Until such time as the *.brd file does not have the - // global parameters: - // "last_trace_width", "trace_min_width", "via_size", "via_drill", - // "via_min_size", and "via_clearance", put those same global - // values into the default NETCLASS until later board load - // code should override them. *.kicad_brd files which have been - // saved with knowledge of NETCLASSes will override these - // defaults, old boards will not. - // - // @todo: I expect that at some point we can remove said global - // parameters from the *.brd file since the ones in the - // default netclass serve the same purpose. If needed - // at all, the global defaults should go into a preferences - // file instead so they are there to start new board - // projects. - m_board->m_NetClasses.GetDefault()->SetParams(); -} - - -void PCB_PARSER::parseNETINFO_ITEM() throw( IO_ERROR, PARSE_ERROR ) -{ - wxCHECK_RET( CurTok() == T_net, - wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as net." ) ); - - int number = parseInt( "net number" ); - NeedSYMBOL(); - wxString name = FromUTF8(); - NeedRIGHT(); - - NETINFO_ITEM* net = new NETINFO_ITEM( m_board ); - net->SetNet( number ); - net->SetNetname( name ); - m_board->AppendNet( net ); -} - - -void PCB_PARSER::parseNETCLASS() throw( IO_ERROR, PARSE_ERROR ) -{ - wxCHECK_RET( CurTok() == T_net_class, - wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as net class." ) ); - - T token; - - auto_ptr nc( new NETCLASS( m_board, wxEmptyString ) ); - - NeedSYMBOL(); - nc->SetName( FromUTF8() ); - NeedSYMBOL(); - nc->SetDescription( FromUTF8() ); - - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - if( token != T_LEFT ) - Expecting( T_LEFT ); - - token = NextTok(); - - switch( token ) - { - case T_clearance: - nc->SetClearance( parseBoardUnits( T_clearance ) ); - break; - - case T_trace_width: - nc->SetTrackWidth( parseBoardUnits( T_trace_width ) ); - break; - - case T_via_dia: - nc->SetViaDiameter( parseBoardUnits( T_via_dia ) ); - break; - - case T_via_drill: - nc->SetViaDrill( parseBoardUnits( T_via_drill ) ); - break; - - case T_uvia_dia: - nc->SetuViaDiameter( parseBoardUnits( T_uvia_dia ) ); - break; - - case T_uvia_drill: - nc->SetuViaDrill( parseBoardUnits( T_uvia_drill ) ); - break; - - case T_add_net: - NeedSYMBOL(); - nc->Add( FromUTF8() ); - break; - - default: - Expecting( "clearance, trace_width, via_dia, via_drill, uvia_dia, uvia_drill, or add_net" ); - } - - NeedRIGHT(); - } - - if( m_board->m_NetClasses.Add( nc.get() ) ) - { - nc.release(); - } - else - { - // Must have been a name conflict, this is a bad board file. - // User may have done a hand edit to the file. - - // auto_ptr will delete nc on this code path - - wxString error; - error.Printf( _( "duplicate NETCLASS name '%s' in file %s at line %d, offset %d" ), - nc->GetName().GetData(), CurSource(), CurLineNumber(), CurOffset() ); - THROW_IO_ERROR( error ); - } -} - - -void PCB_PARSER::parseDRAWSEGMENT() throw( IO_ERROR, PARSE_ERROR ) -{ - wxCHECK_RET( CurTok() == T_gr_arc || CurTok() == T_gr_circle || CurTok() == T_gr_curve || - CurTok() == T_gr_line || CurTok() == T_gr_poly, - wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as DRAWSEGMENT." ) ); - - T token; - - auto_ptr< DRAWSEGMENT > segment( new DRAWSEGMENT( m_board ) ); - - switch( CurTok() ) - { - case T_gr_arc: - segment->SetType( S_ARC ); - NeedLEFT(); - token = NextTok(); - - if( token != T_start ) - Expecting( T_start ); - - segment->SetStart( parseXY() ); - NeedRIGHT(); - token = NextTok(); - - if( token != T_end ) - Expecting( T_end ); - - segment->SetEnd( parseXY() ); - NeedRIGHT(); - token = NextTok(); - - if( token != T_angle ) - Expecting( T_angle ); - - segment->SetAngle( parseDouble( "segment angle" ) ); - NeedRIGHT(); - break; - - case T_gr_circle: - segment->SetType( S_CIRCLE ); - NeedLEFT(); - token = NextTok(); - - if( token != T_center ) - Expecting( T_center ); - - segment->SetStart( parseXY() ); - NeedRIGHT(); - token = NextTok(); - - if( token != T_end ) - Expecting( T_end ); - - segment->SetEnd( parseXY() ); - NeedRIGHT(); - break; - - case T_gr_curve: - segment->SetType( S_CURVE ); - NeedLEFT(); - token = NextTok(); - - if( token != T_pts ) - Expecting( T_pts ); - - segment->SetStart( parseXY() ); - segment->SetBezControl1( parseXY() ); - segment->SetBezControl2( parseXY() ); - segment->SetEnd( parseXY() ); - NeedRIGHT(); - break; - - case T_gr_line: - // Default DRAWSEGMENT type is S_SEGMENT. - NeedLEFT(); - token = NextTok(); - - if( token != T_pts ) - Expecting( T_pts ); - - segment->SetStart( parseXY() ); - segment->SetEnd( parseXY() ); - NeedRIGHT(); - break; - - case T_gr_poly: - { - segment->SetType( S_POLYGON ); - NeedLEFT(); - token = NextTok(); - - if( token != T_pts ) - Expecting( T_pts ); - - std::vector< wxPoint > pts; - - while( (token = NextTok()) != T_RIGHT ) - pts.push_back( parseXY() ); - - segment->SetPolyPoints( pts ); - } - break; - - default: - Expecting( "gr_arc, gr_circle, gr_curve, gr_line, or gr_poly" ); - } - - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - if( token != T_LEFT ) - Expecting( T_LEFT ); - - token = NextTok(); - - switch( token ) - { - case T_layer: - segment->SetLayer( parseBoardItemLayer() ); - break; - - case T_width: - segment->SetWidth( parseBoardUnits( T_width ) ); - break; - - case T_tstamp: - segment->SetTimeStamp( parseHex() ); - break; - - case T_status: - segment->SetStatus( parseHex() ); - break; - - default: - Expecting( "layer, width, tstamp, or status" ); - } - - NeedRIGHT(); - } - - m_board->Add( segment.release() ); -} - - -void PCB_PARSER::parseTEXTE_PCB( TEXTE_PCB* aText ) throw( IO_ERROR, PARSE_ERROR ) -{ - wxCHECK_RET( CurTok() == T_gr_text, - wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as TEXTE_PCB." ) ); - - T token; - - auto_ptr< TEXTE_PCB > text( new TEXTE_PCB( m_board ) ); - NeedSYMBOLorNUMBER(); - - text->SetText( FromUTF8() ); - NeedLEFT(); - token = NextTok(); - - if( token != T_at ) - Expecting( T_at ); - - wxPoint pt; - - pt.x = parseBoardUnits( "X coordinate" ); - pt.y = parseBoardUnits( "Y coordinate" ); - text->SetPosition( pt ); - text->SetOrientation( parseDouble( "angle" ) * 10.0 ); - NeedRIGHT(); - - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - if( token != T_LEFT ) - Expecting( T_LEFT ); - - token = NextTok(); - - switch( token ) - { - case T_layer: - text->SetLayer( parseBoardItemLayer() ); - NeedRIGHT(); - break; - - case T_tstamp: - text->SetTimeStamp( parseHex() ); - NeedRIGHT(); - break; - - case T_effects: - parseEDA_TEXT( (EDA_TEXT*) text.get() ); - break; - - default: - Expecting( "layer, tstamp or effects" ); - } - } - - if( aText == NULL ) - m_board->Add( text.release() ); - else - *aText = *text; -} - - -void PCB_PARSER::parseDIMENSION() throw( IO_ERROR, PARSE_ERROR ) -{ - wxCHECK_RET( CurTok() == T_dimension, - wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as DIMENSION." ) ); - - T token; - - auto_ptr< DIMENSION > dimension( new DIMENSION( m_board ) ); - - dimension->m_Value = parseBoardUnits( "dimension value" ); - NeedLEFT(); - token = NextTok(); - - if( token != T_width ) - Expecting( T_width ); - - dimension->SetWidth( parseBoardUnits( "dimension width value" ) ); - NeedRIGHT(); - - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - if( token != T_LEFT ) - Expecting( T_LEFT ); - - token = NextTok(); - - switch( token ) - { - case T_layer: - dimension->SetLayer( parseBoardItemLayer() ); - NeedRIGHT(); - break; - - case T_tstamp: - dimension->SetTimeStamp( parseHex() ); - NeedRIGHT(); - break; - - case T_gr_text: - parseTEXTE_PCB( &dimension->m_Text ); - break; - - - case T_feature1: - NeedLEFT(); - token = NextTok(); - - if( token != T_pts ) - Expecting( T_pts ); - - parseXY( &dimension->m_featureLineDOx, &dimension->m_featureLineDOy ); - parseXY( &dimension->m_featureLineDFx, &dimension->m_featureLineDFy ); - NeedRIGHT(); - NeedRIGHT(); - break; - - case T_feature2: - NeedLEFT(); - token = NextTok(); - - if( token != T_pts ) - Expecting( T_pts ); - - parseXY( &dimension->m_featureLineGOx, &dimension->m_featureLineGOy ); - parseXY( &dimension->m_featureLineGFx, &dimension->m_featureLineGFy ); - NeedRIGHT(); - NeedRIGHT(); - break; - - - case T_crossbar: - NeedLEFT(); - token = NextTok(); - - if( token != T_pts ) - Expecting( T_pts ); - - parseXY( &dimension->m_crossBarOx, &dimension->m_crossBarOy ); - parseXY( &dimension->m_crossBarFx, &dimension->m_crossBarFy ); - NeedRIGHT(); - NeedRIGHT(); - break; - - case T_arrow1a: - NeedLEFT(); - token = NextTok(); - - if( token != T_pts ) - Expecting( T_pts ); - - parseXY( &dimension->m_arrowD1Ox, &dimension->m_arrowD1Oy ); - parseXY( &dimension->m_arrowD1Fx, &dimension->m_arrowD1Fy ); - NeedRIGHT(); - NeedRIGHT(); - break; - - case T_arrow1b: - NeedLEFT(); - token = NextTok(); - - if( token != T_pts ) - Expecting( T_pts ); - - parseXY( &dimension->m_arrowD2Ox, &dimension->m_arrowD2Oy ); - parseXY( &dimension->m_arrowD2Fx, &dimension->m_arrowD2Fy ); - NeedRIGHT(); - NeedRIGHT(); - break; - - case T_arrow2a: - NeedLEFT(); - token = NextTok(); - - if( token != T_pts ) - Expecting( T_pts ); - - parseXY( &dimension->m_arrowG1Ox, &dimension->m_arrowG1Oy ); - parseXY( &dimension->m_arrowG1Fx, &dimension->m_arrowG1Fy ); - NeedRIGHT(); - NeedRIGHT(); - break; - - case T_arrow2b: - NeedLEFT(); - token = NextTok(); - - if( token != T_pts ) - Expecting( T_pts ); - - parseXY( &dimension->m_arrowG2Ox, &dimension->m_arrowG2Oy ); - parseXY( &dimension->m_arrowG2Fx, &dimension->m_arrowG2Fy ); - NeedRIGHT(); - NeedRIGHT(); - break; - - default: - Expecting( "layer, tstamp, gr_text, feature1, feature2 crossbar, arrow1a, " - "arrow1b, arrow2a, or arrow2b" ); - } - } - - m_board->Add( dimension.release() ); -} - - -void PCB_PARSER::parseMODULE() throw( IO_ERROR, PARSE_ERROR ) -{ - wxCHECK_RET( CurTok() == T_module, - wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as MODULE." ) ); - - wxPoint pt; - T token; - - auto_ptr< MODULE > module( new MODULE( m_board ) ); - - NeedSYMBOL(); - module->SetLibRef( FromUTF8() ); - - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - if( token == T_LEFT ) - token = NextTok(); - - switch( token ) - { - case T_locked: - module->SetLocked( true ); - break; - - case T_placed: - module->SetIsPlaced( true ); - break; - - case T_layer: - module->SetLayer( parseBoardItemLayer() ); - NeedRIGHT(); - break; - - case T_tedit: - module->SetLastEditTime( parseHex() ); - NeedRIGHT(); - break; - - case T_tstamp: - module->SetTimeStamp( parseHex() ); - NeedRIGHT(); - break; - - case T_at: - pt.x = parseBoardUnits( "X coordinate" ); - pt.y = parseBoardUnits( "Y coordinate" ); - module->SetPosition( pt ); - token = NextTok(); - - if( token == T_NUMBER ) - { - module->SetOrientation( parseDouble() * 10.0 ); - NeedRIGHT(); - } - else if( token != T_RIGHT ) - { - Expecting( T_RIGHT ); - } - - break; - - case T_descr: - NeedSYMBOL(); - module->SetDescription( FromUTF8() ); - NeedRIGHT(); - break; - - case T_tags: - NeedSYMBOL(); - module->SetKeywords( FromUTF8() ); - NeedRIGHT(); - break; - - case T_path: - NeedSYMBOL(); - module->SetPath( FromUTF8() ); - NeedRIGHT(); - break; - - case T_autoplace_cost90: - module->m_CntRot90 = parseInt( "auto place cost at 90 degrees" ); - NeedRIGHT(); - break; - - case T_autoplace_cost180: - module->m_CntRot180 = parseInt( "auto place cost at 180 degrees" ); - NeedRIGHT(); - break; - - case T_solder_mask_margin: - module->SetLocalSolderMaskMargin( parseBoardUnits( "local solder mask margin value" ) ); - NeedRIGHT(); - break; - - case T_solder_paste_margin: - module->SetLocalSolderPasteMargin( - parseBoardUnits( "local solder paste margin value" ) ); - NeedRIGHT(); - break; - - case T_solder_paste_ratio: - module->SetLocalSolderPasteMarginRatio( - parseDouble( "local solder paste margin ratio value" ) ); - NeedRIGHT(); - break; - - case T_clearance: - module->SetLocalClearance( parseBoardUnits( "local clearance value" ) ); - NeedRIGHT(); - break; - - case T_zone_connect: - module->SetZoneConnection( (ZoneConnection) parseInt( "zone connection value" ) ); - NeedRIGHT(); - break; - - case T_thermal_width: - module->SetThermalWidth( parseBoardUnits( "thermal width value" ) ); - NeedRIGHT(); - break; - - case T_thermal_gap: - module->SetThermalGap( parseBoardUnits( "thermal gap value" ) ); - NeedRIGHT(); - break; - - case T_attr: - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - switch( token ) - { - case T_smd: - module->SetAttributes( module->GetAttributes() | MOD_CMS ); - break; - - case T_virtual: - module->SetAttributes( module->GetAttributes() | MOD_VIRTUAL ); - break; - - default: - Expecting( "smd and/or virtual" ); - } - } - - break; - - case T_fp_text: - { - TEXTE_MODULE* text = parseTEXTE_MODULE(); - text->SetParent( module.get() ); - double orientation = text->GetOrientation(); - orientation -= module->GetOrientation(); - text->SetOrientation( orientation ); - text->SetDrawCoord(); - - if( text->GetType() == TEXT_is_REFERENCE ) - { - module->Reference() = *text; - delete text; - } - else if( text->GetType() == TEXT_is_VALUE ) - { - module->Value() = *text; - delete text; - } - else - { - module->m_Drawings.PushBack( text ); - } - - break; - } - - case T_fp_arc: - case T_fp_circle: - case T_fp_curve: - case T_fp_line: - case T_fp_poly: - { - EDGE_MODULE* em = parseEDGE_MODULE(); - em->SetParent( module.get() ); - em->SetDrawCoord(); - module->m_Drawings.PushBack( em ); - break; - } - - case T_pad: - { - D_PAD* pad = parseD_PAD(); - wxPoint pt = pad->GetPos0(); - RotatePoint( &pt, module->GetOrientation() ); - pad->SetPosition( pt + module->GetPosition() ); - module->AddPad( pad ); - break; - } - - case T_model: - module->Add3DModel( parse3DModel() ); - break; - - default: - Expecting( "locked, placed, tedit, tstamp, at, descr, tags, path, " - "autoplace_cost90, autoplace_cost180, solder_mask_margin, " - "solder_paste_margin, solder_paste_ratio, clearance, " - "zone_connect, thermal_width, thermal_gap, attr, fp_text, " - "fp_arc, fp_circle, fp_curve, fp_line, fp_poly, pad, or model" ); - } - } - - m_board->Add( module.release(), ADD_APPEND ); -} - - -TEXTE_MODULE* PCB_PARSER::parseTEXTE_MODULE() throw( IO_ERROR, PARSE_ERROR ) -{ - wxCHECK_MSG( CurTok() == T_fp_text, NULL, - wxString::Format( wxT( "Cannot parse %s as TEXTE_MODULE at line %d, offset %d." ), - GetTokenString( CurTok() ), CurLineNumber(), CurOffset() ) ); - - T token = NextTok(); - - auto_ptr< TEXTE_MODULE > text( new TEXTE_MODULE( NULL ) ); - - switch( token ) - { - case T_reference: - text->SetType( TEXT_is_REFERENCE ); - break; - - case T_value: - text->SetType( TEXT_is_VALUE ); - break; - - case T_user: - break; // Default type is user text. - - default: - THROW_IO_ERROR( wxString::Format( _( "cannot handle module text type %s" ), - GetChars( FromUTF8() ) ) ); - } - - NeedSYMBOLorNUMBER(); - - text->SetText( FromUTF8() ); - NeedLEFT(); - token = NextTok(); - - if( token != T_at ) - Expecting( T_at ); - - wxPoint pt; - - pt.x = parseBoardUnits( "X coordinate" ); - pt.y = parseBoardUnits( "Y coordinate" ); - text->SetPos0( pt ); - text->SetOrientation( parseDouble( "angle" ) * 10.0 ); - NeedRIGHT(); - - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - if( token == T_LEFT ) - token = NextTok(); - - switch( token ) - { - case T_hide: - text->SetVisible( false ); - break; - - case T_effects: - parseEDA_TEXT( (EDA_TEXT*) text.get() ); - break; - - default: - Expecting( "hide or effects" ); - } - } - - return text.release(); -} - - -EDGE_MODULE* PCB_PARSER::parseEDGE_MODULE() throw( IO_ERROR, PARSE_ERROR ) -{ - wxCHECK_MSG( CurTok() == T_fp_arc || CurTok() == T_fp_circle || CurTok() == T_fp_curve || - CurTok() == T_fp_line || CurTok() == T_fp_poly, NULL, - wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as EDGE_MODULE." ) ); - - T token; - - auto_ptr< EDGE_MODULE > segment( new EDGE_MODULE( NULL ) ); - - switch( CurTok() ) - { - case T_fp_arc: - segment->SetType( S_ARC ); - NeedLEFT(); - token = NextTok(); - - if( token != T_start ) - Expecting( T_start ); - - segment->SetStart0( parseXY() ); - NeedRIGHT(); - token = NextTok(); - - if( token != T_end ) - Expecting( T_end ); - - segment->SetEnd0( parseXY() ); - NeedRIGHT(); - token = NextTok(); - - if( token != T_angle ) - Expecting( T_angle ); - - segment->SetAngle( parseDouble( "segment angle" ) ); - NeedRIGHT(); - break; - - case T_fp_circle: - segment->SetType( S_CIRCLE ); - NeedLEFT(); - token = NextTok(); - - if( token != T_center ) - Expecting( T_center ); - - segment->SetStart0( parseXY() ); - NeedRIGHT(); - NeedLEFT(); - token = NextTok(); - - if( token != T_end ) - Expecting( T_end ); - - segment->SetEnd0( parseXY() ); - NeedRIGHT(); - break; - - case T_fp_curve: - segment->SetType( S_CURVE ); - NeedLEFT(); - token = NextTok(); - - if( token != T_pts ) - Expecting( T_pts ); - - segment->SetStart0( parseXY() ); - segment->SetBezControl1( parseXY() ); - segment->SetBezControl2( parseXY() ); - segment->SetEnd0( parseXY() ); - NeedRIGHT(); - break; - - case T_fp_line: - // Default DRAWSEGMENT type is S_SEGMENT. - NeedLEFT(); - token = NextTok(); - - if( token != T_pts ) - Expecting( T_pts ); - - segment->SetStart0( parseXY() ); - segment->SetEnd0( parseXY() ); - NeedRIGHT(); - break; - - case T_fp_poly: - { - segment->SetType( S_POLYGON ); - NeedLEFT(); - token = NextTok(); - - if( token != T_pts ) - Expecting( T_pts ); - - std::vector< wxPoint > pts; - - while( (token = NextTok()) != T_RIGHT ) - pts.push_back( parseXY() ); - - segment->SetPolyPoints( pts ); - } - break; - - default: - Expecting( "fp_arc, fp_circle, fp_curve, fp_line, or fp_poly" ); - } - - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - if( token != T_LEFT ) - Expecting( T_LEFT ); - - token = NextTok(); - - switch( token ) - { - case T_layer: - segment->SetLayer( parseBoardItemLayer() ); - break; - - case T_width: - segment->SetWidth( parseBoardUnits( T_width ) ); - break; - - case T_tstamp: - segment->SetTimeStamp( parseHex() ); - break; - - case T_status: - segment->SetStatus( parseHex() ); - break; - - default: - Expecting( "layer, width, tstamp, or status" ); - } - - NeedRIGHT(); - } - - return segment.release(); -} - - -D_PAD* PCB_PARSER::parseD_PAD() throw( IO_ERROR, PARSE_ERROR ) -{ - wxCHECK_MSG( CurTok() == T_pad, NULL, - wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as D_PAD." ) ); - - wxSize sz; - wxPoint pt; - auto_ptr< D_PAD > pad( new D_PAD( NULL ) ); - - NeedSYMBOLorNUMBER(); - pad->SetPadName( FromUTF8() ); - - T token = NextTok(); - - switch( token ) - { - case T_thru_hole: - pad->SetAttribute( PAD_STANDARD ); - break; - - case T_smd: - pad->SetAttribute( PAD_SMD ); - break; - - case T_connect: - pad->SetAttribute( PAD_CONN ); - break; - - case T_np_thru_hole: - pad->SetAttribute( PAD_HOLE_NOT_PLATED ); - break; - - default: - Expecting( "thru_hole, smd, connect, or np_thru_hole" ); - } - - token = NextTok(); - - switch( token ) - { - case T_circle: - pad->SetShape( PAD_CIRCLE ); - break; - - case T_rectangle: - pad->SetShape( PAD_RECT ); - break; - - case T_oval: - pad->SetShape( PAD_OVAL ); - break; - - case T_trapezoid: - pad->SetShape( PAD_TRAPEZOID ); - break; - - default: - Expecting( "circle, rectangle, oval, or trapezoid" ); - } - - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - if( token != T_LEFT ) - Expecting( T_LEFT ); - - token = NextTok(); - - switch( token ) - { - case T_size: - sz.SetWidth( parseBoardUnits( "width value" ) ); - sz.SetHeight( parseBoardUnits( "height value" ) ); - pad->SetSize( sz ); - NeedRIGHT(); - break; - - case T_at: - pt.x = parseBoardUnits( "X coordinate" ); - pt.y = parseBoardUnits( "Y coordinate" ); - pad->SetPos0( pt ); - token = NextTok(); - - if( token == T_NUMBER ) - { - pad->SetOrientation( parseDouble() * 10.0 ); - NeedRIGHT(); - } - else if( token != T_RIGHT ) - { - Expecting( ") or angle value" ); - } - - break; - - case T_drill: - sz.SetWidth( parseBoardUnits( "drill size" ) ); - sz.SetHeight( 0 ); - token = NextTok(); - - if( token == T_NUMBER ) - { - sz.SetHeight( parseBoardUnits() ); - token = NextTok(); - - if( token == T_LEFT ) - { - token = NextTok(); - - if( token != T_offset ) - Expecting( T_offset ); - - pt.x = parseDouble( "drill offset X" ); - pt.y = 0; - token = NextTok(); - - if( token == T_NUMBER ) - { - pt.y = parseDouble(); - NeedRIGHT(); - } - else if( token != T_RIGHT ) - { - Expecting( T_RIGHT ); - } - - pad->SetOffset( pt ); - } - else if( token != T_RIGHT ) - { - Expecting( T_RIGHT ); - } - - pad->SetDrillSize( sz ); - } - else if( token != T_RIGHT ) - { - Expecting( T_RIGHT ); - } - - break; - - case T_layers: - pad->SetLayerMask( parseBoardItemLayersAsMask() ); - break; - - case T_net: - pad->SetNet( parseInt( "net number" ) ); - NeedSYMBOL(); - pad->SetNetname( FromUTF8() ); - NeedRIGHT(); - break; - - - case T_die_length: - pad->SetDieLength( parseBoardUnits( T_die_length ) ); - NeedRIGHT(); - break; - - case T_solder_mask_margin: - pad->SetLocalSolderMaskMargin( parseBoardUnits( T_solder_mask_margin ) ); - NeedRIGHT(); - break; - - case T_solder_paste_margin: - pad->SetLocalSolderPasteMargin( parseBoardUnits( T_solder_paste_margin ) ); - NeedRIGHT(); - break; - - case T_solder_paste_margin_ratio: - pad->SetLocalSolderPasteMarginRatio( parseBoardUnits( T_solder_paste_margin_ratio ) ); - NeedRIGHT(); - break; - - case T_clearance: - pad->SetLocalClearance( parseBoardUnits( "local clearance value" ) ); - NeedRIGHT(); - break; - - case T_zone_connect: - pad->SetZoneConnection( (ZoneConnection) parseInt( "zone connection value" ) ); - NeedRIGHT(); - break; - - case T_thermal_width: - pad->SetThermalWidth( parseBoardUnits( T_thermal_width ) ); - NeedRIGHT(); - break; - - case T_thermal_gap: - pad->SetThermalGap( parseBoardUnits( T_thermal_gap ) ); - NeedRIGHT(); - break; - - default: - Expecting( "at, drill, layers, net, die_length, solder_mask_margin, " - "solder_paste_margin, solder_paste_margin_ratio, clearance, " - "zone_connect, thermal_width, or thermal_gap" ); - } - } - - return pad.release(); -} - - -TRACK* PCB_PARSER::parseTRACK() throw( IO_ERROR, PARSE_ERROR ) -{ - wxCHECK_MSG( CurTok() == T_segment, NULL, - wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as TRACK." ) ); - - wxPoint pt; - T token; - - auto_ptr< TRACK > track( new TRACK( m_board ) ); - - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - if( token != T_LEFT ) - Expecting( T_LEFT ); - - token = NextTok(); - - switch( token ) - { - case T_start: - pt.x = parseBoardUnits( "start x" ); - pt.y = parseBoardUnits( "start y" ); - track->SetStart( pt ); - break; - - case T_end: - pt.x = parseBoardUnits( "end x" ); - pt.y = parseBoardUnits( "end y" ); - track->SetEnd( pt ); - break; - - case T_width: - track->SetWidth( parseBoardUnits( "width" ) ); - break; - - case T_layer: - track->SetLayer( parseBoardItemLayer() ); - break; - - case T_net: - track->SetNet( parseInt( "net number" ) ); - break; - - case T_tstamp: - track->SetTimeStamp( parseHex() ); - break; - - case T_status: - track->SetStatus( parseHex() ); - break; - - default: - Expecting( "start, end, width, layer, net, tstamp, or status" ); - } - - NeedRIGHT(); - } - - return track.release(); -} - - -SEGVIA* PCB_PARSER::parseSEGVIA() throw( IO_ERROR, PARSE_ERROR ) -{ - wxCHECK_MSG( CurTok() == T_via, NULL, - wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as SEGVIA." ) ); - - wxPoint pt; - T token; - - auto_ptr< SEGVIA > via( new SEGVIA( m_board ) ); - - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - if( token == T_LEFT ) - token = NextTok(); - - switch( token ) - { - case T_thru: - via->SetShape( VIA_THROUGH ); - break; - - case T_blind: - via->SetShape( VIA_BLIND_BURIED ); - break; - - case T_micro: - via->SetShape( VIA_MICROVIA ); - break; - - case T_at: - pt.x = parseBoardUnits( "start x" ); - pt.y = parseBoardUnits( "start y" ); - via->SetStart( pt ); - NeedRIGHT(); - break; - - case T_size: - via->SetWidth( parseBoardUnits( "via width" ) ); - NeedRIGHT(); - break; - - case T_drill: - via->SetDrill( parseBoardUnits( "drill diameter" ) ); - NeedRIGHT(); - break; - - case T_layers: - { - int layer1, layer2; - NextTok(); - layer1 = lookUpLayer(); - NextTok(); - layer2 = lookUpLayer(); - via->SetLayerPair( layer1, layer2 ); - NeedRIGHT(); - } - break; - - case T_net: - via->SetNet( parseInt( "net number" ) ); - NeedRIGHT(); - break; - - case T_tstamp: - via->SetTimeStamp( parseHex() ); - NeedRIGHT(); - break; - - case T_status: - via->SetStatus( parseHex() ); - NeedRIGHT(); - break; - - default: - Expecting( "at, size, drill, layers, net, tstamp, or status" ); - } - } - - return via.release(); -} - - -ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER() throw( IO_ERROR, PARSE_ERROR ) -{ - wxCHECK_MSG( CurTok() == T_zone, NULL, - wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + - wxT( " as ZONE_CONTAINER." ) ); - - int hatchStyle; - int hatchPitch; - wxPoint pt; - T token; - - auto_ptr< ZONE_CONTAINER > zone( new ZONE_CONTAINER( m_board ) ); - - zone->SetPriority( 0 ); - - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - if( token == T_LEFT ) - token = NextTok(); - - switch( token ) - { - case T_net: - zone->SetNet( parseInt( "net number" ) ); - NeedRIGHT(); - break; - - case T_net_name: - NeedSYMBOL(); - zone->SetNetName( FromUTF8() ); - NeedRIGHT(); - break; - - case T_layer: - zone->SetLayer( parseBoardItemLayer() ); - NeedRIGHT(); - break; - - case T_tstamp: - zone->SetTimeStamp( parseHex() ); - NeedRIGHT(); - break; - - case T_hatch: - token = NextTok(); - - if( token != T_none && token != T_edge && token != T_full ) - Expecting( "none, edge, or full" ); - - switch( token ) - { - default: - case T_none: hatchStyle = CPolyLine::NO_HATCH; break; - case T_edge: hatchStyle = CPolyLine::DIAGONAL_EDGE; break; - case T_full: hatchStyle = CPolyLine::DIAGONAL_FULL; - } - - hatchPitch = parseBoardUnits( "hatch pitch" ); - NeedRIGHT(); - break; - - case T_priority: - zone->SetPriority( parseInt( "zone priority" ) ); - NeedRIGHT(); - break; - - case T_connect_pads: - token = NextTok(); - - switch( token ) - { - case T_yes: zone->SetPadConnection( PAD_IN_ZONE ); break; - case T_use_thermal: zone->SetPadConnection( THERMAL_PAD ); break; - case T_no: zone->SetPadConnection( PAD_NOT_IN_ZONE ); break; - default: Expecting( "yes, no, or use_thermal" ); - } - - NeedLEFT(); - token = NextTok(); - - if( token != T_clearance ) - Expecting( T_clearance ); - - zone->SetZoneClearance( parseBoardUnits( "zone clearance" ) ); - NeedRIGHT(); - NeedRIGHT(); - break; - - case T_min_thickness: - zone->SetMinThickness( parseBoardUnits( T_min_thickness ) ); - NeedRIGHT(); - break; - - case T_fill: - token = NextTok(); - - if( token != T_yes && token != T_no ) - Expecting( "yes or no" ); - - zone->SetIsFilled( token == T_yes ); - - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - if( token != T_LEFT ) - Expecting( T_LEFT ); - - token = NextTok(); - - switch( token ) - { - case T_mode: - token = NextTok(); - - if( token != T_segment && token != T_polygon ) - Expecting( "segment or polygon" ); - - // @todo Create an enum for fill modes. Using true/false is not clear. - zone->SetFillMode( ( T_segment ) ? true : false ); - break; - - case T_arc_segments: - zone->SetArcSegCount( parseInt( "arc segment count" ) ); - break; - - case T_thermal_gap: - zone->SetThermalReliefGap( parseBoardUnits( T_thermal_gap ) ); - break; - - case T_thermal_bridge_width: - zone->SetThermalReliefCopperBridge( parseBoardUnits( T_thermal_bridge_width ) ); - break; - - case T_smoothing: - switch( NextTok() ) - { - case T_none: - zone->SetCornerSmoothingType( ZONE_SETTINGS::SMOOTHING_NONE ); - break; - - case T_chamfer: - zone->SetCornerSmoothingType( ZONE_SETTINGS::SMOOTHING_CHAMFER ); - break; - - case T_fillet: - zone->SetCornerSmoothingType( ZONE_SETTINGS::SMOOTHING_FILLET ); - break; - - default: - Expecting( "none, chamfer, or fillet" ); - } - - break; - - case T_radius: - zone->SetCornerRadius( parseBoardUnits( "corner radius" ) ); - break; - - default: - Expecting( "mode, arc_segments, thermal_gap, thermal_bridge_width, " - "smoothing, or radius" ); - } - - NeedRIGHT(); - } - - break; - - case T_polygon: - { - std::vector< wxPoint > pts; - - NeedLEFT(); - token = NextTok(); - - if( token != T_pts ) - Expecting( T_pts ); - - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - pts.push_back( parseXY() ); - } - - NeedRIGHT(); - zone->AddPolygon( pts ); - } - - break; - - case T_filled_polygon: - { - wxPoint pt; - std::vector< CPolyPt > pts; - - NeedLEFT(); - token = NextTok(); - - if( token != T_pts ) - Expecting( T_pts ); - - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - pt = parseXY(); - pts.push_back( CPolyPt( pt.x, pt.y ) ); - } - - NeedRIGHT(); - pts.back().end_contour = true; - zone->AddFilledPolysList( pts ); - } - - break; - - case T_fill_segments: - { - std::vector< SEGMENT > segs; - - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - if( token != T_LEFT ) - Expecting( T_LEFT ); - - token = NextTok(); - - if( token != T_pts ) - Expecting( T_pts ); - - SEGMENT segment( parseXY(), parseXY() ); - NeedRIGHT(); - segs.push_back( segment ); - } - - zone->AddFillSegments( segs ); - } - - break; - - default: - Expecting( "net, layer, tstamp, hatch, priority, connect_pads, min_thickness, " - "fill, polygon, filled_polygon, or fill_segments" ); - } - } - - if( zone->GetNumCorners() > 2 ) - { - if( !zone->IsOnCopperLayer() ) - { - zone->SetFillMode( 0 ); - zone->SetNet( 0 ); - } - - // Set hatch here, after outlines corners are read - zone->m_Poly->SetHatch( hatchStyle, hatchPitch ); - } - - return zone.release(); -} - - -PCB_TARGET* PCB_PARSER::parsePCB_TARGET() throw( IO_ERROR, PARSE_ERROR ) -{ - wxCHECK_MSG( CurTok() == T_target, NULL, - wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PCB_TARGET." ) ); - - wxPoint pt; - T token; - - auto_ptr< PCB_TARGET > target( new PCB_TARGET( NULL ) ); - - - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) - { - if( token == T_LEFT ) - token = NextTok(); - - switch( token ) - { - case T_x: - target->SetShape( 1 ); - break; - - case T_plus: - target->SetShape( 0 ); - break; - - case T_at: - pt.x = parseBoardUnits( "target x position" ); - pt.y = parseBoardUnits( "target y position" ); - target->SetPosition( pt ); - NeedRIGHT(); - break; - - case T_size: - target->SetSize( parseBoardUnits( "target size" ) ); - NeedRIGHT(); - break; - - case T_width: - target->SetWidth( parseBoardUnits( "target thickness" ) ); - NeedRIGHT(); - break; - - case T_tstamp: - target->SetTimeStamp( parseHex() ); - NeedRIGHT(); - break; - - default: - Expecting( "x, plus, at, size, width, or tstamp" ); - } - } - - return target.release(); -} - +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2012 CERN + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * @file pcb_parser.cpp + * @brief Pcbnew s-expression file format parser implementation. + */ + +#include +#include +#include +#include +#include +#include <3d_struct.h> +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +double PCB_PARSER::parseDouble() throw( IO_ERROR ) +{ + char* tmp; + + errno = 0; + + double fval = strtod( CurText(), &tmp ); + + if( errno ) + { + wxString error; + error.Printf( _( "invalid floating point number in\nfile: '%s'\nline: %d\noffset: %d" ), + GetChars( CurSource() ), CurLineNumber(), CurOffset() ); + + THROW_IO_ERROR( error ); + } + + if( CurText() == tmp ) + { + wxString error; + error.Printf( _( "missing floating point number in\nfile: '%s'\nline: %d\noffset: %d" ), + GetChars( CurSource() ), CurLineNumber(), CurOffset() ); + + THROW_IO_ERROR( error ); + } + + return fval; +} + + +bool PCB_PARSER::parseBool() throw( PARSE_ERROR ) +{ + T token = NextTok(); + + if( token == T_yes ) + return true; + else if( token == T_no ) + return false; + else + Expecting( "yes or no" ); + + return false; +} + + +wxPoint PCB_PARSER::parseXY() throw( PARSE_ERROR ) +{ + if( CurTok() != T_LEFT ) + NeedLEFT(); + + wxPoint pt; + T token = NextTok(); + + if( token != T_xy ) + Expecting( T_xy ); + + pt.x = parseBoardUnits( "X coordinate" ); + pt.y = parseBoardUnits( "Y coordinate" ); + + NeedRIGHT(); + + return pt; +} + + +void PCB_PARSER::parseXY( int* aX, int* aY ) throw( PARSE_ERROR ) +{ + wxPoint pt = parseXY(); + + if( aX ) + *aX = pt.x; + + if( aY ) + *aY = pt.y; +} + + +void PCB_PARSER::parseEDA_TEXT( EDA_TEXT* aText ) throw( PARSE_ERROR ) +{ + wxCHECK_RET( CurTok() == T_effects, + wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as EDA_TEXT." ) ); + + T token; + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + if( token != T_LEFT ) + Expecting( T_LEFT ); + + token = NextTok(); + + switch( token ) + { + case T_font: + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + if( token == T_LEFT ) + continue; + + switch( token ) + { + case T_size: + { + wxSize sz; + sz.SetHeight( parseBoardUnits( "text height" ) ); + sz.SetWidth( parseBoardUnits( "text width" ) ); + aText->SetSize( sz ); + NeedRIGHT(); + break; + } + + case T_thickness: + aText->SetThickness( parseBoardUnits( "text thickness" ) ); + NeedRIGHT(); + break; + + case T_bold: + aText->SetBold( true ); + break; + + case T_italic: + aText->SetItalic( true ); + break; + + default: + Expecting( "size, bold, or italic" ); + } + } + + break; + + case T_justify: + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + if( token == T_LEFT ) + continue; + + switch( token ) + { + case T_left: + aText->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT ); + break; + + case T_right: + aText->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT ); + break; + + case T_top: + aText->SetVertJustify( GR_TEXT_VJUSTIFY_TOP ); + break; + + case T_bottom: + aText->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM ); + break; + + case T_mirror: + aText->SetMirrored( true ); + break; + + default: + Expecting( "left, right, top, bottom, or mirror" ); + } + + } + break; + + case T_hide: + aText->SetVisible( false ); + break; + + default: + Expecting( "font, justify, or hide" ); + } + } +} + + +S3D_MASTER* PCB_PARSER::parse3DModel() throw( PARSE_ERROR ) +{ + wxCHECK_MSG( CurTok() == T_model, NULL, + wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as S3D_MASTER." ) ); + + T token; + + auto_ptr< S3D_MASTER > n3D( new S3D_MASTER( NULL ) ); + + NeedSYMBOL(); + n3D->m_Shape3DName = FromUTF8(); + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + if( token != T_LEFT ) + Expecting( T_LEFT ); + + token = NextTok(); + + switch( token ) + { + case T_at: + NeedLEFT(); + token = NextTok(); + + if( token != T_xyz ) + Expecting( T_xyz ); + + n3D->m_MatPosition.x = parseDouble( "x value" ); + n3D->m_MatPosition.y = parseDouble( "y value" ); + n3D->m_MatPosition.z = parseDouble( "z value" ); + NeedRIGHT(); + break; + + case T_scale: + NeedLEFT(); + token = NextTok(); + + if( token != T_xyz ) + Expecting( T_xyz ); + + n3D->m_MatScale.x = parseDouble( "x value" ); + n3D->m_MatScale.y = parseDouble( "y value" ); + n3D->m_MatScale.z = parseDouble( "z value" ); + NeedRIGHT(); + break; + + case T_rotate: + NeedLEFT(); + token = NextTok(); + + if( token != T_xyz ) + Expecting( T_xyz ); + + n3D->m_MatRotation.x = parseDouble( "x value" ); + n3D->m_MatRotation.y = parseDouble( "y value" ); + n3D->m_MatRotation.z = parseDouble( "z value" ); + NeedRIGHT(); + break; + + default: + Expecting( "at, scale, or rotate" ); + } + + NeedRIGHT(); + } + + return n3D.release(); +} + + +BOARD_ITEM* PCB_PARSER::Parse() throw( IO_ERROR, PARSE_ERROR ) +{ + T token; + BOARD_ITEM* item; + + token = NextTok(); + + if( token != T_LEFT ) + Expecting( T_LEFT ); + + switch( NextTok() ) + { + case T_kicad_pcb: + if( m_board == NULL ) + m_board = new BOARD(); + + item = (BOARD_ITEM*) parseBOARD(); + break; + + default: + wxString err; + err.Printf( _( "unknown token \"%s\" " ), GetChars( FromUTF8() ) ); + THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() ); + } + + return item; +} + + +BOARD* PCB_PARSER::parseBOARD() throw( IO_ERROR, PARSE_ERROR ) +{ + T token; + + parseHeader(); + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + if( token != T_LEFT ) + { + wxLogDebug( "Expect ( in parseBoard() after %s.", PrevTok() ); + Expecting( T_LEFT ); + } + + token = NextTok(); + + switch( token ) + { + case T_general: + parseGeneralSection(); + break; + + case T_page: + parsePAGE_INFO(); + break; + + case T_title_block: + parseTITLE_BLOCK(); + break; + + case T_layers: + parseLayers(); + break; + + case T_setup: + parseSetup(); + break; + + case T_net: + parseNETINFO_ITEM(); + break; + + case T_net_class: + parseNETCLASS(); + break; + + case T_gr_arc: + case T_gr_circle: + case T_gr_curve: + case T_gr_line: + case T_gr_poly: + m_board->Add( parseDRAWSEGMENT(), ADD_APPEND ); + break; + + case T_gr_text: + m_board->Add( parseTEXTE_PCB(), ADD_APPEND ); + break; + + case T_dimension: + m_board->Add( parseDIMENSION(), ADD_APPEND ); + break; + + case T_module: + m_board->Add( parseMODULE(), ADD_APPEND ); + break; + + case T_segment: + m_board->m_Track.Append( parseTRACK() ); + break; + + case T_via: + m_board->m_Track.Append( parseSEGVIA() ); + break; + + case T_zone: + m_board->Add( parseZONE_CONTAINER(), ADD_APPEND ); + break; + + case T_target: + m_board->Add( parsePCB_TARGET(), ADD_APPEND ); + break; + + default: + wxString err; + err.Printf( _( "unknown token \"%s\"" ), GetChars( FromUTF8() ) ); + THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() ); + } + } + + return m_board; +} + + +void PCB_PARSER::parseHeader() throw( IO_ERROR, PARSE_ERROR ) +{ + wxCHECK_RET( CurTok() == T_kicad_pcb, + wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a header." ) ); + + T token; + + NeedLEFT(); + token = NextTok(); + + if( token != T_version ) + Expecting( GetTokenText( T_version ) ); + + // Get the file version. + m_board->SetFileFormatVersionAtLoad( NeedNUMBER( GetTokenText( T_version ) ) ); + + // Skip the host name and host build version information. + NeedRIGHT(); + NeedLEFT(); + NeedSYMBOL(); + NeedSYMBOL(); + NeedSYMBOL(); + NeedRIGHT(); +} + + +void PCB_PARSER::parseGeneralSection() throw( IO_ERROR, PARSE_ERROR ) +{ + wxCHECK_RET( CurTok() == T_general, + wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + + wxT( " as a general section." ) ); + + T token; + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + if( token != T_LEFT ) + Expecting( T_LEFT ); + + token = NextTok(); + + switch( token ) + { + case T_thickness: + m_board->GetDesignSettings().SetBoardThickness( parseBoardUnits( T_thickness ) ); + NeedRIGHT(); + break; + + case T_no_connects: + m_board->m_NbNoconnect = parseInt( "no connect count" ); + NeedRIGHT(); + break; + + default: // Skip everything but the board thickness. + wxLogDebug( wxT( "Skipping general section token %s " ), GetTokenString( token ) ); + + while( ( token = NextTok() ) != T_RIGHT ) + { + if( !IsSymbol( token ) && token != T_NUMBER ) + Expecting( "symbol or number" ); + } + } + } +} + + +void PCB_PARSER::parsePAGE_INFO() throw( IO_ERROR, PARSE_ERROR ) +{ + wxCHECK_RET( CurTok() == T_page, + wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a PAGE_INFO." ) ); + + T token; + bool isPortrait = false; + + NeedSYMBOL(); + + wxString pageType = FromUTF8(); + + if( pageType == PAGE_INFO::Custom ) + { + PAGE_INFO::SetCustomWidthMils( Iu2Mils( NeedNUMBER( "width" ) ) ); + PAGE_INFO::SetCustomHeightMils( Iu2Mils( NeedNUMBER( "height" ) ) ); + } + + token = NextTok(); + + if( token == T_portrait ) + { + isPortrait = true; + NeedRIGHT(); + } + else if( token != T_RIGHT ) + { + Expecting( "portrait|)" ); + } + + PAGE_INFO pageInfo; + + if( !pageInfo.SetType( pageType, isPortrait ) ) + { + wxString err; + err.Printf( _( "page type \"%s\" is not valid " ), GetChars( FromUTF8() ) ); + THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() ); + } + + m_board->SetPageSettings( pageInfo ); +} + + +void PCB_PARSER::parseTITLE_BLOCK() throw( IO_ERROR, PARSE_ERROR ) +{ + wxCHECK_RET( CurTok() == T_title_block, + wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + + wxT( " as TITLE_BLOCK." ) ); + + T token; + TITLE_BLOCK titleBlock; + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + if( token != T_LEFT ) + Expecting( T_LEFT ); + + token = NextTok(); + + switch( token ) + { + case T_title: + NeedSYMBOL(); + titleBlock.SetTitle( FromUTF8() ); + break; + + case T_date: + NeedSYMBOL(); + titleBlock.SetDate( FromUTF8() ); + break; + + case T_rev: + NextTok(); + titleBlock.SetRevision( FromUTF8() ); + break; + + case T_company: + NextTok(); + titleBlock.SetCompany( FromUTF8() ); + break; + + case T_comment: + { + int commentNumber = NeedNUMBER( "comment" ); + + switch( commentNumber ) + { + case 1: + NextTok(); + titleBlock.SetComment1( FromUTF8() ); + break; + + case 2: + NextTok(); + titleBlock.SetComment2( FromUTF8() ); + break; + + case 3: + NextTok(); + titleBlock.SetComment3( FromUTF8() ); + break; + + case 4: + NextTok(); + titleBlock.SetComment4( FromUTF8() ); + break; + + default: + wxString err; + err.Printf( _( "%d is not a valid title block comment number" ), commentNumber ); + THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() ); + } + + break; + } + + default: + Expecting( "title, date, rev, company, or comment" ); + } + + NeedRIGHT(); + } + + m_board->SetTitleBlock( titleBlock ); +} + + +void PCB_PARSER::parseLayers() throw( IO_ERROR, PARSE_ERROR ) +{ + wxCHECK_RET( CurTok() == T_layers, + wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as layers." ) ); + + T token; + wxString name; + wxString type; + bool isVisible; + int visibleLayers = 0; + int enabledLayers = 0; + std::vector< LAYER > layers; + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + if( token != T_LEFT ) + Expecting( T_LEFT ); + +#if !USE_LAYER_NAMES + NeedNUMBER( "layer index" ); +#endif + + NeedSYMBOL(); + name = FromUTF8(); + NeedSYMBOL(); + type = FromUTF8(); + + token = NextTok(); + + if( token == T_hide ) + { + isVisible = false; + NeedRIGHT(); + } + else if( token == T_RIGHT ) + { + isVisible = true; + } + else + { + Expecting( "hide or )" ); + } + + layers.push_back( LAYER( name, LAYER::ParseType( type.c_str() ), isVisible ) ); + } + + int copperLayerCount = 0; + + for( unsigned i = 0; i < layers.size(); i++ ) + { + if( layers[i].m_Type != LT_UNDEFINED ) + copperLayerCount++; + } + + // We need at least 2 copper layers and there must be an even number of them. + if( (copperLayerCount < 2) || ((copperLayerCount % 2) != 0) ) + { + wxString err; + err.Printf( _( "%d is not a valid layer count" ), layers.size() ); + THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() ); + } + + m_board->SetCopperLayerCount( copperLayerCount ); + + // Copper layers are sequential from front to back in the file but the current layer + // design uses sequential layers from back to front except for the front layer which + // is always vector index 15. + for( unsigned i = 0; i < layers.size(); i++ ) + { + int layerIndex = i; + + // The copper layers can have different names but they always are at the beginning + // and have a valid layer type. Non-copper layer name cannot be changed so the + // list index can be looked up by name. + if( layers[i].m_Type != LT_UNDEFINED ) + { + if( i == 0 ) + layerIndex = LAYER_N_FRONT; + else + layerIndex = copperLayerCount - 1 - i; + } + else + { + layerIndex = LAYER::GetDefaultIndex( layers[i].m_Name ); + + if( layerIndex == UNDEFINED_LAYER ) + { + wxString error; + error.Printf( _( "Cannot determine fixed layer list index of layer name \"%s\"" ), + layers[i].m_Name ); + THROW_IO_ERROR( error ); + } + } + + enabledLayers |= 1 << layerIndex; + + if( layers[i].IsVisible() ) + visibleLayers |= 1 << layerIndex; + + layers[i].SetFixedListIndex( layerIndex ); + m_board->SetLayer( layerIndex, layers[i] ); + m_layerMap[ layers[i].m_Name ] = layerIndex; + wxLogDebug( wxT( "Mapping layer %s index index %d" ), + GetChars( layers[i].m_Name ), layerIndex ); + } + + m_board->SetVisibleLayers( visibleLayers ); + m_board->SetEnabledLayers( enabledLayers ); +} + + +int PCB_PARSER::lookUpLayer() throw( PARSE_ERROR, IO_ERROR ) +{ +#if USE_LAYER_NAMES + wxString name = FromUTF8(); + const LAYER_HASH_MAP::iterator it = m_layerMap.find( name ); + + if( it == m_layerMap.end() ) + { + wxString error; + error.Printf( _( "Layer %s in file <%s> at line %d, position %d was not defined in the layers section" ), + GetChars( name ), GetChars( CurSource() ), CurLineNumber(), CurOffset() ); + THROW_IO_ERROR( error ); + } + + return m_layerMap[ name ]; +#else + if( CurTok() != T_NUMBER ) + Expecting( T_NUMBER ); + + int layerIndex = parseInt(); + + if( !m_board->IsLayerEnabled( layerIndex ) ) + { + wxString error; + error.Printf( _( "Layer index %d in file <%s> at line, offset %d was not defined in the layers section" ), + layerIndex, GetChars( CurSource() ), CurLineNumber(), CurOffset() ); + THROW_IO_ERROR( error ); + } + + return layerIndex; +#endif +} + + +int PCB_PARSER::parseBoardItemLayer() throw( PARSE_ERROR, IO_ERROR ) +{ + wxCHECK_MSG( CurTok() == T_layer, UNDEFINED_LAYER, + wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as layer." ) ); + + NextTok(); + + int layerIndex = lookUpLayer(); + + // Handle closing ) in object parser. + + return layerIndex; +} + + +int PCB_PARSER::parseBoardItemLayersAsMask() throw( PARSE_ERROR, IO_ERROR ) +{ + wxCHECK_MSG( CurTok() == T_layers, 0, + wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + + wxT( " as item layer mask." ) ); + + int layerIndex; + int layerMask = 0; + T token; + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + layerIndex = lookUpLayer(); + layerMask |= ( 1 << layerIndex ); + } + + return layerMask; +} + + +void PCB_PARSER::parseSetup() throw( IO_ERROR, PARSE_ERROR ) +{ + wxCHECK_RET( CurTok() == T_setup, + wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as setup." ) ); + + T token; + int lastTraceWidth; + NETCLASS* defaultNetclass = m_board->m_NetClasses.GetDefault(); + BOARD_DESIGN_SETTINGS designSettings = m_board->GetDesignSettings(); + ZONE_SETTINGS zoneSettings = m_board->GetZoneSettings(); + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + if( token != T_LEFT ) + { + wxLogDebug( "Expected ( in parseSetup()." ); + Expecting( T_LEFT ); + } + + token = NextTok(); + + switch( token ) + { + case T_last_trace_width: + lastTraceWidth = parseBoardUnits( T_last_trace_width ); + NeedRIGHT(); + break; + + case T_user_trace_width: + m_board->m_TrackWidthList.push_back( parseBoardUnits( T_user_trace_width ) ); + NeedRIGHT(); + break; + + case T_trace_clearance: + defaultNetclass->SetClearance( parseBoardUnits( T_trace_clearance ) ); + NeedRIGHT(); + break; + + case T_zone_clearance: + zoneSettings.m_ZoneClearance = parseBoardUnits( T_zone_clearance ); + NeedRIGHT(); + break; + + case T_zone_45_only: + zoneSettings.m_Zone_45_Only = parseBool(); + NeedRIGHT(); + break; + + case T_trace_min: + designSettings.m_TrackMinWidth = parseBoardUnits( T_trace_min ); + NeedRIGHT(); + break; + + case T_segment_width: + designSettings.m_DrawSegmentWidth = parseBoardUnits( T_segment_width ); + NeedRIGHT(); + break; + + case T_edge_width: + designSettings.m_EdgeSegmentWidth = parseBoardUnits( T_edge_width ); + NeedRIGHT(); + break; + + case T_via_size: + defaultNetclass->SetViaDiameter( parseBoardUnits( T_via_size ) ); + NeedRIGHT(); + break; + + case T_via_drill: + defaultNetclass->SetViaDrill( parseBoardUnits( T_via_drill ) ); + NeedRIGHT(); + break; + + case T_via_min_size: + designSettings.m_ViasMinSize = parseBoardUnits( T_via_min_size ); + NeedRIGHT(); + break; + + case T_via_min_drill: + designSettings.m_ViasMinDrill = parseBoardUnits( T_via_min_drill ); + NeedRIGHT(); + break; + + case T_user_via: + { + int viaSize = parseBoardUnits( "user via size" ); + int viaDrill = parseBoardUnits( "user via drill" ); + m_board->m_ViasDimensionsList.push_back( VIA_DIMENSION( viaSize, viaDrill ) ); + NeedRIGHT(); + } + break; + + case T_uvia_size: + defaultNetclass->SetuViaDiameter( parseBoardUnits( T_uvia_size ) ); + NeedRIGHT(); + break; + + case T_uvia_drill: + defaultNetclass->SetuViaDrill( parseBoardUnits( T_uvia_drill ) ); + NeedRIGHT(); + break; + + case T_uvias_allowed: + designSettings.m_MicroViasAllowed = parseBool(); + NeedRIGHT(); + break; + + case T_uvia_min_size: + designSettings.m_MicroViasMinSize = parseBoardUnits( T_uvia_min_size ); + NeedRIGHT(); + break; + + case T_uvia_min_drill: + designSettings.m_MicroViasMinDrill = parseBoardUnits( T_uvia_min_drill ); + NeedRIGHT(); + break; + + case T_pcb_text_width: + designSettings.m_PcbTextWidth = parseBoardUnits( T_pcb_text_width ); + NeedRIGHT(); + break; + + case T_pcb_text_size: + designSettings.m_PcbTextSize.x = parseBoardUnits( "pcb text width" ); + designSettings.m_PcbTextSize.y = parseBoardUnits( "pcb text height" ); + NeedRIGHT(); + break; + + case T_mod_edge_width: + designSettings.m_ModuleSegmentWidth = parseBoardUnits( T_mod_edge_width ); + NeedRIGHT(); + break; + + case T_mod_text_size: + designSettings.m_ModuleTextSize.x = parseBoardUnits( "module text width" ); + designSettings.m_ModuleTextSize.y = parseBoardUnits( "module text height" ); + NeedRIGHT(); + break; + + case T_mod_text_width: + designSettings.m_ModuleTextWidth = parseBoardUnits( T_mod_text_width ); + NeedRIGHT(); + break; + + case T_pad_size: + { + wxSize sz; + sz.SetWidth( parseBoardUnits( "master pad width" ) ); + sz.SetHeight( parseBoardUnits( "master pad height" ) ); + designSettings.m_Pad_Master.SetSize( sz ); + NeedRIGHT(); + break; + } + + case T_pad_drill: + { + int drillSize = parseBoardUnits( T_pad_drill ); + designSettings.m_Pad_Master.SetDrillSize( wxSize( drillSize, drillSize ) ); + NeedRIGHT(); + } + break; + + case T_pad_to_mask_clearance: + designSettings.m_SolderMaskMargin = parseBoardUnits( T_pad_to_mask_clearance ); + NeedRIGHT(); + break; + + case T_pad_to_paste_clearance: + designSettings.m_SolderPasteMargin = parseBoardUnits( T_pad_to_paste_clearance ); + NeedRIGHT(); + break; + + case T_pad_to_paste_clearance_ratio: + designSettings.m_SolderPasteMarginRatio = parseDouble( T_pad_to_paste_clearance_ratio ); + NeedRIGHT(); + break; + + case T_aux_axis_origin: + { + int x = parseBoardUnits( "auxilary origin X" ); + int y = parseBoardUnits( "auxilary origin Y" ); + // x, y are not evaluated left to right, since they are push on stack right to left + m_board->SetOriginAxisPosition( wxPoint( x, y ) ); + NeedRIGHT(); + break; + } + + case T_visible_elements: + designSettings.SetVisibleElements( parseHex() ); + NeedRIGHT(); + break; + + // case T_pcbplotparams: + // { + // PCB_PLOT_PARAMS plotParams; + // PCB_PLOT_PARAMS_PARSER parser( reader ); + + // plotParams.Parse( &parser ); + // m_board->SetPlotOptions( plotParams ); + // break; + // } + + default: + Expecting( "valid setup token" ); + } + } + + m_board->SetDesignSettings( designSettings ); + m_board->SetZoneSettings( zoneSettings ); + + // Until such time as the *.brd file does not have the + // global parameters: + // "last_trace_width", "trace_min_width", "via_size", "via_drill", + // "via_min_size", and "via_clearance", put those same global + // values into the default NETCLASS until later board load + // code should override them. *.kicad_brd files which have been + // saved with knowledge of NETCLASSes will override these + // defaults, old boards will not. + // + // @todo: I expect that at some point we can remove said global + // parameters from the *.brd file since the ones in the + // default netclass serve the same purpose. If needed + // at all, the global defaults should go into a preferences + // file instead so they are there to start new board + // projects. + m_board->m_NetClasses.GetDefault()->SetParams(); +} + + +void PCB_PARSER::parseNETINFO_ITEM() throw( IO_ERROR, PARSE_ERROR ) +{ + wxCHECK_RET( CurTok() == T_net, + wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as net." ) ); + + int number = parseInt( "net number" ); + NeedSYMBOL(); + wxString name = FromUTF8(); + NeedRIGHT(); + + NETINFO_ITEM* net = new NETINFO_ITEM( m_board ); + net->SetNet( number ); + net->SetNetname( name ); + m_board->AppendNet( net ); +} + + +void PCB_PARSER::parseNETCLASS() throw( IO_ERROR, PARSE_ERROR ) +{ + wxCHECK_RET( CurTok() == T_net_class, + wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as net class." ) ); + + T token; + + auto_ptr nc( new NETCLASS( m_board, wxEmptyString ) ); + + NeedSYMBOL(); + nc->SetName( FromUTF8() ); + NeedSYMBOL(); + nc->SetDescription( FromUTF8() ); + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + if( token != T_LEFT ) + Expecting( T_LEFT ); + + token = NextTok(); + + switch( token ) + { + case T_clearance: + nc->SetClearance( parseBoardUnits( T_clearance ) ); + break; + + case T_trace_width: + nc->SetTrackWidth( parseBoardUnits( T_trace_width ) ); + break; + + case T_via_dia: + nc->SetViaDiameter( parseBoardUnits( T_via_dia ) ); + break; + + case T_via_drill: + nc->SetViaDrill( parseBoardUnits( T_via_drill ) ); + break; + + case T_uvia_dia: + nc->SetuViaDiameter( parseBoardUnits( T_uvia_dia ) ); + break; + + case T_uvia_drill: + nc->SetuViaDrill( parseBoardUnits( T_uvia_drill ) ); + break; + + case T_add_net: + NeedSYMBOL(); + nc->Add( FromUTF8() ); + break; + + default: + Expecting( "clearance, trace_width, via_dia, via_drill, uvia_dia, uvia_drill, or add_net" ); + } + + NeedRIGHT(); + } + + if( m_board->m_NetClasses.Add( nc.get() ) ) + { + nc.release(); + } + else + { + // Must have been a name conflict, this is a bad board file. + // User may have done a hand edit to the file. + + // auto_ptr will delete nc on this code path + + wxString error; + error.Printf( _( "duplicate NETCLASS name '%s' in file %s at line %d, offset %d" ), + nc->GetName().GetData(), CurSource(), CurLineNumber(), CurOffset() ); + THROW_IO_ERROR( error ); + } +} + + +DRAWSEGMENT* PCB_PARSER::parseDRAWSEGMENT() throw( IO_ERROR, PARSE_ERROR ) +{ + wxCHECK_MSG( CurTok() == T_gr_arc || CurTok() == T_gr_circle || CurTok() == T_gr_curve || + CurTok() == T_gr_line || CurTok() == T_gr_poly, NULL, + wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as DRAWSEGMENT." ) ); + + T token; + + auto_ptr< DRAWSEGMENT > segment( new DRAWSEGMENT( NULL ) ); + + switch( CurTok() ) + { + case T_gr_arc: + segment->SetShape( S_ARC ); + NeedLEFT(); + token = NextTok(); + + if( token != T_start ) + Expecting( T_start ); + + segment->SetStart( parseXY() ); + NeedRIGHT(); + NeedLEFT(); + token = NextTok(); + + if( token != T_end ) + Expecting( T_end ); + + segment->SetEnd( parseXY() ); + NeedRIGHT(); + token = NextTok(); + + if( token != T_angle ) + Expecting( T_angle ); + + segment->SetAngle( parseDouble( "segment angle" ) ); + NeedRIGHT(); + break; + + case T_gr_circle: + segment->SetShape( S_CIRCLE ); + NeedLEFT(); + token = NextTok(); + + if( token != T_center ) + Expecting( T_center ); + + segment->SetStart( parseXY() ); + NeedRIGHT(); + NeedLEFT(); + + token = NextTok(); + if( token != T_end ) + Expecting( T_end ); + + segment->SetEnd( parseXY() ); + NeedRIGHT(); + break; + + case T_gr_curve: + segment->SetShape( S_CURVE ); + NeedLEFT(); + token = NextTok(); + + if( token != T_pts ) + Expecting( T_pts ); + + segment->SetStart( parseXY() ); + segment->SetBezControl1( parseXY() ); + segment->SetBezControl2( parseXY() ); + segment->SetEnd( parseXY() ); + NeedRIGHT(); + break; + + case T_gr_line: + // Default DRAWSEGMENT type is S_SEGMENT. + NeedLEFT(); + token = NextTok(); + + if( token != T_pts ) + Expecting( T_pts ); + + segment->SetStart( parseXY() ); + segment->SetEnd( parseXY() ); + NeedRIGHT(); + NeedLEFT(); + token = NextTok(); + + if( token != T_angle ) + Expecting( T_angle ); + + segment->SetAngle( parseDouble( "segment angle" ) * 10.0 ); + NeedRIGHT(); + break; + + case T_gr_poly: + { + segment->SetShape( S_POLYGON ); + NeedLEFT(); + token = NextTok(); + + if( token != T_pts ) + Expecting( T_pts ); + + std::vector< wxPoint > pts; + + while( (token = NextTok()) != T_RIGHT ) + pts.push_back( parseXY() ); + + segment->SetPolyPoints( pts ); + } + break; + + default: + Expecting( "gr_arc, gr_circle, gr_curve, gr_line, or gr_poly" ); + } + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + if( token != T_LEFT ) + Expecting( T_LEFT ); + + token = NextTok(); + + switch( token ) + { + case T_layer: + segment->SetLayer( parseBoardItemLayer() ); + break; + + case T_width: + segment->SetWidth( parseBoardUnits( T_width ) ); + break; + + case T_tstamp: + segment->SetTimeStamp( parseHex() ); + break; + + case T_status: + segment->SetStatus( parseHex() ); + break; + + default: + Expecting( "layer, width, tstamp, or status" ); + } + + NeedRIGHT(); + } + + return segment.release(); +} + + +TEXTE_PCB* PCB_PARSER::parseTEXTE_PCB() throw( IO_ERROR, PARSE_ERROR ) +{ + wxCHECK_MSG( CurTok() == T_gr_text, NULL, + wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as TEXTE_PCB." ) ); + + T token; + + auto_ptr< TEXTE_PCB > text( new TEXTE_PCB( m_board ) ); + NeedSYMBOLorNUMBER(); + + text->SetText( FromUTF8() ); + NeedLEFT(); + token = NextTok(); + + if( token != T_at ) + Expecting( T_at ); + + wxPoint pt; + + pt.x = parseBoardUnits( "X coordinate" ); + pt.y = parseBoardUnits( "Y coordinate" ); + text->SetPosition( pt ); + text->SetOrientation( parseDouble( "angle" ) * 10.0 ); + NeedRIGHT(); + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + if( token != T_LEFT ) + Expecting( T_LEFT ); + + token = NextTok(); + + switch( token ) + { + case T_layer: + text->SetLayer( parseBoardItemLayer() ); + NeedRIGHT(); + break; + + case T_tstamp: + text->SetTimeStamp( parseHex() ); + NeedRIGHT(); + break; + + case T_effects: + parseEDA_TEXT( (EDA_TEXT*) text.get() ); + break; + + default: + Expecting( "layer, tstamp or effects" ); + } + } + + return text.release(); +} + + +DIMENSION* PCB_PARSER::parseDIMENSION() throw( IO_ERROR, PARSE_ERROR ) +{ + wxCHECK_MSG( CurTok() == T_dimension, NULL, + wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as DIMENSION." ) ); + + T token; + + auto_ptr< DIMENSION > dimension( new DIMENSION( NULL ) ); + + dimension->m_Value = parseBoardUnits( "dimension value" ); + NeedLEFT(); + token = NextTok(); + + if( token != T_width ) + Expecting( T_width ); + + dimension->SetWidth( parseBoardUnits( "dimension width value" ) ); + NeedRIGHT(); + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + if( token != T_LEFT ) + Expecting( T_LEFT ); + + token = NextTok(); + + switch( token ) + { + case T_layer: + dimension->SetLayer( parseBoardItemLayer() ); + NeedRIGHT(); + break; + + case T_tstamp: + dimension->SetTimeStamp( parseHex() ); + NeedRIGHT(); + break; + + case T_gr_text: + { + TEXTE_PCB* text = parseTEXTE_PCB(); + dimension->m_Text = *text; + delete text; + break; + } + + case T_feature1: + NeedLEFT(); + token = NextTok(); + + if( token != T_pts ) + Expecting( T_pts ); + + parseXY( &dimension->m_featureLineDOx, &dimension->m_featureLineDOy ); + parseXY( &dimension->m_featureLineDFx, &dimension->m_featureLineDFy ); + NeedRIGHT(); + NeedRIGHT(); + break; + + case T_feature2: + NeedLEFT(); + token = NextTok(); + + if( token != T_pts ) + Expecting( T_pts ); + + parseXY( &dimension->m_featureLineGOx, &dimension->m_featureLineGOy ); + parseXY( &dimension->m_featureLineGFx, &dimension->m_featureLineGFy ); + NeedRIGHT(); + NeedRIGHT(); + break; + + + case T_crossbar: + NeedLEFT(); + token = NextTok(); + + if( token != T_pts ) + Expecting( T_pts ); + + parseXY( &dimension->m_crossBarOx, &dimension->m_crossBarOy ); + parseXY( &dimension->m_crossBarFx, &dimension->m_crossBarFy ); + NeedRIGHT(); + NeedRIGHT(); + break; + + case T_arrow1a: + NeedLEFT(); + token = NextTok(); + + if( token != T_pts ) + Expecting( T_pts ); + + parseXY( &dimension->m_arrowD1Ox, &dimension->m_arrowD1Oy ); + parseXY( &dimension->m_arrowD1Fx, &dimension->m_arrowD1Fy ); + NeedRIGHT(); + NeedRIGHT(); + break; + + case T_arrow1b: + NeedLEFT(); + token = NextTok(); + + if( token != T_pts ) + Expecting( T_pts ); + + parseXY( &dimension->m_arrowD2Ox, &dimension->m_arrowD2Oy ); + parseXY( &dimension->m_arrowD2Fx, &dimension->m_arrowD2Fy ); + NeedRIGHT(); + NeedRIGHT(); + break; + + case T_arrow2a: + NeedLEFT(); + token = NextTok(); + + if( token != T_pts ) + Expecting( T_pts ); + + parseXY( &dimension->m_arrowG1Ox, &dimension->m_arrowG1Oy ); + parseXY( &dimension->m_arrowG1Fx, &dimension->m_arrowG1Fy ); + NeedRIGHT(); + NeedRIGHT(); + break; + + case T_arrow2b: + NeedLEFT(); + token = NextTok(); + + if( token != T_pts ) + Expecting( T_pts ); + + parseXY( &dimension->m_arrowG2Ox, &dimension->m_arrowG2Oy ); + parseXY( &dimension->m_arrowG2Fx, &dimension->m_arrowG2Fy ); + NeedRIGHT(); + NeedRIGHT(); + break; + + default: + Expecting( "layer, tstamp, gr_text, feature1, feature2 crossbar, arrow1a, " + "arrow1b, arrow2a, or arrow2b" ); + } + } + + return dimension.release(); +} + + +MODULE* PCB_PARSER::parseMODULE() throw( IO_ERROR, PARSE_ERROR ) +{ + wxCHECK_MSG( CurTok() == T_module, NULL, + wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as MODULE." ) ); + + wxPoint pt; + T token; + + auto_ptr< MODULE > module( new MODULE( m_board ) ); + + NeedSYMBOL(); + module->SetLibRef( FromUTF8() ); + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + if( token == T_LEFT ) + token = NextTok(); + + switch( token ) + { + case T_locked: + module->SetLocked( true ); + break; + + case T_placed: + module->SetIsPlaced( true ); + break; + + case T_layer: + module->SetLayer( parseBoardItemLayer() ); + NeedRIGHT(); + break; + + case T_tedit: + module->SetLastEditTime( parseHex() ); + NeedRIGHT(); + break; + + case T_tstamp: + module->SetTimeStamp( parseHex() ); + NeedRIGHT(); + break; + + case T_at: + pt.x = parseBoardUnits( "X coordinate" ); + pt.y = parseBoardUnits( "Y coordinate" ); + module->SetPosition( pt ); + token = NextTok(); + + if( token == T_NUMBER ) + { + module->SetOrientation( parseDouble() * 10.0 ); + NeedRIGHT(); + } + else if( token != T_RIGHT ) + { + Expecting( T_RIGHT ); + } + + break; + + case T_descr: + NeedSYMBOL(); + module->SetDescription( FromUTF8() ); + NeedRIGHT(); + break; + + case T_tags: + NeedSYMBOL(); + module->SetKeywords( FromUTF8() ); + NeedRIGHT(); + break; + + case T_path: + NeedSYMBOL(); + module->SetPath( FromUTF8() ); + NeedRIGHT(); + break; + + case T_autoplace_cost90: + module->m_CntRot90 = parseInt( "auto place cost at 90 degrees" ); + NeedRIGHT(); + break; + + case T_autoplace_cost180: + module->m_CntRot180 = parseInt( "auto place cost at 180 degrees" ); + NeedRIGHT(); + break; + + case T_solder_mask_margin: + module->SetLocalSolderMaskMargin( parseBoardUnits( "local solder mask margin value" ) ); + NeedRIGHT(); + break; + + case T_solder_paste_margin: + module->SetLocalSolderPasteMargin( + parseBoardUnits( "local solder paste margin value" ) ); + NeedRIGHT(); + break; + + case T_solder_paste_ratio: + module->SetLocalSolderPasteMarginRatio( + parseDouble( "local solder paste margin ratio value" ) ); + NeedRIGHT(); + break; + + case T_clearance: + module->SetLocalClearance( parseBoardUnits( "local clearance value" ) ); + NeedRIGHT(); + break; + + case T_zone_connect: + module->SetZoneConnection( (ZoneConnection) parseInt( "zone connection value" ) ); + NeedRIGHT(); + break; + + case T_thermal_width: + module->SetThermalWidth( parseBoardUnits( "thermal width value" ) ); + NeedRIGHT(); + break; + + case T_thermal_gap: + module->SetThermalGap( parseBoardUnits( "thermal gap value" ) ); + NeedRIGHT(); + break; + + case T_attr: + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + switch( token ) + { + case T_smd: + module->SetAttributes( module->GetAttributes() | MOD_CMS ); + break; + + case T_virtual: + module->SetAttributes( module->GetAttributes() | MOD_VIRTUAL ); + break; + + default: + Expecting( "smd and/or virtual" ); + } + } + + break; + + case T_fp_text: + { + TEXTE_MODULE* text = parseTEXTE_MODULE(); + text->SetParent( module.get() ); + double orientation = text->GetOrientation(); + orientation -= module->GetOrientation(); + text->SetOrientation( orientation ); + text->SetDrawCoord(); + + if( text->GetType() == TEXT_is_REFERENCE ) + { + module->Reference() = *text; + delete text; + } + else if( text->GetType() == TEXT_is_VALUE ) + { + module->Value() = *text; + delete text; + } + else + { + module->m_Drawings.PushBack( text ); + } + + break; + } + + case T_fp_arc: + case T_fp_circle: + case T_fp_curve: + case T_fp_line: + case T_fp_poly: + { + EDGE_MODULE* em = parseEDGE_MODULE(); + em->SetParent( module.get() ); + em->SetDrawCoord(); + module->m_Drawings.PushBack( em ); + break; + } + + case T_pad: + { + D_PAD* pad = parseD_PAD(); + wxPoint pt = pad->GetPos0(); + RotatePoint( &pt, module->GetOrientation() ); + pad->SetPosition( pt + module->GetPosition() ); + module->AddPad( pad ); + break; + } + + case T_model: + module->Add3DModel( parse3DModel() ); + break; + + default: + Expecting( "locked, placed, tedit, tstamp, at, descr, tags, path, " + "autoplace_cost90, autoplace_cost180, solder_mask_margin, " + "solder_paste_margin, solder_paste_ratio, clearance, " + "zone_connect, thermal_width, thermal_gap, attr, fp_text, " + "fp_arc, fp_circle, fp_curve, fp_line, fp_poly, pad, or model" ); + } + } + + return module.release(); +} + + +TEXTE_MODULE* PCB_PARSER::parseTEXTE_MODULE() throw( IO_ERROR, PARSE_ERROR ) +{ + wxCHECK_MSG( CurTok() == T_fp_text, NULL, + wxString::Format( wxT( "Cannot parse %s as TEXTE_MODULE at line %d, offset %d." ), + GetTokenString( CurTok() ), CurLineNumber(), CurOffset() ) ); + + T token = NextTok(); + + auto_ptr< TEXTE_MODULE > text( new TEXTE_MODULE( NULL ) ); + + switch( token ) + { + case T_reference: + text->SetType( TEXT_is_REFERENCE ); + break; + + case T_value: + text->SetType( TEXT_is_VALUE ); + break; + + case T_user: + break; // Default type is user text. + + default: + THROW_IO_ERROR( wxString::Format( _( "cannot handle module text type %s" ), + GetChars( FromUTF8() ) ) ); + } + + NeedSYMBOLorNUMBER(); + + text->SetText( FromUTF8() ); + NeedLEFT(); + token = NextTok(); + + if( token != T_at ) + Expecting( T_at ); + + wxPoint pt; + + pt.x = parseBoardUnits( "X coordinate" ); + pt.y = parseBoardUnits( "Y coordinate" ); + text->SetPos0( pt ); + text->SetOrientation( parseDouble( "angle" ) * 10.0 ); + NeedRIGHT(); + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + if( token == T_LEFT ) + token = NextTok(); + + switch( token ) + { + case T_layer: + text->SetLayer( parseBoardItemLayer() ); + NeedRIGHT(); + break; + + case T_hide: + text->SetVisible( false ); + break; + + case T_effects: + parseEDA_TEXT( (EDA_TEXT*) text.get() ); + break; + + default: + Expecting( "hide or effects" ); + } + } + + return text.release(); +} + + +EDGE_MODULE* PCB_PARSER::parseEDGE_MODULE() throw( IO_ERROR, PARSE_ERROR ) +{ + wxCHECK_MSG( CurTok() == T_fp_arc || CurTok() == T_fp_circle || CurTok() == T_fp_curve || + CurTok() == T_fp_line || CurTok() == T_fp_poly, NULL, + wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as EDGE_MODULE." ) ); + + T token; + + auto_ptr< EDGE_MODULE > segment( new EDGE_MODULE( NULL ) ); + + switch( CurTok() ) + { + case T_fp_arc: + segment->SetShape( S_ARC ); + NeedLEFT(); + token = NextTok(); + + if( token != T_start ) + Expecting( T_start ); + + segment->SetStart0( parseXY() ); + NeedRIGHT(); + token = NextTok(); + + if( token != T_end ) + Expecting( T_end ); + + segment->SetEnd0( parseXY() ); + NeedRIGHT(); + token = NextTok(); + + if( token != T_angle ) + Expecting( T_angle ); + + segment->SetAngle( parseDouble( "segment angle" ) ); + NeedRIGHT(); + break; + + case T_fp_circle: + segment->SetShape( S_CIRCLE ); + NeedLEFT(); + token = NextTok(); + + if( token != T_center ) + Expecting( T_center ); + + segment->SetStart0( parseXY() ); + NeedRIGHT(); + NeedLEFT(); + token = NextTok(); + + if( token != T_end ) + Expecting( T_end ); + + segment->SetEnd0( parseXY() ); + NeedRIGHT(); + break; + + case T_fp_curve: + segment->SetShape( S_CURVE ); + NeedLEFT(); + token = NextTok(); + + if( token != T_pts ) + Expecting( T_pts ); + + segment->SetStart0( parseXY() ); + segment->SetBezControl1( parseXY() ); + segment->SetBezControl2( parseXY() ); + segment->SetEnd0( parseXY() ); + NeedRIGHT(); + break; + + case T_fp_line: + // Default DRAWSEGMENT type is S_SEGMENT. + NeedLEFT(); + token = NextTok(); + + if( token != T_pts ) + Expecting( T_pts ); + + segment->SetStart0( parseXY() ); + segment->SetEnd0( parseXY() ); + NeedRIGHT(); + break; + + case T_fp_poly: + { + segment->SetShape( S_POLYGON ); + NeedLEFT(); + token = NextTok(); + + if( token != T_pts ) + Expecting( T_pts ); + + std::vector< wxPoint > pts; + + while( (token = NextTok()) != T_RIGHT ) + pts.push_back( parseXY() ); + + segment->SetPolyPoints( pts ); + } + break; + + default: + Expecting( "fp_arc, fp_circle, fp_curve, fp_line, or fp_poly" ); + } + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + if( token != T_LEFT ) + Expecting( T_LEFT ); + + token = NextTok(); + + switch( token ) + { + case T_layer: + segment->SetLayer( parseBoardItemLayer() ); + break; + + case T_width: + segment->SetWidth( parseBoardUnits( T_width ) ); + break; + + case T_tstamp: + segment->SetTimeStamp( parseHex() ); + break; + + case T_status: + segment->SetStatus( parseHex() ); + break; + + default: + Expecting( "layer, width, tstamp, or status" ); + } + + NeedRIGHT(); + } + + return segment.release(); +} + + +D_PAD* PCB_PARSER::parseD_PAD() throw( IO_ERROR, PARSE_ERROR ) +{ + wxCHECK_MSG( CurTok() == T_pad, NULL, + wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as D_PAD." ) ); + + wxSize sz; + wxPoint pt; + auto_ptr< D_PAD > pad( new D_PAD( NULL ) ); + + NeedSYMBOLorNUMBER(); + pad->SetPadName( FromUTF8() ); + + T token = NextTok(); + + switch( token ) + { + case T_thru_hole: + pad->SetAttribute( PAD_STANDARD ); + break; + + case T_smd: + pad->SetAttribute( PAD_SMD ); + break; + + case T_connect: + pad->SetAttribute( PAD_CONN ); + break; + + case T_np_thru_hole: + pad->SetAttribute( PAD_HOLE_NOT_PLATED ); + break; + + default: + Expecting( "thru_hole, smd, connect, or np_thru_hole" ); + } + + token = NextTok(); + + switch( token ) + { + case T_circle: + pad->SetShape( PAD_CIRCLE ); + break; + + case T_rectangle: + pad->SetShape( PAD_RECT ); + break; + + case T_oval: + pad->SetShape( PAD_OVAL ); + break; + + case T_trapezoid: + pad->SetShape( PAD_TRAPEZOID ); + break; + + default: + Expecting( "circle, rectangle, oval, or trapezoid" ); + } + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + if( token != T_LEFT ) + Expecting( T_LEFT ); + + token = NextTok(); + + switch( token ) + { + case T_size: + sz.SetWidth( parseBoardUnits( "width value" ) ); + sz.SetHeight( parseBoardUnits( "height value" ) ); + pad->SetSize( sz ); + NeedRIGHT(); + break; + + case T_at: + pt.x = parseBoardUnits( "X coordinate" ); + pt.y = parseBoardUnits( "Y coordinate" ); + pad->SetPos0( pt ); + token = NextTok(); + + if( token == T_NUMBER ) + { + pad->SetOrientation( parseDouble() * 10.0 ); + NeedRIGHT(); + } + else if( token != T_RIGHT ) + { + Expecting( ") or angle value" ); + } + + break; + + case T_drill: + sz.SetWidth( parseBoardUnits( "drill size" ) ); + sz.SetHeight( 0 ); + token = NextTok(); + + if( token == T_NUMBER ) + { + sz.SetHeight( parseBoardUnits() ); + token = NextTok(); + + if( token == T_LEFT ) + { + token = NextTok(); + + if( token != T_offset ) + Expecting( T_offset ); + + pt.x = parseDouble( "drill offset X" ); + pt.y = 0; + token = NextTok(); + + if( token == T_NUMBER ) + { + pt.y = parseDouble(); + NeedRIGHT(); + } + else if( token != T_RIGHT ) + { + Expecting( T_RIGHT ); + } + + pad->SetOffset( pt ); + } + else if( token != T_RIGHT ) + { + Expecting( T_RIGHT ); + } + + pad->SetDrillSize( sz ); + } + else if( token != T_RIGHT ) + { + Expecting( T_RIGHT ); + } + + break; + + case T_layers: + { + int layerMask = parseBoardItemLayersAsMask(); + + // Only the layers that are used are saved so we need to enable all the copper + // layers to prevent any problems with the current design. At some point in + // the future, the layer handling should be improved. + if( pad->GetAttribute() == PAD_STANDARD ) + layerMask |= ALL_CU_LAYERS; + + pad->SetLayerMask( layerMask ); + break; + } + + case T_net: + pad->SetNet( parseInt( "net number" ) ); + NeedSYMBOL(); + pad->SetNetname( FromUTF8() ); + NeedRIGHT(); + break; + + case T_die_length: + pad->SetDieLength( parseBoardUnits( T_die_length ) ); + NeedRIGHT(); + break; + + case T_solder_mask_margin: + pad->SetLocalSolderMaskMargin( parseBoardUnits( T_solder_mask_margin ) ); + NeedRIGHT(); + break; + + case T_solder_paste_margin: + pad->SetLocalSolderPasteMargin( parseBoardUnits( T_solder_paste_margin ) ); + NeedRIGHT(); + break; + + case T_solder_paste_margin_ratio: + pad->SetLocalSolderPasteMarginRatio( parseBoardUnits( T_solder_paste_margin_ratio ) ); + NeedRIGHT(); + break; + + case T_clearance: + pad->SetLocalClearance( parseBoardUnits( "local clearance value" ) ); + NeedRIGHT(); + break; + + case T_zone_connect: + pad->SetZoneConnection( (ZoneConnection) parseInt( "zone connection value" ) ); + NeedRIGHT(); + break; + + case T_thermal_width: + pad->SetThermalWidth( parseBoardUnits( T_thermal_width ) ); + NeedRIGHT(); + break; + + case T_thermal_gap: + pad->SetThermalGap( parseBoardUnits( T_thermal_gap ) ); + NeedRIGHT(); + break; + + default: + Expecting( "at, drill, layers, net, die_length, solder_mask_margin, " + "solder_paste_margin, solder_paste_margin_ratio, clearance, " + "zone_connect, thermal_width, or thermal_gap" ); + } + } + + return pad.release(); +} + + +TRACK* PCB_PARSER::parseTRACK() throw( IO_ERROR, PARSE_ERROR ) +{ + wxCHECK_MSG( CurTok() == T_segment, NULL, + wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as TRACK." ) ); + + wxPoint pt; + T token; + + auto_ptr< TRACK > track( new TRACK( m_board ) ); + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + if( token != T_LEFT ) + Expecting( T_LEFT ); + + token = NextTok(); + + switch( token ) + { + case T_start: + pt.x = parseBoardUnits( "start x" ); + pt.y = parseBoardUnits( "start y" ); + track->SetStart( pt ); + break; + + case T_end: + pt.x = parseBoardUnits( "end x" ); + pt.y = parseBoardUnits( "end y" ); + track->SetEnd( pt ); + break; + + case T_width: + track->SetWidth( parseBoardUnits( "width" ) ); + break; + + case T_layer: + track->SetLayer( parseBoardItemLayer() ); + break; + + case T_net: + track->SetNet( parseInt( "net number" ) ); + break; + + case T_tstamp: + track->SetTimeStamp( parseHex() ); + break; + + case T_status: + track->SetStatus( parseHex() ); + break; + + default: + Expecting( "start, end, width, layer, net, tstamp, or status" ); + } + + NeedRIGHT(); + } + + return track.release(); +} + + +SEGVIA* PCB_PARSER::parseSEGVIA() throw( IO_ERROR, PARSE_ERROR ) +{ + wxCHECK_MSG( CurTok() == T_via, NULL, + wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as SEGVIA." ) ); + + wxPoint pt; + T token; + + auto_ptr< SEGVIA > via( new SEGVIA( m_board ) ); + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + if( token == T_LEFT ) + token = NextTok(); + + switch( token ) + { + case T_thru: + via->SetShape( VIA_THROUGH ); + break; + + case T_blind: + via->SetShape( VIA_BLIND_BURIED ); + break; + + case T_micro: + via->SetShape( VIA_MICROVIA ); + break; + + case T_at: + pt.x = parseBoardUnits( "start x" ); + pt.y = parseBoardUnits( "start y" ); + via->SetStart( pt ); + NeedRIGHT(); + break; + + case T_size: + via->SetWidth( parseBoardUnits( "via width" ) ); + NeedRIGHT(); + break; + + case T_drill: + via->SetDrill( parseBoardUnits( "drill diameter" ) ); + NeedRIGHT(); + break; + + case T_layers: + { + int layer1, layer2; + NextTok(); + layer1 = lookUpLayer(); + NextTok(); + layer2 = lookUpLayer(); + via->SetLayerPair( layer1, layer2 ); + NeedRIGHT(); + } + break; + + case T_net: + via->SetNet( parseInt( "net number" ) ); + NeedRIGHT(); + break; + + case T_tstamp: + via->SetTimeStamp( parseHex() ); + NeedRIGHT(); + break; + + case T_status: + via->SetStatus( parseHex() ); + NeedRIGHT(); + break; + + default: + Expecting( "at, size, drill, layers, net, tstamp, or status" ); + } + } + + return via.release(); +} + + +ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER() throw( IO_ERROR, PARSE_ERROR ) +{ + wxCHECK_MSG( CurTok() == T_zone, NULL, + wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + + wxT( " as ZONE_CONTAINER." ) ); + + int hatchStyle; + int hatchPitch; + wxPoint pt; + T token; + + // bigger scope since each filled_polygon is concatonated in here + std::vector< CPolyPt > pts; + + auto_ptr< ZONE_CONTAINER > zone( new ZONE_CONTAINER( m_board ) ); + + zone->SetPriority( 0 ); + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + if( token == T_LEFT ) + token = NextTok(); + + switch( token ) + { + case T_net: + zone->SetNet( parseInt( "net number" ) ); + NeedRIGHT(); + break; + + case T_net_name: + NeedSYMBOL(); + zone->SetNetName( FromUTF8() ); + NeedRIGHT(); + break; + + case T_layer: + zone->SetLayer( parseBoardItemLayer() ); + NeedRIGHT(); + break; + + case T_tstamp: + zone->SetTimeStamp( parseHex() ); + NeedRIGHT(); + break; + + case T_hatch: + token = NextTok(); + + if( token != T_none && token != T_edge && token != T_full ) + Expecting( "none, edge, or full" ); + + switch( token ) + { + default: + case T_none: hatchStyle = CPolyLine::NO_HATCH; break; + case T_edge: hatchStyle = CPolyLine::DIAGONAL_EDGE; break; + case T_full: hatchStyle = CPolyLine::DIAGONAL_FULL; + } + + hatchPitch = parseBoardUnits( "hatch pitch" ); + NeedRIGHT(); + break; + + case T_priority: + zone->SetPriority( parseInt( "zone priority" ) ); + NeedRIGHT(); + break; + + case T_connect_pads: + token = NextTok(); + + switch( token ) + { + case T_yes: zone->SetPadConnection( PAD_IN_ZONE ); break; + case T_use_thermal: zone->SetPadConnection( THERMAL_PAD ); break; + case T_no: zone->SetPadConnection( PAD_NOT_IN_ZONE ); break; + default: Expecting( "yes, no, or use_thermal" ); + } + + NeedLEFT(); + token = NextTok(); + + if( token != T_clearance ) + Expecting( T_clearance ); + + zone->SetZoneClearance( parseBoardUnits( "zone clearance" ) ); + NeedRIGHT(); + NeedRIGHT(); + break; + + case T_min_thickness: + zone->SetMinThickness( parseBoardUnits( T_min_thickness ) ); + NeedRIGHT(); + break; + + case T_fill: + token = NextTok(); + + if( token != T_yes && token != T_no ) + Expecting( "yes or no" ); + + zone->SetIsFilled( token == T_yes ); + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + if( token != T_LEFT ) + Expecting( T_LEFT ); + + token = NextTok(); + + switch( token ) + { + case T_mode: + token = NextTok(); + + if( token != T_segment && token != T_polygon ) + Expecting( "segment or polygon" ); + + // @todo Create an enum for fill modes. + zone->SetFillMode( token == T_polygon ? 0 : 1 ); + break; + + case T_arc_segments: + zone->SetArcSegCount( parseInt( "arc segment count" ) ); + break; + + case T_thermal_gap: + zone->SetThermalReliefGap( parseBoardUnits( T_thermal_gap ) ); + break; + + case T_thermal_bridge_width: + zone->SetThermalReliefCopperBridge( parseBoardUnits( T_thermal_bridge_width ) ); + break; + + case T_smoothing: + switch( NextTok() ) + { + case T_none: + zone->SetCornerSmoothingType( ZONE_SETTINGS::SMOOTHING_NONE ); + break; + + case T_chamfer: + zone->SetCornerSmoothingType( ZONE_SETTINGS::SMOOTHING_CHAMFER ); + break; + + case T_fillet: + zone->SetCornerSmoothingType( ZONE_SETTINGS::SMOOTHING_FILLET ); + break; + + default: + Expecting( "none, chamfer, or fillet" ); + } + + break; + + case T_radius: + zone->SetCornerRadius( parseBoardUnits( "corner radius" ) ); + break; + + default: + Expecting( "mode, arc_segments, thermal_gap, thermal_bridge_width, " + "smoothing, or radius" ); + } + + NeedRIGHT(); + } + + break; + + case T_polygon: + { + std::vector< wxPoint > corners; + + NeedLEFT(); + token = NextTok(); + + if( token != T_pts ) + Expecting( T_pts ); + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + corners.push_back( parseXY() ); + } + + NeedRIGHT(); + zone->AddPolygon( corners ); + } + + break; + + case T_filled_polygon: + { + // "(filled_polygon (pts" + NeedLEFT(); + token = NextTok(); + + if( token != T_pts ) + Expecting( T_pts ); + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + pts.push_back( CPolyPt( parseXY() ) ); + } + + NeedRIGHT(); + pts.back().end_contour = true; + } + + break; + + case T_fill_segments: + { + std::vector< SEGMENT > segs; + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + if( token != T_LEFT ) + Expecting( T_LEFT ); + + token = NextTok(); + + if( token != T_pts ) + Expecting( T_pts ); + + SEGMENT segment( parseXY(), parseXY() ); + NeedRIGHT(); + segs.push_back( segment ); + } + + zone->AddFillSegments( segs ); + } + + break; + + default: + Expecting( "net, layer, tstamp, hatch, priority, connect_pads, min_thickness, " + "fill, polygon, filled_polygon, or fill_segments" ); + } + } + + if( zone->GetNumCorners() > 2 ) + { + if( !zone->IsOnCopperLayer() ) + { + zone->SetFillMode( 0 ); + zone->SetNet( 0 ); + } + + // Set hatch here, after outlines corners are read + zone->m_Poly->SetHatch( hatchStyle, hatchPitch ); + } + + if( pts.size() ) + zone->AddFilledPolysList( pts ); + + return zone.release(); +} + + +PCB_TARGET* PCB_PARSER::parsePCB_TARGET() throw( IO_ERROR, PARSE_ERROR ) +{ + wxCHECK_MSG( CurTok() == T_target, NULL, + wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PCB_TARGET." ) ); + + wxPoint pt; + T token; + + auto_ptr< PCB_TARGET > target( new PCB_TARGET( NULL ) ); + + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + if( token == T_LEFT ) + token = NextTok(); + + switch( token ) + { + case T_x: + target->SetShape( 1 ); + break; + + case T_plus: + target->SetShape( 0 ); + break; + + case T_at: + pt.x = parseBoardUnits( "target x position" ); + pt.y = parseBoardUnits( "target y position" ); + target->SetPosition( pt ); + NeedRIGHT(); + break; + + case T_size: + target->SetSize( parseBoardUnits( "target size" ) ); + NeedRIGHT(); + break; + + case T_width: + target->SetWidth( parseBoardUnits( "target thickness" ) ); + NeedRIGHT(); + break; + + case T_tstamp: + target->SetTimeStamp( parseHex() ); + NeedRIGHT(); + break; + + default: + Expecting( "x, plus, at, size, width, or tstamp" ); + } + } + + return target.release(); +} + diff --git a/pcbnew/pcb_parser.h b/pcbnew/pcb_parser.h index 45252bee9f..20d214ba42 100644 --- a/pcbnew/pcb_parser.h +++ b/pcbnew/pcb_parser.h @@ -1,214 +1,216 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2012 CERN - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you may find one here: - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * or you may search the http://www.gnu.org website for the version 2 license, - * or you may write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -/** - * @file pcb_parser.h - * @brief Pcbnew s-expression file format parser definition. - */ - -#ifndef _PCBNEW_PARSER_H_ -#define _PCBNEW_PARSER_H_ - -#include - -#include - - -using namespace PCB; - - -class BOARD; -class BOARD_ITEM; -class D_PAD; -class EDGE_MODULE; -class TEXTE_MODULE; -class TEXTE_PCB; -class MODULE; -class PCB_TARGET; -class S3D_MASTER; -class ZONE_CONTAINER; - - -WX_DECLARE_STRING_HASH_MAP( int, LAYER_HASH_MAP ); - - -#define USE_LAYER_NAMES 1 // Set to 0 to format and parse layers by index number. - - -/** - * Class PCB_PARSER - * reads a Pcbnew s-expression fromatted #LINE_READER object and returns the appropriate - * #BOARD_ITEM object. - */ -class PCB_PARSER : public PCB_LEXER -{ - BOARD* m_board; - LAYER_HASH_MAP m_layerMap; //< Map layer name to it's index saved in BOARD::m_Layer. - - void parseHeader() throw( IO_ERROR, PARSE_ERROR ); - void parseGeneralSection() throw( IO_ERROR, PARSE_ERROR ); - void parsePAGE_INFO() throw( IO_ERROR, PARSE_ERROR ); - void parseTITLE_BLOCK() throw( IO_ERROR, PARSE_ERROR ); - void parseLayers() throw( IO_ERROR, PARSE_ERROR ); - void parseSetup() throw( IO_ERROR, PARSE_ERROR ); - void parseNETINFO_ITEM() throw( IO_ERROR, PARSE_ERROR ); - void parseNETCLASS() throw( IO_ERROR, PARSE_ERROR ); - void parseDRAWSEGMENT() throw( IO_ERROR, PARSE_ERROR ); - void parseTEXTE_PCB( TEXTE_PCB* aText = NULL ) throw( IO_ERROR, PARSE_ERROR ); - void parseDIMENSION() throw( IO_ERROR, PARSE_ERROR ); - void parseMODULE() throw( IO_ERROR, PARSE_ERROR ); - TEXTE_MODULE* parseTEXTE_MODULE() throw( IO_ERROR, PARSE_ERROR ); - EDGE_MODULE* parseEDGE_MODULE() throw( IO_ERROR, PARSE_ERROR ); - D_PAD* parseD_PAD() throw( IO_ERROR, PARSE_ERROR ); - TRACK* parseTRACK() throw( IO_ERROR, PARSE_ERROR ); - SEGVIA* parseSEGVIA() throw( IO_ERROR, PARSE_ERROR ); - ZONE_CONTAINER* parseZONE_CONTAINER() throw( IO_ERROR, PARSE_ERROR ); - PCB_TARGET* parsePCB_TARGET() throw( IO_ERROR, PARSE_ERROR ); - BOARD* parseBOARD() throw( IO_ERROR, PARSE_ERROR ); - - - /** - * Function lookUpLayer - * parses the current token for the layer definition of a #BOARD_ITEM object. - * - * @throw IO_ERROR if the layer is not valid. - * @throw PARSE_ERROR if the layer syntax is incorrect. - * @return The index the parsed #BOARD_ITEM layer. - */ - int lookUpLayer() throw( PARSE_ERROR, IO_ERROR ); - - /** - * Function parseBoardItemLayer - * parses the layer definition of a #BOARD_ITEM object. - * - * @throw IO_ERROR if the layer is not valid. - * @throw PARSE_ERROR if the layer syntax is incorrect. - * @return The index the parsed #BOARD_ITEM layer. - */ - int parseBoardItemLayer() throw( IO_ERROR, PARSE_ERROR ); - - /** - * Function parseBoardItemLayersAsMask - * parses the layers definition of a #BOARD_ITEM object. - * - * @throw IO_ERROR if any of the layers is not valid. - * @throw PARSE_ERROR if the layers syntax is incorrect. - * @return The mask of layers the parsed #BOARD_ITEM is on. - */ - int parseBoardItemLayersAsMask() throw( PARSE_ERROR, IO_ERROR ); - - /** - * Function parseXY - * parses 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 coorinate points. This - * way the parser can be used in either case. - * - * @throw PARSE_ERROR if the coordinate pair syntax is incorrect. - * @return A wxPoint object containing the coordinate pair. - */ - wxPoint parseXY() throw( PARSE_ERROR ); - - void parseXY( int* aX, int* aY ) throw( PARSE_ERROR ); - - /** - * Function parseEDA_TEXT - * parses the common settings for any object derived from #EDA_TEXT. - * - * @throw PARSE_ERROR if the text syntax is not valid. - * @param aText A point to the #EDA_TEXT object to save the parsed settings into. - */ - void parseEDA_TEXT( EDA_TEXT* aText ) throw( PARSE_ERROR ); - - S3D_MASTER* parse3DModel() throw( PARSE_ERROR ); - - /** - * Function parseDouble - * parses the current token as an ASCII numeric string with possible leading whitespace into - * a double precision floating point number. - * - * @throw IO_ERROR if an error occurs attempting to convert the current token. - * @return The result of the parsed token. - */ - double parseDouble() throw( IO_ERROR ); - - inline double parseDouble( const char* aExpected ) throw( IO_ERROR ) - { - NeedNUMBER( aExpected ); - return parseDouble(); - } - - inline double parseDouble( T aToken ) throw( IO_ERROR ) - { - return parseDouble( GetTokenText( aToken ) ); - } - - inline int parseBoardUnits() throw( IO_ERROR ) - { - // There should be no rounding issues here, since the values in the file are in mm - // and get converted to nano-meters. This product should be an integer, exactly. - return int( parseDouble() * 1e6 ); - } - - inline int parseBoardUnits( const char* aExpected ) throw( PARSE_ERROR ) - { - return KIROUND( parseDouble( aExpected ) * 1e6 ); - } - - inline int parseBoardUnits( T aToken ) throw( PARSE_ERROR ) - { - return parseBoardUnits( GetTokenText( aToken ) ); - } - - inline int parseInt() throw( PARSE_ERROR ) - { - return (int)strtol( CurText(), NULL, 10 ); - } - - inline int parseInt( const char* aExpected ) throw( PARSE_ERROR ) - { - NeedNUMBER( aExpected ); - return parseInt(); - } - - inline int parseHex() throw( PARSE_ERROR ) - { - NeedSYMBOLorNUMBER(); - return (int)strtol( CurText(), NULL, 16 ); - } - - bool parseBool() throw( PARSE_ERROR ); - -public: - PCB_PARSER( LINE_READER* aReader, BOARD* aBoard = NULL ) : - PCB_LEXER( aReader ), - m_board( aBoard ) - { - } - - BOARD_ITEM* Parse() throw( IO_ERROR, PARSE_ERROR ); -}; - - -#endif // _PCBNEW_PARSER_H_ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2012 CERN + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * @file pcb_parser.h + * @brief Pcbnew s-expression file format parser definition. + */ + +#ifndef _PCBNEW_PARSER_H_ +#define _PCBNEW_PARSER_H_ + +#include + +#include + + +using namespace PCB; + + +class BOARD; +class BOARD_ITEM; +class D_PAD; +class DIMENSION; +class DRAWSEGMENT; +class EDGE_MODULE; +class TEXTE_MODULE; +class TEXTE_PCB; +class MODULE; +class PCB_TARGET; +class S3D_MASTER; +class ZONE_CONTAINER; + + +WX_DECLARE_STRING_HASH_MAP( int, LAYER_HASH_MAP ); + + +#define USE_LAYER_NAMES 1 // Set to 0 to format and parse layers by index number. + + +/** + * Class PCB_PARSER + * reads a Pcbnew s-expression fromatted #LINE_READER object and returns the appropriate + * #BOARD_ITEM object. + */ +class PCB_PARSER : public PCB_LEXER +{ + BOARD* m_board; + LAYER_HASH_MAP m_layerMap; //< Map layer name to it's index saved in BOARD::m_Layer. + + void parseHeader() throw( IO_ERROR, PARSE_ERROR ); + void parseGeneralSection() throw( IO_ERROR, PARSE_ERROR ); + void parsePAGE_INFO() throw( IO_ERROR, PARSE_ERROR ); + void parseTITLE_BLOCK() throw( IO_ERROR, PARSE_ERROR ); + void parseLayers() throw( IO_ERROR, PARSE_ERROR ); + void parseSetup() throw( IO_ERROR, PARSE_ERROR ); + void parseNETINFO_ITEM() throw( IO_ERROR, PARSE_ERROR ); + void parseNETCLASS() throw( IO_ERROR, PARSE_ERROR ); + DRAWSEGMENT* parseDRAWSEGMENT() throw( IO_ERROR, PARSE_ERROR ); + TEXTE_PCB* parseTEXTE_PCB() throw( IO_ERROR, PARSE_ERROR ); + DIMENSION* parseDIMENSION() throw( IO_ERROR, PARSE_ERROR ); + MODULE* parseMODULE() throw( IO_ERROR, PARSE_ERROR ); + TEXTE_MODULE* parseTEXTE_MODULE() throw( IO_ERROR, PARSE_ERROR ); + EDGE_MODULE* parseEDGE_MODULE() throw( IO_ERROR, PARSE_ERROR ); + D_PAD* parseD_PAD() throw( IO_ERROR, PARSE_ERROR ); + TRACK* parseTRACK() throw( IO_ERROR, PARSE_ERROR ); + SEGVIA* parseSEGVIA() throw( IO_ERROR, PARSE_ERROR ); + ZONE_CONTAINER* parseZONE_CONTAINER() throw( IO_ERROR, PARSE_ERROR ); + PCB_TARGET* parsePCB_TARGET() throw( IO_ERROR, PARSE_ERROR ); + BOARD* parseBOARD() throw( IO_ERROR, PARSE_ERROR ); + + + /** + * Function lookUpLayer + * parses the current token for the layer definition of a #BOARD_ITEM object. + * + * @throw IO_ERROR if the layer is not valid. + * @throw PARSE_ERROR if the layer syntax is incorrect. + * @return The index the parsed #BOARD_ITEM layer. + */ + int lookUpLayer() throw( PARSE_ERROR, IO_ERROR ); + + /** + * Function parseBoardItemLayer + * parses the layer definition of a #BOARD_ITEM object. + * + * @throw IO_ERROR if the layer is not valid. + * @throw PARSE_ERROR if the layer syntax is incorrect. + * @return The index the parsed #BOARD_ITEM layer. + */ + int parseBoardItemLayer() throw( IO_ERROR, PARSE_ERROR ); + + /** + * Function parseBoardItemLayersAsMask + * parses the layers definition of a #BOARD_ITEM object. + * + * @throw IO_ERROR if any of the layers is not valid. + * @throw PARSE_ERROR if the layers syntax is incorrect. + * @return The mask of layers the parsed #BOARD_ITEM is on. + */ + int parseBoardItemLayersAsMask() throw( PARSE_ERROR, IO_ERROR ); + + /** + * Function parseXY + * parses 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 coorinate points. This + * way the parser can be used in either case. + * + * @throw PARSE_ERROR if the coordinate pair syntax is incorrect. + * @return A wxPoint object containing the coordinate pair. + */ + wxPoint parseXY() throw( PARSE_ERROR ); + + void parseXY( int* aX, int* aY ) throw( PARSE_ERROR ); + + /** + * Function parseEDA_TEXT + * parses the common settings for any object derived from #EDA_TEXT. + * + * @throw PARSE_ERROR if the text syntax is not valid. + * @param aText A point to the #EDA_TEXT object to save the parsed settings into. + */ + void parseEDA_TEXT( EDA_TEXT* aText ) throw( PARSE_ERROR ); + + S3D_MASTER* parse3DModel() throw( PARSE_ERROR ); + + /** + * Function parseDouble + * parses the current token as an ASCII numeric string with possible leading whitespace into + * a double precision floating point number. + * + * @throw IO_ERROR if an error occurs attempting to convert the current token. + * @return The result of the parsed token. + */ + double parseDouble() throw( IO_ERROR ); + + inline double parseDouble( const char* aExpected ) throw( IO_ERROR ) + { + NeedNUMBER( aExpected ); + return parseDouble(); + } + + inline double parseDouble( T aToken ) throw( IO_ERROR ) + { + return parseDouble( GetTokenText( aToken ) ); + } + + inline int parseBoardUnits() throw( IO_ERROR ) + { + // There should be no rounding issues here, since the values in the file are in mm + // and get converted to nano-meters. This product should be an integer, exactly. + return int( parseDouble() * IU_PER_MM ); + } + + inline int parseBoardUnits( const char* aExpected ) throw( PARSE_ERROR ) + { + return KIROUND( parseDouble( aExpected ) * IU_PER_MM ); + } + + inline int parseBoardUnits( T aToken ) throw( PARSE_ERROR ) + { + return parseBoardUnits( GetTokenText( aToken ) ); + } + + inline int parseInt() throw( PARSE_ERROR ) + { + return (int)strtol( CurText(), NULL, 10 ); + } + + inline int parseInt( const char* aExpected ) throw( PARSE_ERROR ) + { + NeedNUMBER( aExpected ); + return parseInt(); + } + + inline int parseHex() throw( PARSE_ERROR ) + { + NeedSYMBOLorNUMBER(); + return (int)strtol( CurText(), NULL, 16 ); + } + + bool parseBool() throw( PARSE_ERROR ); + +public: + PCB_PARSER( LINE_READER* aReader, BOARD* aBoard = NULL ) : + PCB_LEXER( aReader ), + m_board( aBoard ) + { + } + + BOARD_ITEM* Parse() throw( IO_ERROR, PARSE_ERROR ); +}; + + +#endif // _PCBNEW_PARSER_H_ diff --git a/pcbnew/pcb_plot_params.cpp b/pcbnew/pcb_plot_params.cpp index c3b5fec2d8..cebe330847 100644 --- a/pcbnew/pcb_plot_params.cpp +++ b/pcbnew/pcb_plot_params.cpp @@ -120,7 +120,7 @@ void PCB_PLOT_PARAMS::Format( OUTPUTFORMATTER* aFormatter, const char* falseStr = getTokenName( T_false ); const char* trueStr = getTokenName( T_true ); - aFormatter->Print( aNestLevel, "(%s", getTokenName( T_pcbplotparams ) ); + aFormatter->Print( aNestLevel, "(%s\n", getTokenName( T_pcbplotparams ) ); aFormatter->Print( aNestLevel+1, "(%s %ld)\n", getTokenName( T_layerselection ), layerSelection ); aFormatter->Print( aNestLevel+1, "(%s %s)\n", getTokenName( T_usegerberextensions ), @@ -173,7 +173,7 @@ void PCB_PLOT_PARAMS::Format( OUTPUTFORMATTER* aFormatter, scaleSelection ); aFormatter->Print( aNestLevel+1, "(%s %s)\n", getTokenName( T_outputdirectory ), aFormatter->Quotew( outputDirectory ).c_str() ); - aFormatter->Print( 0, ")\n" ); + aFormatter->Print( aNestLevel, ")\n" ); }