From 9204086f41df57fdf3590545a9a5c840006732d1 Mon Sep 17 00:00:00 2001 From: Wayne Stambaugh Date: Sat, 9 Jun 2012 13:00:13 -0400 Subject: [PATCH] Add Pcbnew s-expression file parser. * Add s-expression file parser object and keyword files. * Fix minor issues with s-expression file formatting. * Fix a minor bug the zone container fill state parsing in the legacy plugin. * Move EDA_TEXT visibility definition to eda_text.h. * Add minor BOARD_ITEM object improvements to support s-expression file parser. --- .bzrignore | 2 + 3d-viewer/3d_draw.cpp | 2 +- common/CMakeLists.txt | 10 + common/eda_text.cpp | 6 +- common/pcb.keywords | 195 ++ common/worksheet.cpp | 24 +- eeschema/general.h | 2 - include/class_board_design_settings.h | 5 +- include/eda_text.h | 12 + include/layers_id_colors_and_visibility.h | 1 + kicad/tree_project_frame.cpp | 5 +- pcbnew/class_board.cpp | 67 +- pcbnew/class_board.h | 43 +- pcbnew/class_board_design_settings.cpp | 4 +- pcbnew/class_board_item.cpp | 24 +- pcbnew/class_dimension.h | 1 + pcbnew/class_module.cpp | 14 + pcbnew/class_module.h | 16 + pcbnew/class_zone.cpp | 18 + pcbnew/class_zone.h | 17 + pcbnew/export_vrml.cpp | 2 +- pcbnew/kicad_plugin.cpp | 2125 +++++++++--------- pcbnew/kicad_plugin.h | 286 +-- pcbnew/legacy_plugin.cpp | 6 +- pcbnew/pcb_parser.cpp | 2499 +++++++++++++++++++++ pcbnew/pcb_parser.h | 214 ++ 26 files changed, 4399 insertions(+), 1201 deletions(-) create mode 100644 common/pcb.keywords create mode 100644 pcbnew/pcb_parser.cpp create mode 100644 pcbnew/pcb_parser.h diff --git a/.bzrignore b/.bzrignore index c981d28c7f..9ec42d51e5 100644 --- a/.bzrignore +++ b/.bzrignore @@ -30,3 +30,5 @@ new/sweet_keywords.cpp new/sweet_lexer.h bitmaps_png/png* bitmaps_png/tmp +common/pcb_keywords.cpp +include/pcb_lexer.h diff --git a/3d-viewer/3d_draw.cpp b/3d-viewer/3d_draw.cpp index 422b4822f9..0c0a6b05d8 100644 --- a/3d-viewer/3d_draw.cpp +++ b/3d-viewer/3d_draw.cpp @@ -177,7 +177,7 @@ GLuint EDA_3D_CANVAS::CreateDrawGL_List() // because all boards thickness no not match with this setup: // double epoxy_width = 1.6; // epoxy width in mm - g_Parm_3D_Visu.m_Epoxy_Width = pcb->GetDesignSettings().m_BoardThickness + g_Parm_3D_Visu.m_Epoxy_Width = pcb->GetDesignSettings().GetBoardThickness() * g_Parm_3D_Visu.m_BoardScale; // calculate z position for each layer diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index aa5520740c..e0fc9eef79 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -121,6 +121,8 @@ set(PCB_COMMON_SRCS ../pcbnew/legacy_plugin.cpp ../pcbnew/kicad_plugin.cpp pcb_plot_params_keywords.cpp + pcb_keywords.cpp + ../pcbnew/pcb_parser.cpp ) @@ -148,6 +150,14 @@ make_lexer( PCBPLOTPARAMS_T ) +# auto-generate pcbnew_sexpr.h and pcbnew_sexpr.cpp +make_lexer( ${CMAKE_CURRENT_SOURCE_DIR}/pcb.keywords + ${PROJECT_SOURCE_DIR}/include/pcb_lexer.h + ${CMAKE_CURRENT_SOURCE_DIR}/pcb_keywords.cpp + PCB + ) + + # The dsntest may not build properly using MS Visual Studio. if(NOT MSVC) # This one gets made only when testing. diff --git a/common/eda_text.cpp b/common/eda_text.cpp index 6cbae0800f..b1073f847e 100644 --- a/common/eda_text.cpp +++ b/common/eda_text.cpp @@ -354,7 +354,11 @@ void EDA_TEXT::Format( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aControl // 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)", FMT_IU( m_Size ).c_str() ); + 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" ); diff --git a/common/pcb.keywords b/common/pcb.keywords new file mode 100644 index 0000000000..1896b02039 --- /dev/null +++ b/common/pcb.keywords @@ -0,0 +1,195 @@ +# +# 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 +# + +# These are the keywords for the Pcbnew s-expression file format. + +add_net +angle +arc +arc_segments +area +arrow1a +arrow1b +arrow2a +arrow2b +at +attr +autoplace_cost90 +autoplace_cost180 +aux_axis_origin +blind +bold +bottom +center +chamfer +circle +clearance +comment +company +connect +connect_pads +crossbar +date +descr +die_length +dimension +drawings +drill +edge +edge_width +effects +end +feature1 +feature2 +fill +fill_segments +filled_polygon +fillet +font +fp_arc +fp_circle +fp_curve +fp_line +fp_poly +fp_text +full +general +gr_arc +gr_circle +gr_curve +gr_line +gr_poly +gr_text +hatch +hide +italic +justify +kicad_pcb +last_trace_width +layer +layers +left +links +locked +micro +min_thickness +mirror +mod_edge_width +mod_text_size +mod_text_width +mode +model +module +net +net_class +net_name +nets +no +no_connects +none +np_thru_hole +offset +oval +pad +pad_drill +pad_size +pad_to_mask_clearance +pad_to_paste_clearance +pad_to_paste_clearance_ratio +page +path +pcb_text_size +pcb_text_width +placed +plus +polygon +portrait +priority +pts +radius +rev +rectangle +reference +right +rotate +scale +segment +segment_width +setup +size +smd +smoothing +solder_mask_margin +solder_paste_margin +solder_paste_margin_ratio +solder_paste_ratio +start +status +tags +target +title +title_block +tedit +thermal_width +thermal_gap +thermal_bridge_width +thickness +top +trace_width +tracks +trace_min +trace_clearance +trapezoid +thru +thru_hole +tstamp +use_thermal +user +user_trace_width +user_via +uvia_dia +uvia_drill +uvia_min_drill +uvia_min_size +uvia_size +uvias_allowed +value +version +via +via_dia +via_drill +via_min_drill +via_min_size +via_size +virtual +visible_elements +width +x +xy +xyz +yes +zone +zone_45_only +zone_clearance +zone_connect +zones diff --git a/common/worksheet.cpp b/common/worksheet.cpp index 6d44ef801c..356bbb6740 100644 --- a/common/worksheet.cpp +++ b/common/worksheet.cpp @@ -1673,28 +1673,36 @@ void TITLE_BLOCK::Format( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aCont aFormatter->Print( aNestLevel, "(title_block\n" ); if( !m_title.IsEmpty() ) - aFormatter->Print( aNestLevel+1, "(title %s)\n", EscapedUTF8( m_title ).c_str() ); + aFormatter->Print( aNestLevel+1, "(title %s)\n", + aFormatter->Quotew( m_title ).c_str() ); if( !m_date.IsEmpty() ) - aFormatter->Print( aNestLevel+1, "(date %s)\n", EscapedUTF8( m_date ).c_str() ); + aFormatter->Print( aNestLevel+1, "(date %s)\n", + aFormatter->Quotew( m_date ).c_str() ); if( !m_revision.IsEmpty() ) - aFormatter->Print( aNestLevel+1, "(rev %s)\n", EscapedUTF8( m_revision ).c_str() ); + aFormatter->Print( aNestLevel+1, "(rev %s)\n", + aFormatter->Quotew( m_revision ).c_str() ); if( !m_company.IsEmpty() ) - aFormatter->Print( aNestLevel+1, "(company %s)\n", EscapedUTF8( m_company ).c_str() ); + aFormatter->Print( aNestLevel+1, "(company %s)\n", + aFormatter->Quotew( m_company ).c_str() ); if( !m_comment1.IsEmpty() ) - aFormatter->Print( aNestLevel+1, "(comment1 %s)\n", EscapedUTF8( m_comment1 ).c_str() ); + aFormatter->Print( aNestLevel+1, "(comment 1 %s)\n", + aFormatter->Quotew( m_comment1 ).c_str() ); if( !m_comment2.IsEmpty() ) - aFormatter->Print( aNestLevel+1, "(comment2 %s)\n", EscapedUTF8( m_comment2 ).c_str() ); + aFormatter->Print( aNestLevel+1, "(comment 2 %s)\n", + aFormatter->Quotew( m_comment2 ).c_str() ); if( !m_comment3.IsEmpty() ) - aFormatter->Print( aNestLevel+1, "(comment3 %s)\n", EscapedUTF8( m_comment3 ).c_str() ); + aFormatter->Print( aNestLevel+1, "(comment 3 %s)\n", + aFormatter->Quotew( m_comment3 ).c_str() ); if( !m_comment4.IsEmpty() ) - aFormatter->Print( aNestLevel+1, "(comment4 %s)\n", EscapedUTF8( m_comment4 ).c_str() ); + aFormatter->Print( aNestLevel+1, "(comment 4 %s)\n", + aFormatter->Quotew( m_comment4 ).c_str() ); aFormatter->Print( aNestLevel, ")\n\n" ); } diff --git a/eeschema/general.h b/eeschema/general.h index 826bc4c80b..40a3ec4e4c 100644 --- a/eeschema/general.h +++ b/eeschema/general.h @@ -33,8 +33,6 @@ class TRANSFORM; #define HIGHLIGHT_COLOR WHITE -#define TEXT_NO_VISIBLE 1 - //#define GR_DEFAULT_DRAWMODE GR_COPY #define GR_DEFAULT_DRAWMODE GR_COPY diff --git a/include/class_board_design_settings.h b/include/class_board_design_settings.h index 53c3a40812..aad0e2b64b 100644 --- a/include/class_board_design_settings.h +++ b/include/class_board_design_settings.h @@ -37,7 +37,6 @@ public: int m_SolderPasteMargin; ///< Solder paste margin absolute value double m_SolderPasteMarginRatio; ///< Solder pask margin ratio value of pad size ///< The final margin is the sum of these 2 values - int m_BoardThickness; ///< Board Thickness for 3D viewer // Variables used in footprint handling wxSize m_ModuleTextSize; ///< Default footprint texts size @@ -188,11 +187,15 @@ public: */ void AppendConfigs( PARAM_CFG_ARRAY* aResult ); + int GetBoardThickness() const { return m_boardThickness; } + void SetBoardThickness( int aThickness ) { m_boardThickness = aThickness; } + private: int m_CopperLayerCount; ///< Number of copper layers for this design int m_EnabledLayers; ///< Bit-mask for layer enabling int m_VisibleLayers; ///< Bit-mask for layer visibility int m_VisibleElements; ///< Bit-mask for element category visibility + int m_boardThickness; ///< Board thickness for 3D viewer }; #endif // BOARD_DESIGN_SETTINGS_H_ diff --git a/include/eda_text.h b/include/eda_text.h index 529733bb3c..ad44c3e48e 100644 --- a/include/eda_text.h +++ b/include/eda_text.h @@ -57,7 +57,10 @@ enum EDA_DRAW_MODE_T { SKETCH // sketch mode: segments have thickness, but are not filled }; + #define DEFAULT_SIZE_TEXT 60 /* default text height (in mils or 1/1000") */ +#define TEXT_NO_VISIBLE 1 //< EDA_TEXT::m_Attribut(e?) visibility flag. + /** * Class EDA_TEXT @@ -110,6 +113,15 @@ public: void SetItalic( bool isItalic ) { m_Italic = isItalic; } bool IsItalic() const { return m_Italic; } + void SetBold( bool aBold ) { m_Bold = aBold; } + bool IsBold() const { return m_Bold; } + + void SetVisible( bool aVisible ) + { + ( aVisible ) ? m_Attributs &= ~TEXT_NO_VISIBLE : m_Attributs |= TEXT_NO_VISIBLE; + } + bool IsVisible() const { return !( m_Attributs & TEXT_NO_VISIBLE ); } + void SetMirrored( bool isMirrored ) { m_Mirror = isMirrored; } bool IsMirrored() const { return m_Mirror; } diff --git a/include/layers_id_colors_and_visibility.h b/include/layers_id_colors_and_visibility.h index ca35fcf0bd..6b7fd7ef38 100644 --- a/include/layers_id_colors_and_visibility.h +++ b/include/layers_id_colors_and_visibility.h @@ -7,6 +7,7 @@ #define _LAYERS_ID_AND_VISIBILITY_H_ /* Layer identification (layer number) */ +#define UNDEFINED_LAYER -1 #define FIRST_COPPER_LAYER 0 #define LAYER_N_BACK 0 #define LAYER_N_2 1 diff --git a/kicad/tree_project_frame.cpp b/kicad/tree_project_frame.cpp index e7e4dd7037..bcc750fabf 100644 --- a/kicad/tree_project_frame.cpp +++ b/kicad/tree_project_frame.cpp @@ -539,7 +539,10 @@ bool TREE_PROJECT_FRAME::AddFileToTree( const wxString& aName, bool addFile = false; for( unsigned i = 0; i < m_Filters.size(); i++ ) { - reg.Compile( m_Filters[i], wxRE_ICASE ); + wxCHECK2_MSG( reg.Compile( m_Filters[i], wxRE_ICASE ), continue, + wxT( "Regular expression " ) + m_Filters[i] + + wxT( " failed to compile." ) ); + if( reg.Matches( aName ) ) { addFile = true; diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index 6589ba0fc2..e891aaa93b 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -339,6 +339,18 @@ int BOARD::GetCurrentMicroViaDrill() } +bool BOARD::SetLayer( int aIndex, const LAYER& aLayer ) +{ + if( aIndex < NB_COPPER_LAYERS ) + { + m_Layer[ aIndex ] = aLayer; + return true; + } + + return false; +} + + wxString BOARD::GetLayerName( int aLayerIndex ) const { if( !IsValidLayerIndex( aLayerIndex ) ) @@ -407,7 +419,7 @@ bool BOARD::SetLayerName( int aLayerIndex, const wxString& aLayerName ) if( !IsValidCopperLayerIndex( aLayerIndex ) ) return false; - if( aLayerName == wxEmptyString || aLayerName.Len() > 20 ) + if( aLayerName == wxEmptyString || aLayerName.Len() > 20 ) return false; // no quote chars in the name allowed @@ -506,14 +518,65 @@ LAYER_T LAYER::ParseType( const char* aType ) else if( strcmp( aType, "jumper" ) == 0 ) return LT_JUMPER; else - return LAYER_T( -1 ); + return LT_UNDEFINED; } + +int LAYER::GetDefaultIndex( const wxString& aName ) +{ + static LAYER_INDEX_HASH_MAP layerIndices; + + if( layerIndices.empty() ) + { + // These are only default layer names. The copper names may be over-ridden in + // the BOARD (*.brd) file. + + layerIndices[ _( "Front" ) ] = LAYER_N_FRONT; + layerIndices[ _( "Inner2" ) ] = LAYER_N_2; + layerIndices[ _( "Inner3" ) ] = LAYER_N_3; + layerIndices[ _( "Inner4" ) ] = LAYER_N_4; + layerIndices[ _( "Inner5" ) ] = LAYER_N_5; + layerIndices[ _( "Inner6" ) ] = LAYER_N_6; + layerIndices[ _( "Inner7" ) ] = LAYER_N_7; + layerIndices[ _( "Inner8" ) ] = LAYER_N_8; + layerIndices[ _( "Inner9" ) ] = LAYER_N_9; + layerIndices[ _( "Inner10" ) ] = LAYER_N_10; + layerIndices[ _( "Inner11" ) ] = LAYER_N_11; + layerIndices[ _( "Inner12" ) ] = LAYER_N_12; + layerIndices[ _( "Inner13" ) ] = LAYER_N_13; + layerIndices[ _( "Inner14" ) ] = LAYER_N_14; + layerIndices[ _( "Inner15" ) ] = LAYER_N_15; + layerIndices[ _( "Back" ) ] = LAYER_N_BACK; + layerIndices[ _( "Adhes_Back" ) ] = ADHESIVE_N_BACK; + layerIndices[ _( "Adhes_Front" ) ] = ADHESIVE_N_FRONT; + layerIndices[ _( "SoldP_Back" ) ] = SOLDERPASTE_N_BACK; + layerIndices[ _( "SoldP_Front" ) ] = SOLDERPASTE_N_FRONT; + layerIndices[ _( "SilkS_Back" ) ] = SILKSCREEN_N_BACK; + layerIndices[ _( "SilkS_Front" ) ] = SILKSCREEN_N_FRONT; + layerIndices[ _( "Mask_Back" ) ] = SOLDERMASK_N_BACK; + layerIndices[ _( "Mask_Front" ) ] = SOLDERMASK_N_FRONT; + layerIndices[ _( "Drawings" ) ] = DRAW_N; + layerIndices[ _( "Comments" ) ] = COMMENT_N; + layerIndices[ _( "Eco1" ) ] = ECO1_N; + layerIndices[ _( "Eco2" ) ] = ECO2_N; + layerIndices[ _( "PCB_Edges" ) ] = EDGE_N; + } + + const LAYER_INDEX_HASH_MAP::iterator it = layerIndices.find( aName ); + + if( it == layerIndices.end() ) + return UNDEFINED_LAYER; + + return layerIndices[ aName ]; +} + + int BOARD::GetCopperLayerCount() const { return m_designSettings.GetCopperLayerCount(); } + void BOARD::SetCopperLayerCount( int aCount ) { m_designSettings.SetCopperLayerCount( aCount ); diff --git a/pcbnew/class_board.h b/pcbnew/class_board.h index 3ea070f1ac..b2a6476819 100644 --- a/pcbnew/class_board.h +++ b/pcbnew/class_board.h @@ -19,6 +19,9 @@ #include #include +#include + + class PCB_BASE_FRAME; class PCB_EDIT_FRAME; class PICKED_ITEMS_LIST; @@ -43,6 +46,7 @@ typedef std::vector< TRACK* > TRACK_PTRS; */ enum LAYER_T { + LT_UNDEFINED = -1, LT_SIGNAL, LT_POWER, LT_MIXED, @@ -51,11 +55,27 @@ enum LAYER_T /** - * Struct LAYER + * Class LAYER * holds information pertinent to a layer of a BOARD. */ -struct LAYER +class LAYER { +public: + LAYER( const wxString& aName = wxEmptyString, LAYER_T aType = LT_SIGNAL, + bool aVisible = true ) : + m_Name( aName ), + m_Type( aType ), + m_visible( aVisible ), + m_fixedListIndex( UNDEFINED_LAYER ) + { + } + + void SetVisible( bool aEnable ) { m_visible = aEnable; } + bool IsVisible() const { return m_visible; } + + void SetFixedListIndex( int aIndex ) { m_fixedListIndex = aIndex; } + int GetFixedListIndex() const { return m_fixedListIndex; } + /** The name of the layer, there should be no spaces in this name. */ wxString m_Name; @@ -63,7 +83,6 @@ struct LAYER LAYER_T m_Type; // int m_Color; -// bool m_Visible; // ? use flags in m_Color instead ? /** * Function ShowType @@ -81,9 +100,25 @@ struct LAYER * LAYER_T(-1) if the string is invalid */ static LAYER_T ParseType( const char* aType ); + + /** + * Function GetDefaultIndex + * returns the layer index of the layer \a aName. + * + * @param aName A reference to a wxString object containing the default layer name. + * @return The index of the layer \a aName if found otherwise #UNDEFINED_LAYER_INDEX. + */ + static int GetDefaultIndex( const wxString& aName ); + +private: + bool m_visible; + int m_fixedListIndex; }; +WX_DECLARE_STRING_HASH_MAP( int, LAYER_INDEX_HASH_MAP ); + + /** * Struct VIA_DIMENSION * is a small helper container to handle a stock of specific vias each with @@ -600,6 +635,8 @@ public: */ bool SetLayerName( int aLayerIndex, const wxString& aLayerName ); + bool SetLayer( int aIndex, const LAYER& aLayer ); + /** * Function GetLayerType * returns the type of the copper layer given by aLayerIndex. diff --git a/pcbnew/class_board_design_settings.cpp b/pcbnew/class_board_design_settings.cpp index 5a8eeec5bb..8fcdeae7ed 100644 --- a/pcbnew/class_board_design_settings.cpp +++ b/pcbnew/class_board_design_settings.cpp @@ -62,7 +62,7 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS() : m_ModuleSegmentWidth = DMils2iu( 100 ); // Layer thickness for 3D viewer - m_BoardThickness = DMils2iu( DEFAULT_BOARD_THICKNESS_DMILS ); + m_boardThickness = DMils2iu( DEFAULT_BOARD_THICKNESS_DMILS ); } @@ -70,7 +70,7 @@ void BOARD_DESIGN_SETTINGS::AppendConfigs( PARAM_CFG_ARRAY* aResult ) { m_Pad_Master.AppendConfigs( aResult ); - aResult->push_back( new PARAM_CFG_INT( wxT( "BoardThickness" ), &m_BoardThickness, + aResult->push_back( new PARAM_CFG_INT( wxT( "BoardThickness" ), &m_boardThickness, DMils2iu( DEFAULT_BOARD_THICKNESS_DMILS ), 0, 0xFFFF ) ); aResult->push_back( new PARAM_CFG_INT( wxT( "TxtPcbV" ), &m_PcbTextSize.y, diff --git a/pcbnew/class_board_item.cpp b/pcbnew/class_board_item.cpp index 8795948220..38352ea57d 100644 --- a/pcbnew/class_board_item.cpp +++ b/pcbnew/class_board_item.cpp @@ -91,31 +91,15 @@ wxString BOARD_ITEM::GetLayerName() const std::string BOARD_ITEM::FormatInternalUnits( int aValue ) { - char buf[50]; + char buf[50]; #if defined( USE_PCBNEW_NANOMETRES ) - double engUnits = aValue / 1000000.0; + int nm = aValue; #else - double engUnits = ( aValue * 10000.0 ) / 25.4 / 1000000.0; + int nm = KIROUND( ( aValue / 10000.0 ) * 25.4 * 1e6 ); #endif - int len; - - if( engUnits != 0.0 && fabs( engUnits ) <= 0.0001 ) - { - // printf( "f: " ); - len = snprintf( buf, 49, "%.10f", engUnits ); - - while( --len > 0 && buf[len] == '0' ) - buf[len] = '\0'; - - ++len; - } - else - { - // printf( "g: " ); - len = snprintf( buf, 49, "%.10g", engUnits ); - } + int len = snprintf( buf, 49, "%g", nm / 1e6 ); return std::string( buf, len ); } diff --git a/pcbnew/class_dimension.h b/pcbnew/class_dimension.h index e10b925f83..ef449c32cf 100644 --- a/pcbnew/class_dimension.h +++ b/pcbnew/class_dimension.h @@ -32,6 +32,7 @@ #include +#include class LINE_READER; diff --git a/pcbnew/class_module.cpp b/pcbnew/class_module.cpp index 75b71a5773..d8beb467ff 100644 --- a/pcbnew/class_module.cpp +++ b/pcbnew/class_module.cpp @@ -572,6 +572,20 @@ D_PAD* MODULE::GetPad( const wxPoint& aPosition, int aLayerMask ) } +void MODULE::Add3DModel( S3D_MASTER* a3DModel ) +{ + a3DModel->SetParent( this ); + m_3D_Drawings.PushBack( a3DModel ); +} + + +void MODULE::AddPad( D_PAD* aPad ) +{ + aPad->SetParent( this ); + m_Pads.PushBack( aPad ); +} + + // see class_module.h SEARCH_RESULT MODULE::Visit( INSPECTOR* inspector, const void* testData, const KICAD_T scanTypes[] ) diff --git a/pcbnew/class_module.h b/pcbnew/class_module.h index 9a4477dc92..dce5244907 100644 --- a/pcbnew/class_module.h +++ b/pcbnew/class_module.h @@ -325,6 +325,22 @@ public: */ unsigned GetPadCount() const { return m_Pads.GetCount() ; } + /** + * Function Add3DModel + * adds \a a3DModel definition to the end of the 3D model list. + * + * @param a3DModel A pointer to a #S3D_MASTER to add to the list. + */ + void Add3DModel( S3D_MASTER* a3DModel ); + + /** + * Function AddPad + * adds \a aPad to the end of the pad list. + * + * @param aPad A pointer to a #D_PAD to add to the list. + */ + void AddPad( D_PAD* aPad ); + SEARCH_RESULT Visit( INSPECTOR* inspector, const void* testData, const KICAD_T scanTypes[] ); diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp index ef2511683c..140b0b2cfd 100644 --- a/pcbnew/class_zone.cpp +++ b/pcbnew/class_zone.cpp @@ -916,6 +916,24 @@ ZoneConnection ZONE_CONTAINER::GetPadConnection( D_PAD* aPad ) const } +void ZONE_CONTAINER::AddPolygon( std::vector< wxPoint >& aPolygon ) +{ + if( aPolygon.empty() ) + return; + + for( unsigned i = 0; i < aPolygon.size(); i++ ) + { + if( i == 0 ) + m_Poly->Start( GetLayer(), aPolygon[i].x, aPolygon[i].y, GetHatchStyle() ); + else + AppendCorner( aPolygon[i] ); + } + + m_Poly->Close(); +} + + + wxString ZONE_CONTAINER::GetSelectMenuText() const { wxString text; diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h index 8c81c296f9..376c330c4c 100644 --- a/pcbnew/class_zone.h +++ b/pcbnew/class_zone.h @@ -429,6 +429,11 @@ public: return m_Poly->GetHatchStyle(); } + void SetHatchStyle( CPolyLine::hatch_style aStyle ) + { + m_Poly->SetHatchStyle( aStyle ); + } + /** * Function TransformShapeWithClearanceToPolygon * Convert the track shape to a closed polygon @@ -515,6 +520,18 @@ public: unsigned int GetCornerRadius() const { return cornerRadius; }; + void AddPolygon( std::vector< wxPoint >& aPolygon ); + + void AddFilledPolygon( std::vector< CPolyPt >& aPolygon ) + { + m_FilledPolysList.insert( m_FilledPolysList.end(), aPolygon.begin(), aPolygon.end() ); + } + + void AddFillSegments( std::vector< SEGMENT >& aSegments ) + { + m_FillSegmList.insert( m_FillSegmList.end(), aSegments.begin(), aSegments.end() ); + } + virtual wxString GetSelectMenuText() const; virtual BITMAP_DEF GetMenuImage() const { return add_zone_xpm; } diff --git a/pcbnew/export_vrml.cpp b/pcbnew/export_vrml.cpp index d1c2cfebcf..3ef710c4a2 100644 --- a/pcbnew/export_vrml.cpp +++ b/pcbnew/export_vrml.cpp @@ -369,7 +369,7 @@ static void compute_layer_Zs( BOARD* pcb ) //{{{ int copper_layers = pcb->GetCopperLayerCount( ); // We call it 'layer' thickness, but it's the whole board thickness! - double board_thickness = pcb->GetDesignSettings().m_BoardThickness; + double board_thickness = pcb->GetDesignSettings().GetBoardThickness(); double half_thickness = board_thickness / 2; // Compute each layer's Z value, more or less like the 3d view diff --git a/pcbnew/kicad_plugin.cpp b/pcbnew/kicad_plugin.cpp index 0303c807a0..a2a307f3e3 100644 --- a/pcbnew/kicad_plugin.cpp +++ b/pcbnew/kicad_plugin.cpp @@ -1,1019 +1,1106 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2012 CERN - * Copyright (C) 1992-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 - */ - -#include -#include -#include -#include // LEGACY_BOARD_FILE_VERSION - -#include <3d_struct.h> - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define FMTIU BOARD_ITEM::FormatInternalUnits - - -void PCB_IO::Save( const wxString& aFileName, BOARD* aBoard, PROPERTIES* aProperties ) -{ - LOCALE_IO toggle; // toggles on, then off, the C locale. - - m_board = aBoard; - - wxFileOutputStream fs( aFileName ); - - if( !fs.IsOk() ) - { - m_error.Printf( _( "cannot open file '%s'" ), aFileName.GetData() ); - THROW_IO_ERROR( m_error ); - } - - STREAM_OUTPUTFORMATTER formatter( fs ); - - formatter.Print( 0, "(kicad-board (version %d) (host pcbnew %s)\n", SEXPR_BOARD_FILE_VERSION, - formatter.Quotew( GetBuildVersion() ).c_str() ); - Format( aBoard, (OUTPUTFORMATTER*) &formatter, 1, 0 ); - formatter.Print( 0, ")\n" ); -} - - -void PCB_IO::Format( BOARD_ITEM* aItem, OUTPUTFORMATTER* aFormatter, int aNestLevel, - int aControlBits ) const - throw( IO_ERROR ) -{ - switch( aItem->Type() ) - { - case PCB_T: - format( (BOARD*) aItem, aFormatter, aNestLevel, aControlBits ); - break; - - case PCB_DIMENSION_T: - format( ( DIMENSION*) aItem, aFormatter, aNestLevel, aControlBits ); - break; - - case PCB_LINE_T: - format( (DRAWSEGMENT*) aItem, aFormatter, aNestLevel, aControlBits ); - break; - - case PCB_MODULE_EDGE_T: - format( (EDGE_MODULE*) aItem, aFormatter, aNestLevel, aControlBits ); - break; - - case PCB_TARGET_T: - format( (PCB_TARGET*) aItem, aFormatter, aNestLevel, aControlBits ); - break; - - case PCB_MODULE_T: - format( (MODULE*) aItem, aFormatter, aNestLevel, aControlBits ); - break; - - case PCB_PAD_T: - format( (D_PAD*) aItem, aFormatter, aNestLevel, aControlBits ); - break; - - case PCB_TEXT_T: - format( (TEXTE_PCB*) aItem, aFormatter, aNestLevel, aControlBits ); - break; - - case PCB_MODULE_TEXT_T: - format( (TEXTE_MODULE*) aItem, aFormatter, aNestLevel, aControlBits ); - break; - - case PCB_TRACE_T: - case PCB_VIA_T: - format( (TRACK*) aItem, aFormatter, aNestLevel, aControlBits ); - break; - - case PCB_ZONE_AREA_T: - format( (ZONE_CONTAINER*) aItem, aFormatter, aNestLevel, aControlBits ); - break; - - default: - wxFAIL_MSG( wxT( "Cannot format item " ) + aItem->GetClass() ); - } -} - - -void PCB_IO::format( BOARD* aBoard, OUTPUTFORMATTER* aFormatter, int aNestLevel, - int aControlBits ) const - throw( IO_ERROR ) -{ - aFormatter->Print( aNestLevel, ")\n" ); - aFormatter->Print( 0, "\n" ); - - aFormatter->Print( aNestLevel, "(general\n" ); - aFormatter->Print( aNestLevel+1, "(links %d)\n", aBoard->GetRatsnestsCount() ); - aFormatter->Print( aNestLevel+1, "(no_connects %d)\n", aBoard->m_NbNoconnect ); - - // Write Bounding box info - aFormatter->Print( aNestLevel+1, "(area %s %s %s %s)\n", - FMTIU( aBoard->GetBoundingBox().GetX() ).c_str(), - FMTIU( aBoard->GetBoundingBox().GetY() ).c_str(), - FMTIU( aBoard->GetBoundingBox().GetRight() ).c_str(), - FMTIU( aBoard->GetBoundingBox().GetBottom() ).c_str() ); - aFormatter->Print( aNestLevel+1, "(thickness %s)\n", - FMTIU( aBoard->GetDesignSettings().m_BoardThickness ).c_str() ); - - aFormatter->Print( aNestLevel+1, "(drawings %d)\n", aBoard->m_Drawings.GetCount() ); - aFormatter->Print( aNestLevel+1, "(tracks %d)\n", aBoard->GetNumSegmTrack() ); - aFormatter->Print( aNestLevel+1, "(zones %d)\n", aBoard->GetNumSegmZone() ); - aFormatter->Print( aNestLevel+1, "(modules %d)\n", aBoard->m_Modules.GetCount() ); - aFormatter->Print( aNestLevel+1, "(nets %d)\n", aBoard->GetNetCount() ); - aFormatter->Print( aNestLevel, ")\n\n" ); - - aBoard->GetPageSettings().Format( aFormatter, aNestLevel, aControlBits ); - aBoard->GetTitleBlock().Format( aFormatter, aNestLevel, aControlBits ); - - // Layers. - aFormatter->Print( aNestLevel, "(layers %d %08X", aBoard->GetCopperLayerCount(), - aBoard->GetEnabledLayers() ); - - if( aBoard->GetEnabledLayers() != aBoard->GetVisibleLayers() ) - aFormatter->Print( 0, " %08X", aBoard->GetVisibleLayers() ); - - aFormatter->Print( 0, "\n" ); - - unsigned layerMask = ALL_CU_LAYERS & aBoard->GetEnabledLayers(); - - for( int layer = 0; layerMask; ++layer, layerMask >>= 1 ) - { - if( layerMask & 1 ) - { - aFormatter->Print( aNestLevel+1, "(layer%d %s %s)\n", layer, - aFormatter->Quotew( aBoard->GetLayerName( layer ) ).c_str(), - LAYER::ShowType( aBoard->GetLayerType( layer ) ) ); - } - } - - aFormatter->Print( aNestLevel, ")\n\n" ); - - // Setup - aFormatter->Print( aNestLevel, "(setup\n" ); - - // Save current default track width, for compatibility with older Pcbnew version; - aFormatter->Print( aNestLevel+1, "(last_trace_width %s)\n", - FMTIU( aBoard->m_TrackWidthList[aBoard->m_TrackWidthSelector] ).c_str() ); - - // Save custom tracks width list (the first is not saved here: this is the netclass value - for( unsigned ii = 1; ii < aBoard->m_TrackWidthList.size(); ii++ ) - aFormatter->Print( aNestLevel+1, "(user_trace_width%d %s)\n", - ii+1, FMTIU( aBoard->m_TrackWidthList[ii] ).c_str() ); - - aFormatter->Print( aNestLevel+1, "(trace_clearance %s)\n", - FMTIU( aBoard->m_NetClasses.GetDefault()->GetClearance() ).c_str() ); - - // ZONE_SETTINGS - aFormatter->Print( aNestLevel+1, "(zone_clearance %s)\n", - FMTIU( aBoard->GetZoneSettings().m_ZoneClearance ).c_str() ); - aFormatter->Print( aNestLevel+1, "(zone_45_only %d)\n", - aBoard->GetZoneSettings().m_Zone_45_Only ); - - aFormatter->Print( aNestLevel+1, "(trace_min %s)\n", - FMTIU( aBoard->GetDesignSettings().m_TrackMinWidth ).c_str() ); - - aFormatter->Print( aNestLevel+1, "(segment_width %s)\n", - FMTIU( aBoard->GetDesignSettings().m_DrawSegmentWidth ).c_str() ); - aFormatter->Print( aNestLevel+1, "(edge_width %s)\n", - FMTIU( aBoard->GetDesignSettings().m_EdgeSegmentWidth ).c_str() ); - - // Save current default via size, for compatibility with older Pcbnew version; - aFormatter->Print( aNestLevel+1, "(via_size %s)\n", - FMTIU( aBoard->m_NetClasses.GetDefault()->GetViaDiameter() ).c_str() ); - aFormatter->Print( aNestLevel+1, "(via_drill %s)\n", - FMTIU( aBoard->m_NetClasses.GetDefault()->GetViaDrill() ).c_str() ); - aFormatter->Print( aNestLevel+1, "(via_min_size %s)\n", - FMTIU( aBoard->GetDesignSettings().m_ViasMinSize ).c_str() ); - aFormatter->Print( aNestLevel+1, "(via_min_drill %s)\n", - FMTIU( aBoard->GetDesignSettings().m_ViasMinDrill ).c_str() ); - - // Save custom vias diameters list (the first is not saved here: this is - // the netclass value - for( unsigned ii = 1; ii < aBoard->m_ViasDimensionsList.size(); ii++ ) - aFormatter->Print( aNestLevel+1, "(user_via%d %s %s)\n", ii, - FMTIU( aBoard->m_ViasDimensionsList[ii].m_Diameter ).c_str(), - FMTIU( aBoard->m_ViasDimensionsList[ii].m_Drill ).c_str() ); - - // for old versions compatibility: - aFormatter->Print( aNestLevel+1, "(uvia_size %s)\n", - FMTIU( aBoard->m_NetClasses.GetDefault()->GetuViaDiameter() ).c_str() ); - aFormatter->Print( aNestLevel+1, "(uvia_drill %s)\n", - FMTIU( aBoard->m_NetClasses.GetDefault()->GetuViaDrill() ).c_str() ); - aFormatter->Print( aNestLevel+1, "(uvias_allow %s)\n", - FMTIU( aBoard->GetDesignSettings().m_MicroViasAllowed ).c_str() ); - aFormatter->Print( aNestLevel+1, "(uvia_min_size %s)\n", - FMTIU( aBoard->GetDesignSettings().m_MicroViasMinSize ).c_str() ); - aFormatter->Print( aNestLevel+1, "(uvia_min_drill %s)\n", - FMTIU( aBoard->GetDesignSettings().m_MicroViasMinDrill ).c_str() ); - - aFormatter->Print( aNestLevel+1, "(pcb_text_width %s)\n", - FMTIU( aBoard->GetDesignSettings().m_PcbTextWidth ).c_str() ); - aFormatter->Print( aNestLevel+1, "(pcb_text_size %s %s)\n", - FMTIU( aBoard->GetDesignSettings().m_PcbTextSize.x ).c_str(), - FMTIU( aBoard->GetDesignSettings().m_PcbTextSize.y ).c_str() ); - - aFormatter->Print( aNestLevel+1, "(mod_edge_width %s)\n", - FMTIU( aBoard->GetDesignSettings().m_ModuleSegmentWidth ).c_str() ); - aFormatter->Print( aNestLevel+1, "(mod_text_size %s %s)\n", - FMTIU( aBoard->GetDesignSettings().m_ModuleTextSize.x ).c_str(), - FMTIU( aBoard->GetDesignSettings().m_ModuleTextSize.y ).c_str() ); - aFormatter->Print( aNestLevel+1, "(mod_text_width %s)\n", - FMTIU( aBoard->GetDesignSettings().m_ModuleTextWidth ).c_str() ); - - aFormatter->Print( aNestLevel+1, "(pad_size %s %s)\n", - FMTIU( aBoard->GetDesignSettings().m_Pad_Master.GetSize().x ).c_str(), - FMTIU( aBoard->GetDesignSettings().m_Pad_Master.GetSize().x ).c_str() ); - aFormatter->Print( aNestLevel+1, "(pad_drill %s)\n", - FMTIU( aBoard->GetDesignSettings().m_Pad_Master.GetDrillSize().x ).c_str() ); - - aFormatter->Print( aNestLevel+1, "(pad_to_mask_clearance %s)\n", - FMTIU( aBoard->GetDesignSettings().m_SolderMaskMargin ).c_str() ); - - if( aBoard->GetDesignSettings().m_SolderPasteMargin != 0 ) - aFormatter->Print( aNestLevel+1, "(pad_to_paste_clearance %s)\n", - FMTIU( aBoard->GetDesignSettings().m_SolderPasteMargin ).c_str() ); - - if( aBoard->GetDesignSettings().m_SolderPasteMarginRatio != 0 ) - aFormatter->Print( aNestLevel+1, "(pad_to_paste_clearance_ratio %g)\n", - aBoard->GetDesignSettings().m_SolderPasteMarginRatio ); - - aFormatter->Print( aNestLevel+1, "(aux_axis_origin %s %s)\n", - FMTIU( aBoard->GetOriginAxisPosition().x ).c_str(), - FMTIU( aBoard->GetOriginAxisPosition().y ).c_str() ); - - aFormatter->Print( aNestLevel+1, "(visible_elements %X)\n", - aBoard->GetDesignSettings().GetVisibleElements() ); - - aFormatter->Print( aNestLevel, ")\n\n" ); - - - int netcount = aBoard->GetNetCount(); - - for( int i = 0; i < netcount; ++i ) - aFormatter->Print( aNestLevel, "(net %d %s)\n", - aBoard->FindNet( i )->GetNet(), - aFormatter->Quotew( aBoard->FindNet( i )->GetNetname() ).c_str() ); - - aFormatter->Print( 0, "\n" ); - - // Save the default net class first. - aBoard->m_NetClasses.GetDefault()->Format( aFormatter, aNestLevel, aControlBits ); - - // Save the rest of the net classes alphabetically. - for( NETCLASSES::const_iterator it = aBoard->m_NetClasses.begin(); - it != aBoard->m_NetClasses.end(); - ++it ) - { - NETCLASS* netclass = it->second; - netclass->Format( aFormatter, aNestLevel, aControlBits ); - } - - // Save the graphical items on the board (not owned by a module) - for( BOARD_ITEM* item = aBoard->m_Drawings; item; item = item->Next() ) - Format( item, aFormatter, aNestLevel, aControlBits ); - - aFormatter->Print( 0, "\n" ); - - // Save the modules. - for( MODULE* module = aBoard->m_Modules; module; module = (MODULE*) module->Next() ) - { - Format( module, aFormatter, aNestLevel, aControlBits ); - aFormatter->Print( 0, "\n" ); - } - - // Do not save MARKER_PCBs, they can be regenerated easily. - - // Save the tracks and vias. - for( TRACK* track = aBoard->m_Track; track; track = track->Next() ) - Format( track, aFormatter, aNestLevel, aControlBits ); - - /// @todo Add warning here that the old segment filed zones are no longer supported and - /// will not be saved. - - aFormatter->Print( 0, "\n" ); - - // Save the polygon (which are the newer technology) zones. - for( int i=0; i < aBoard->GetAreaCount(); ++i ) - Format( aBoard->GetArea( i ), aFormatter, aNestLevel, aControlBits ); -} - - -void PCB_IO::format( DIMENSION* aDimension, OUTPUTFORMATTER* aFormatter, int aNestLevel, - int aControlBits ) const - throw( IO_ERROR ) -{ - aFormatter->Print( aNestLevel, "(dimension %s (width %s) (layer %s)", - FMT_IU( aDimension->m_Value ).c_str(), - FMT_IU( aDimension->m_Width ).c_str(), - aFormatter->Quotew( aDimension->GetLayerName() ).c_str() ); - - if( aDimension->GetTimeStamp() ) - aFormatter->Print( 0, " (tstamp %lX)", aDimension->GetTimeStamp() ); - - aFormatter->Print( 0, "\n" ); - - Format( (TEXTE_PCB*) &aDimension->m_Text, aFormatter, aNestLevel+1, aControlBits ); - - aFormatter->Print( aNestLevel+1, "(feature1 pts((xy %s %s) (xy %s %s)))\n", - FMT_IU( aDimension->m_featureLineDOx ).c_str(), - FMT_IU( aDimension->m_featureLineDOy ).c_str(), - FMT_IU( aDimension->m_featureLineDFx ).c_str(), - FMT_IU( aDimension->m_featureLineDFy ).c_str() ); - - aFormatter->Print( aNestLevel+1, "(feature2 pts((xy %s %s) (xy %s %s)))\n", - FMT_IU( aDimension->m_featureLineGOx ).c_str(), - FMT_IU( aDimension->m_featureLineGOy ).c_str(), - FMT_IU( aDimension->m_featureLineGFx ).c_str(), - FMT_IU( aDimension->m_featureLineGFy ).c_str() ); - - aFormatter->Print( aNestLevel+1, "(crossbar pts((xy %s %s) (xy %s %s)))\n", - FMT_IU( aDimension->m_crossBarOx ).c_str(), - FMT_IU( aDimension->m_crossBarOy ).c_str(), - FMT_IU( aDimension->m_crossBarFx ).c_str(), - FMT_IU( aDimension->m_crossBarFy ).c_str() ); - - aFormatter->Print( aNestLevel+1, "(arrow1a pts((xy %s %s) (xy %s %s)))\n", - FMT_IU( aDimension->m_arrowD1Ox ).c_str(), - FMT_IU( aDimension->m_arrowD1Oy ).c_str(), - FMT_IU( aDimension->m_arrowD1Fx ).c_str(), - FMT_IU( aDimension->m_arrowD1Fy ).c_str() ); - - aFormatter->Print( aNestLevel+1, "(arrow1b pts((xy %s %s) (xy %s %s)))\n", - FMT_IU( aDimension->m_arrowD2Ox ).c_str(), - FMT_IU( aDimension->m_arrowD2Oy ).c_str(), - FMT_IU( aDimension->m_arrowD2Fx ).c_str(), - FMT_IU( aDimension->m_arrowD2Fy ).c_str() ); - - aFormatter->Print( aNestLevel+1, "(arrow2a pts((xy %s %s) (xy %s %s)))\n", - FMT_IU( aDimension->m_arrowG1Ox ).c_str(), - FMT_IU( aDimension->m_arrowG1Oy ).c_str(), - FMT_IU( aDimension->m_arrowG1Fx ).c_str(), - FMT_IU( aDimension->m_arrowG1Fy ).c_str() ); - - aFormatter->Print( aNestLevel+1, "(arrow2b pts((xy %s %s) (xy %s %s)))\n", - FMT_IU( aDimension->m_arrowG2Ox ).c_str(), - FMT_IU( aDimension->m_arrowG2Oy ).c_str(), - FMT_IU( aDimension->m_arrowG2Fx ).c_str(), - FMT_IU( aDimension->m_arrowG2Fy ).c_str() ); - - aFormatter->Print( aNestLevel, ")\n" ); - } - - - void PCB_IO::format( DRAWSEGMENT* aSegment, OUTPUTFORMATTER* aFormatter, int aNestLevel, - int aControlBits ) const - throw( IO_ERROR ) - { - unsigned i; - - switch( aSegment->GetShape() ) - { - case S_SEGMENT: // Line - aFormatter->Print( aNestLevel, "(gr_line (pts (xy %s) (xy %s))", - FMT_IU( aSegment->GetStart() ).c_str(), - FMT_IU( aSegment->GetEnd() ).c_str() ); - break; - - case S_CIRCLE: // Circle - aFormatter->Print( aNestLevel, "(gr_circle (center (xy %s)) (end (xy %s))", - FMT_IU( aSegment->GetStart() ).c_str(), - FMT_IU( aSegment->GetEnd() ).c_str() ); - break; - - case S_ARC: // Arc - aFormatter->Print( aNestLevel, "(gr_arc (start (xy %s)) (end (xy %s)) (angle %s)", - FMT_IU( aSegment->GetStart() ).c_str(), - FMT_IU( aSegment->GetEnd() ).c_str(), - FMT_ANGLE( aSegment->GetAngle() ).c_str() ); - break; - - case S_POLYGON: // Polygon - aFormatter->Print( aNestLevel, "(gr_line (pts" ); - - for( i = 0; i < aSegment->GetPolyPoints().size(); ++i ) - aFormatter->Print( 0, " (xy %s)", FMT_IU( aSegment->GetPolyPoints()[i] ).c_str() ); - - aFormatter->Print( 0, ")" ); - break; - - case S_CURVE: // Bezier curve - aFormatter->Print( aNestLevel, "(gr_curve pts(xy(%s) xy(%s) xy(%s) xy(%s))", - FMT_IU( aSegment->GetStart() ).c_str(), - FMT_IU( aSegment->GetBezControl1() ).c_str(), - FMT_IU( aSegment->GetBezControl2() ).c_str(), - FMT_IU( aSegment->GetEnd() ).c_str() ); - break; - - default: - wxFAIL_MSG( wxT( "Cannot format invalid DRAWSEGMENT type." ) ); - }; - - aFormatter->Print( 0, " (layer %s)", aFormatter->Quotew( aSegment->GetLayerName() ).c_str() ); - - if( aSegment->GetWidth() != 0 ) - aFormatter->Print( 0, " (width %s)", FMT_IU( aSegment->GetWidth() ).c_str() ); - - if( aSegment->GetTimeStamp() ) - aFormatter->Print( 0, " (tstamp %lX)", aSegment->GetTimeStamp() ); - - if( aSegment->GetStatus() ) - aFormatter->Print( 0, " (status %X)", aSegment->GetStatus() ); - - aFormatter->Print( 0, ")\n" ); -} - - -void PCB_IO::format( EDGE_MODULE* aModuleDrawing, OUTPUTFORMATTER* aFormatter, int aNestLevel, - int aControlBits ) const - throw( IO_ERROR ) -{ - switch( aModuleDrawing->GetShape() ) - { - case S_SEGMENT: // Line - aFormatter->Print( aNestLevel, "(fp_line (pts (xy %s) (xy %s)", - FMT_IU( aModuleDrawing->GetStart0() ).c_str(), - FMT_IU( aModuleDrawing->GetEnd0() ).c_str() ); - break; - - case S_CIRCLE: // Circle - aFormatter->Print( aNestLevel, "(fp_circle (center (xy %s)) (end (xy %s)", - FMT_IU( aModuleDrawing->GetStart0() ).c_str(), - FMT_IU( aModuleDrawing->GetEnd0() ).c_str() ); - break; - - case S_ARC: // Arc - aFormatter->Print( aNestLevel, "(fp_arc (start (xy %s)) (end (xy %s)) (angle %s)", - FMT_IU( aModuleDrawing->GetStart0() ).c_str(), - FMT_IU( aModuleDrawing->GetEnd0() ).c_str(), - FMT_ANGLE( aModuleDrawing->GetAngle() ).c_str() ); - break; - - case S_POLYGON: // Polygon - aFormatter->Print( aNestLevel, "(fp_poly (pts" ); - - for( unsigned i = 0; i < aModuleDrawing->GetPolyPoints().size(); ++i ) - aFormatter->Print( 0, " (xy %s)", - FMT_IU( aModuleDrawing->GetPolyPoints()[i] ).c_str() ); - - break; - - case S_CURVE: // Bezier curve - aFormatter->Print( aNestLevel, "(fp_curve pts(xy(%s) xy(%s) xy(%s) xy(%s))", - FMT_IU( aModuleDrawing->GetStart0() ).c_str(), - FMT_IU( aModuleDrawing->GetBezControl1() ).c_str(), - FMT_IU( aModuleDrawing->GetBezControl2() ).c_str(), - FMT_IU( aModuleDrawing->GetEnd0() ).c_str() ); - break; - - default: - wxFAIL_MSG( wxT( "Cannot format invalid DRAWSEGMENT type." ) ); - }; - - aFormatter->Print( 0, " (layer %s)", - aFormatter->Quotew( aModuleDrawing->GetLayerName() ).c_str() ); - - if( aModuleDrawing->GetWidth() != 0 ) - aFormatter->Print( 0, " (width %s)", FMT_IU( aModuleDrawing->GetWidth() ).c_str() ); - - if( aModuleDrawing->GetTimeStamp() ) - aFormatter->Print( 0, " (tstamp %lX)", aModuleDrawing->GetTimeStamp() ); - - if( aModuleDrawing->GetStatus() ) - aFormatter->Print( 0, " (status %X)", aModuleDrawing->GetStatus() ); - - aFormatter->Print( 0, ")\n" ); -} - - -void PCB_IO::format( PCB_TARGET* aTarget, OUTPUTFORMATTER* aFormatter, int aNestLevel, - int aControlBits ) const - throw( IO_ERROR ) -{ - aFormatter->Print( aNestLevel, "(target %c (pos (xy %s)) (size %s)", - ( aTarget->GetShape() ) ? 'x' : '+', - FMT_IU( aTarget->GetPosition() ).c_str(), - FMT_IU( aTarget->GetSize() ).c_str() ); - - if( aTarget->GetWidth() != 0 ) - aFormatter->Print( aNestLevel, " (width %s)", FMT_IU( aTarget->GetWidth() ).c_str() ); - - aFormatter->Print( aNestLevel, " (layer %d)", aTarget->GetLayer() ); - - if( aTarget->GetTimeStamp() ) - aFormatter->Print( aNestLevel, " (tstamp %lX)", aTarget->GetTimeStamp() ); - - aFormatter->Print( aNestLevel, ")\n" ); -} - - -void PCB_IO::format( MODULE* aModule, OUTPUTFORMATTER* aFormatter, int aNestLevel, - int aControlBits ) const - throw( IO_ERROR ) -{ - aFormatter->Print( aNestLevel, "(module %s", aFormatter->Quotew( aModule->m_LibRef ).c_str() ); - - if( aModule->IsLocked() ) - aFormatter->Print( aNestLevel, " locked" ); - - if( aModule->IsPlaced() ) - aFormatter->Print( aNestLevel, " placed" ); - - aFormatter->Print( 0, " (tedit %lX) (tstamp %lX)\n", - aModule->GetLastEditTime(), aModule->GetTimeStamp() ); - - aFormatter->Print( aNestLevel+1, "(at %s", FMT_IU( aModule->m_Pos ).c_str() ); - - if( aModule->m_Orient != 0.0 ) - aFormatter->Print( 0, " %s", FMT_ANGLE( aModule->m_Orient ).c_str() ); - - aFormatter->Print( 0, ")\n" ); - - if( !aModule->m_Doc.IsEmpty() ) - aFormatter->Print( aNestLevel+1, "(descr %s)\n", - aFormatter->Quotew( aModule->m_Doc ).c_str() ); - - if( !aModule->m_KeyWord.IsEmpty() ) - aFormatter->Print( aNestLevel+1, "(tags %s)\n", - aFormatter->Quotew( aModule->m_KeyWord ).c_str() ); - - if( !aModule->m_Path.IsEmpty() ) - aFormatter->Print( aNestLevel+1, "(path %s)\n", - aFormatter->Quotew( aModule->m_Path ).c_str() ); - - if( aModule->m_CntRot90 != 0 ) - aFormatter->Print( aNestLevel+1, "(autoplace_cost90 %d)\n", aModule->m_CntRot90 ); - - if( aModule->m_CntRot180 != 0 ) - aFormatter->Print( aNestLevel+1, "(autoplace_cost180 %d)\n", aModule->m_CntRot180 ); - - if( aModule->GetLocalSolderMaskMargin() != 0 ) - aFormatter->Print( aNestLevel+1, "(solder_mask_margin %s)\n", - FMT_IU( aModule->GetLocalSolderMaskMargin() ).c_str() ); - - if( aModule->GetLocalSolderPasteMargin() != 0 ) - aFormatter->Print( aNestLevel+1, "(solder_paste_margin %s)\n", - FMT_IU( aModule->GetLocalSolderPasteMargin() ).c_str() ); - - if( aModule->GetLocalSolderPasteMarginRatio() != 0 ) - aFormatter->Print( aNestLevel+1, "(solder_paste_ratio %g)\n", - aModule->GetLocalSolderPasteMarginRatio() ); - - if( aModule->GetLocalClearance() != 0 ) - aFormatter->Print( aNestLevel+1, "(clearance %s)\n", - FMT_IU( aModule->GetLocalClearance() ).c_str() ); - - if( aModule->m_ZoneConnection != UNDEFINED_CONNECTION ) - aFormatter->Print( aNestLevel+1, "(zone_connect %d)\n", aModule->m_ZoneConnection ); - - if( aModule->m_ThermalWidth != 0 ) - aFormatter->Print( aNestLevel+1, "(thermal_width %s)\n", - FMT_IU( aModule->m_ThermalWidth ).c_str() ); - - if( aModule->m_ThermalGap != 0 ) - aFormatter->Print( aNestLevel+1, "(thermal_gap %s)\n", - FMT_IU( aModule->m_ThermalGap ).c_str() ); - - // Attributes - if( aModule->m_Attributs != MOD_DEFAULT ) - { - aFormatter->Print( aNestLevel+1, "(attr " ); - - if( aModule->m_Attributs & MOD_CMS ) - aFormatter->Print( 0, " smd" ); - - if( aModule->m_Attributs & MOD_VIRTUAL ) - aFormatter->Print( 0, " virtual" ); - - aFormatter->Print( 0, ")\n" ); - } - - Format( (BOARD_ITEM*) aModule->m_Reference, aFormatter, aNestLevel+1, aControlBits ); - Format( (BOARD_ITEM*) aModule->m_Value, aFormatter, aNestLevel+1, aControlBits ); - - // Save drawing elements. - for( BOARD_ITEM* gr = aModule->m_Drawings; gr; gr = gr->Next() ) - Format( gr, aFormatter, aNestLevel+1, aControlBits ); - - // Save pads. - for( D_PAD* pad = aModule->m_Pads; pad; pad = pad->Next() ) - Format( pad, aFormatter, aNestLevel+1, aControlBits ); - - // Save 3D info. - for( S3D_MASTER* t3D = aModule->m_3D_Drawings; t3D; t3D = t3D->Next() ) - { - if( !t3D->m_Shape3DName.IsEmpty() ) - { - aFormatter->Print( aNestLevel+1, "(3d_shape %s\n", - aFormatter->Quotew( t3D->m_Shape3DName ).c_str() ); - - aFormatter->Print( aNestLevel+2, "(at (xyz %.16g %.16g %.16g))\n", - t3D->m_MatPosition.x, - t3D->m_MatPosition.y, - t3D->m_MatPosition.z ); - - aFormatter->Print( aNestLevel+2, "(scale (xyz %.16g %.16g %.16g))\n", - t3D->m_MatScale.x, - t3D->m_MatScale.y, - t3D->m_MatScale.z ); - - aFormatter->Print( aNestLevel+2, "(rotate (xyz %.16g %.16g %.16g))\n", - t3D->m_MatRotation.x, - t3D->m_MatRotation.y, - t3D->m_MatRotation.z ); - - aFormatter->Print( aNestLevel+1, ")\n" ); - } - } - - aFormatter->Print( aNestLevel, ")\n" ); -} - - - - -void PCB_IO::format( D_PAD* aPad, OUTPUTFORMATTER* aFormatter, int aNestLevel, - int aControlBits ) const - throw( IO_ERROR ) -{ - std::string shape; - - switch( aPad->GetShape() ) - { - case PAD_CIRCLE: shape = "circle"; break; - case PAD_RECT: shape = "rectangle"; break; - case PAD_OVAL: shape = "oval"; break; - case PAD_TRAPEZOID: shape = "trapezoid"; break; - - default: - THROW_IO_ERROR( wxString::Format( _( "unknown pad type: %d"), aPad->GetShape() ) ); - } - - std::string type; - - switch( aPad->GetAttribute() ) - { - case PAD_STANDARD: type = "thru_hole"; break; - case PAD_SMD: type = "smd"; break; - case PAD_CONN: type = "connect"; break; - case PAD_HOLE_NOT_PLATED: type = "np_thru_hole"; break; - - default: - THROW_IO_ERROR( wxString::Format( _( "unknown pad attribute: %d" ), - aPad->GetAttribute() ) ); - } - - aFormatter->Print( aNestLevel, "(pad %s %s %s (size %s)\n", - aFormatter->Quotew( aPad->GetPadName() ).c_str(), - type.c_str(), shape.c_str(), - FMT_IU( aPad->GetSize() ).c_str() ); - aFormatter->Print( aNestLevel+1, "(at %s", FMT_IU( aPad->GetPos0() ).c_str() ); - - if( aPad->GetOrientation() != 0.0 ) - aFormatter->Print( 0, " %s", FMT_ANGLE( aPad->GetOrientation() ).c_str() ); - - aFormatter->Print( 0, ")\n" ); - - if( (aPad->GetDrillSize().GetWidth() > 0) || (aPad->GetDrillSize().GetHeight() > 0) ) - { - std::string drill = (aPad->GetDrillSize().GetHeight() > 0) ? - FMT_IU( aPad->GetDrillSize() ).c_str() : - FMT_IU( aPad->GetDrillSize().GetWidth() ).c_str(); - aFormatter->Print( aNestLevel+1, "(drill %s", drill.c_str() ); - - if( (aPad->GetOffset().x > 0) || (aPad->GetOffset().y > 0) ) - { - std::string drillOffset = ( aPad->GetOffset().x > 0 ) ? - FMT_IU( aPad->GetOffset() ).c_str() : - FMT_IU( aPad->GetOffset().x ).c_str(); - aFormatter->Print( 0, " (offset %s)", drillOffset.c_str() ); - } - - aFormatter->Print( 0, ")\n" ); - } - - aFormatter->Print( aNestLevel+1, "(layers %08X)\n", aPad->GetLayerMask() ); - - aFormatter->Print( aNestLevel+1, "(net %d %s)\n", - aPad->GetNet(), aFormatter->Quotew( aPad->GetNetname() ).c_str() ); - - if( aPad->GetDieLength() != 0 ) - aFormatter->Print( aNestLevel+1, "(die_length %s)\n", - FMT_IU( aPad->GetDieLength() ).c_str() ); - - if( aPad->GetLocalSolderMaskMargin() != 0 ) - aFormatter->Print( aNestLevel+1, "(solder_mask_margin %s)\n", - FMT_IU( aPad->GetLocalSolderMaskMargin() ).c_str() ); - - if( aPad->GetLocalSolderPasteMargin() != 0 ) - aFormatter->Print( aNestLevel+1, "(solder_paste_margin %s)\n", - FMT_IU( aPad->GetLocalSolderPasteMargin() ).c_str() ); - - if( aPad->GetLocalSolderPasteMarginRatio() != 0 ) - aFormatter->Print( aNestLevel+1, "(solder_paste_margin_ratio %g)\n", - aPad->GetLocalSolderPasteMarginRatio() ); - - if( aPad->GetLocalClearance() != 0 ) - aFormatter->Print( aNestLevel+1, "(clearance %s)\n", - FMT_IU( aPad->GetLocalClearance() ).c_str() ); - - if( aPad->GetZoneConnection() != UNDEFINED_CONNECTION ) - aFormatter->Print( aNestLevel+1, "(zone_connect %d)\n", aPad->GetZoneConnection() ); - - if( aPad->GetThermalWidth() != 0 ) - aFormatter->Print( aNestLevel+1, "(thermal_width %s)\n", - FMT_IU( aPad->GetThermalWidth() ).c_str() ); - - if( aPad->GetThermalGap() != 0 ) - aFormatter->Print( aNestLevel+1, "(thermal_gap %s)\n", - FMT_IU( aPad->GetThermalGap() ).c_str() ); - - aFormatter->Print( aNestLevel, ")\n" ); -} - - -void PCB_IO::format( TEXTE_PCB* aText, OUTPUTFORMATTER* aFormatter, int aNestLevel, - int aControlBits ) const - throw( IO_ERROR ) -{ - aFormatter->Print( aNestLevel, "(gr_text %s (at %s %s) (layer %s)", - aFormatter->Quotew( aText->GetText() ).c_str(), - FMT_IU( aText->GetPosition() ).c_str(), - FMT_ANGLE( aText->GetOrientation() ).c_str(), - aFormatter->Quotew( aText->GetLayerName() ).c_str() ); - - if( aText->GetTimeStamp() ) - aFormatter->Print( 0, " (tstamp %lX)", aText->GetTimeStamp() ); - - aFormatter->Print( 0, "\n" ); - - aText->EDA_TEXT::Format( aFormatter, aNestLevel, aControlBits ); - - aFormatter->Print( aNestLevel, ")\n" ); -} - - -void PCB_IO::format( TEXTE_MODULE* aText, OUTPUTFORMATTER* aFormatter, int aNestLevel, - int aControlBits ) const - throw( IO_ERROR ) -{ - MODULE* parent = (MODULE*) aText->GetParent(); - double orient = aText->GetOrientation(); - wxString type; - - switch( aText->GetType() ) - { - case 0: type = wxT( "reference" ); break; - case 1: type = wxT( "value" ); break; - default: type = wxT( "user" ); - } - - // Due to the Pcbnew history, m_Orient is saved in screen value - // but it is handled as relative to its parent footprint - if( parent ) - orient += parent->GetOrientation(); - - aFormatter->Print( aNestLevel, "(fp_text %s %s (at %s %s)%s\n", - aFormatter->Quotew( type ).c_str(), - aFormatter->Quotew( aText->GetText() ).c_str(), - FMT_IU( aText->GetPos0() ).c_str(), FMT_ANGLE( orient ).c_str(), - (!aText->IsVisible()) ? " hide" : "" ); - - aText->EDA_TEXT::Format( aFormatter, aNestLevel, aControlBits ); - - aFormatter->Print( aNestLevel, ")\n" ); -} - - -void PCB_IO::format( TRACK* aTrack, OUTPUTFORMATTER* aFormatter, int aNestLevel, - int aControlBits ) const - throw( IO_ERROR ) -{ - if( aTrack->Type() == PCB_VIA_T ) - { - std::string type; - int layer1, layer2; - - SEGVIA* via = (SEGVIA*) aTrack; - BOARD* board = (BOARD*) via->GetParent(); - - wxCHECK_RET( board != 0, wxT( "Via " ) + via->GetSelectMenuText() + - wxT( " has no parent." ) ); - - via->ReturnLayerPair( &layer1, &layer2 ); - - switch( aTrack->GetShape() ) - { - case VIA_THROUGH: type = "thru"; break; - case VIA_BLIND_BURIED: type = "blind"; break; - case VIA_MICROVIA: type = "micro"; break; - default: - THROW_IO_ERROR( wxString::Format( _( "unknown via type %d" ), aTrack->GetShape() ) ); - } - - aFormatter->Print( aNestLevel, "(via %s (at %s) (size %s)", type.c_str(), - FMT_IU( aTrack->GetStart() ).c_str(), - FMT_IU( aTrack->GetWidth() ).c_str() ); - - if( aTrack->GetDrill() != UNDEFINED_DRILL_DIAMETER ) - aFormatter->Print( 0, " (drill %s)", FMT_IU( aTrack->GetDrill() ).c_str() ); - - aFormatter->Print( 0, " (layers %s %s) (net %d)", - aFormatter->Quotew( board->GetLayerName( layer1 ) ).c_str(), - aFormatter->Quotew( board->GetLayerName( layer2 ) ).c_str(), - aTrack->GetNet() ); - } - else - { - aFormatter->Print( aNestLevel, "(segment (start %s) (end %s) (width %s)", - FMT_IU( aTrack->GetStart() ).c_str(), FMT_IU( aTrack->GetEnd() ).c_str(), - FMT_IU( aTrack->GetWidth() ).c_str() ); - - aFormatter->Print( 0, " (layer %s) (net %d)", - aFormatter->Quotew( aTrack->GetLayerName() ).c_str(), - aTrack->GetNet() ); - } - - if( aTrack->GetTimeStamp() != 0 ) - aFormatter->Print( 0, " (tstamp %lX)", aTrack->GetTimeStamp() ); - - if( aTrack->GetStatus() != 0 ) - aFormatter->Print( 0, " (status %X)", aTrack->GetStatus() ); - - aFormatter->Print( 0, ")\n" ); -} - - -void PCB_IO::format( ZONE_CONTAINER* aZone, OUTPUTFORMATTER* aFormatter, int aNestLevel, - int aControlBits ) const - throw( IO_ERROR ) -{ - aFormatter->Print( aNestLevel, "(zone (net %d %s) (layer %s) (tstamp %lX)\n", - aZone->GetNet(), aFormatter->Quotew( aZone->GetNetName() ).c_str(), - aFormatter->Quotew( aZone->GetLayerName() ).c_str(), - aZone->GetTimeStamp() ); - - - // Save the outline aux info - std::string hatch; - - switch( aZone->GetHatchStyle() ) - { - default: - case CPolyLine::NO_HATCH: hatch = "none"; break; - case CPolyLine::DIAGONAL_EDGE: hatch = "edge"; break; - case CPolyLine::DIAGONAL_FULL: hatch = "full"; break; - } - - aFormatter->Print( aNestLevel+1, "(hatch %s)\n", hatch.c_str() ); - - if( aZone->GetPriority() > 0 ) - aFormatter->Print( aNestLevel+1, "(priority %d)\n", aZone->GetPriority() ); - - // Save pad option and clearance - std::string padoption; - - switch( aZone->GetPadConnection() ) - { - default: - case PAD_IN_ZONE: padoption = "yes"; break; - case THERMAL_PAD: padoption = "use_thermal"; break; - case PAD_NOT_IN_ZONE: padoption = "no"; break; - } - - aFormatter->Print( aNestLevel+1, "(connect_pads %s (clearance %s))\n", - padoption.c_str(), FMT_IU( aZone->GetZoneClearance() ).c_str() ); - - aFormatter->Print( aNestLevel+1, "(min_thickness %s)\n", - FMT_IU( aZone->GetMinThickness() ).c_str() ); - - aFormatter->Print( aNestLevel+1, - "(fill %s (mode %s) (arc_segments %d) (thermal_gap %s) (thermal_bridge_width %s)\n", - (aZone->IsFilled()) ? "yes" : "no", - (aZone->GetFillMode()) ? "segment" : "polygon", - aZone->m_ArcToSegmentsCount, - FMT_IU( aZone->GetThermalReliefGap() ).c_str(), - FMT_IU( aZone->GetThermalReliefCopperBridge() ).c_str() ); - - std::string smoothing; - - switch( aZone->GetCornerSmoothingType() ) - { - case ZONE_SETTINGS::SMOOTHING_NONE: smoothing = "none"; break; - case ZONE_SETTINGS::SMOOTHING_CHAMFER: smoothing = "chamfer"; break; - case ZONE_SETTINGS::SMOOTHING_FILLET: smoothing = "fillet"; break; - default: - THROW_IO_ERROR( wxString::Format( _( "unknown zone corner smoothing type %d" ), - aZone->GetCornerSmoothingType() ) ); - } - - aFormatter->Print( aNestLevel+1, "(smoothing %s (radius %s))\n", - smoothing.c_str(), FMT_IU( aZone->GetCornerRadius() ).c_str() ); - - const std::vector< CPolyPt >& cv = aZone->m_Poly->corner; - - if( cv.size() ) - { - aFormatter->Print( aNestLevel+1, "(polygon\n"); - aFormatter->Print( aNestLevel+2, "(pts\n" ); - - for( std::vector< CPolyPt >::const_iterator it = cv.begin(); it != cv.end(); ++it ) - { - aFormatter->Print( aNestLevel+3, "(xy %s %s)\n", - FMT_IU( it->x ).c_str(), FMT_IU( it->y ).c_str() ); - - if( it->end_contour ) - { - aFormatter->Print( aNestLevel+2, ")\n" ); - - if( it+1 != cv.end() ) - { - aFormatter->Print( aNestLevel+1, ")\n" ); - aFormatter->Print( aNestLevel+1, "(polygon\n" ); - aFormatter->Print( aNestLevel+2, "(pts\n" ); - } - } - } - - aFormatter->Print( aNestLevel+1, ")\n" ); - } - - // Save the PolysList - const std::vector< CPolyPt >& fv = aZone->GetFilledPolysList(); - - if( fv.size() ) - { - aFormatter->Print( aNestLevel+1, "(filled_polygon\n" ); - aFormatter->Print( aNestLevel+2, "(pts\n" ); - - for( std::vector< CPolyPt >::const_iterator it = fv.begin(); it != fv.end(); ++it ) - { - aFormatter->Print( aNestLevel+3, "(xy %s %s)\n", - FMT_IU( it->x ).c_str(), FMT_IU( it->y ).c_str() ); - - if( it->end_contour ) - { - aFormatter->Print( aNestLevel+2, ")\n" ); - - if( it+1 != fv.end() ) - { - aFormatter->Print( aNestLevel+1, ")\n" ); - aFormatter->Print( aNestLevel+1, "(filled_polygon\n" ); - aFormatter->Print( aNestLevel+2, "(pts\n" ); - } - } - } - - aFormatter->Print( aNestLevel+1, ")\n" ); - } - - // Save the filling segments list - const std::vector< SEGMENT >& segs = aZone->m_FillSegmList; - - if( segs.size() ) - { - aFormatter->Print( aNestLevel+1, "(fill_segments\n" ); - - for( std::vector< SEGMENT >::const_iterator it = segs.begin(); it != segs.end(); ++it ) - { - aFormatter->Print( aNestLevel+2, "(pts (xy %s) (xy %s))\n", - FMT_IU( it->m_Start ).c_str(), - FMT_IU( it->m_End ).c_str() ); - } - - aFormatter->Print( aNestLevel+1, ")\n" ); - } - - aFormatter->Print( aNestLevel, ")\n" ); -} +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2012 CERN + * Copyright (C) 1992-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 + */ + +#include +#include +#include +#include // LEGACY_BOARD_FILE_VERSION +#include +#include <3d_struct.h> + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define FMTIU BOARD_ITEM::FormatInternalUnits + + +void PCB_IO::Save( const wxString& aFileName, BOARD* aBoard, PROPERTIES* aProperties ) +{ + LOCALE_IO toggle; // toggles on, then off, the C locale. + + m_board = aBoard; + + wxFileOutputStream fs( aFileName ); + + if( !fs.IsOk() ) + { + m_error.Printf( _( "cannot open file '%s'" ), aFileName.GetData() ); + THROW_IO_ERROR( m_error ); + } + + STREAM_OUTPUTFORMATTER formatter( fs ); + + m_out = &formatter; // no ownership + + m_out->Print( 0, "(kicad_pcb (version %d) (host pcbnew %s)\n", SEXPR_BOARD_FILE_VERSION, + formatter.Quotew( GetBuildVersion() ).c_str() ); + + Format( aBoard, 1 ); + + m_out->Print( 0, ")\n" ); +} + + +void PCB_IO::Format( BOARD_ITEM* aItem, int aNestLevel ) const + throw( IO_ERROR ) +{ + switch( aItem->Type() ) + { + case PCB_T: + format( (BOARD*) aItem, aNestLevel ); + break; + + case PCB_DIMENSION_T: + format( ( DIMENSION*) aItem, aNestLevel ); + break; + + case PCB_LINE_T: + format( (DRAWSEGMENT*) aItem, aNestLevel ); + break; + + case PCB_MODULE_EDGE_T: + format( (EDGE_MODULE*) aItem, aNestLevel ); + break; + + case PCB_TARGET_T: + format( (PCB_TARGET*) aItem, aNestLevel ); + break; + + case PCB_MODULE_T: + format( (MODULE*) aItem, aNestLevel ); + break; + + case PCB_PAD_T: + format( (D_PAD*) aItem, aNestLevel ); + break; + + case PCB_TEXT_T: + format( (TEXTE_PCB*) aItem, aNestLevel ); + break; + + case PCB_MODULE_TEXT_T: + format( (TEXTE_MODULE*) aItem, aNestLevel ); + break; + + case PCB_TRACE_T: + case PCB_VIA_T: + format( (TRACK*) aItem, aNestLevel ); + break; + + case PCB_ZONE_AREA_T: + format( (ZONE_CONTAINER*) aItem, aNestLevel ); + break; + + default: + wxFAIL_MSG( wxT( "Cannot format item " ) + aItem->GetClass() ); + } +} + + +void PCB_IO::formatLayer( const BOARD_ITEM* aItem ) const +{ +#if USE_LAYER_NAMES + m_out->Print( 0, " (layer %s)", m_out->Quotew( aItem->GetLayerName() ).c_str() ); +#else + m_out->Print( 0, " (layer %d)", aItem->GetLayer() ); +#endif +} + + +void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const + throw( IO_ERROR ) +{ + m_out->Print( 0, "\n" ); + + m_out->Print( aNestLevel, "(general\n" ); + m_out->Print( aNestLevel+1, "(links %d)\n", aBoard->GetRatsnestsCount() ); + m_out->Print( aNestLevel+1, "(no_connects %d)\n", aBoard->m_NbNoconnect ); + + // Write Bounding box info + m_out->Print( aNestLevel+1, "(area %s %s %s %s)\n", + FMTIU( aBoard->GetBoundingBox().GetX() ).c_str(), + FMTIU( aBoard->GetBoundingBox().GetY() ).c_str(), + FMTIU( aBoard->GetBoundingBox().GetRight() ).c_str(), + FMTIU( aBoard->GetBoundingBox().GetBottom() ).c_str() ); + m_out->Print( aNestLevel+1, "(thickness %s)\n", + FMTIU( aBoard->GetDesignSettings().GetBoardThickness() ).c_str() ); + + m_out->Print( aNestLevel+1, "(drawings %d)\n", aBoard->m_Drawings.GetCount() ); + m_out->Print( aNestLevel+1, "(tracks %d)\n", aBoard->GetNumSegmTrack() ); + m_out->Print( aNestLevel+1, "(zones %d)\n", aBoard->GetNumSegmZone() ); + m_out->Print( aNestLevel+1, "(modules %d)\n", aBoard->m_Modules.GetCount() ); + m_out->Print( aNestLevel+1, "(nets %d)\n", aBoard->GetNetCount() ); + m_out->Print( aNestLevel, ")\n\n" ); + + aBoard->GetPageSettings().Format( m_out, aNestLevel, m_ctl ); + aBoard->GetTitleBlock().Format( m_out, aNestLevel, m_ctl ); + + // Layers. + m_out->Print( aNestLevel, "(layers\n" ); + + unsigned mask = LAYER_FRONT; + unsigned layer = LAYER_N_FRONT; + + // Save only the used copper layers from front to back. + while( mask != 0 ) + { + if( mask & aBoard->GetEnabledLayers() ) + { +#if USE_LAYER_NAMES + m_out->Print( aNestLevel+1, "(%s %s", + m_out->Quotew( aBoard->GetLayerName( layer ) ).c_str(), + LAYER::ShowType( aBoard->GetLayerType( layer ) ) ); +#else + m_out->Print( aNestLevel+1, "(%d %s %s", layer, + m_out->Quotew( aBoard->GetLayerName( layer ) ).c_str(), + LAYER::ShowType( aBoard->GetLayerType( layer ) ) ); +#endif + + if( !( aBoard->GetVisibleLayers() & mask ) ) + m_out->Print( 0, "hide" ); + + m_out->Print( 0, ")\n" ); + } + + mask >>= 1; + layer--; + } + + mask = ADHESIVE_LAYER_BACK; + layer = ADHESIVE_N_BACK; + + // Save used non-copper layers in the order they are defined. + while( layer < LAYER_COUNT ) + { + if( mask & aBoard->GetEnabledLayers() ) + { +#if USE_LAYER_NAMES + m_out->Print( aNestLevel+1, "(%s user", + m_out->Quotew( aBoard->GetLayerName( layer ) ).c_str() ); +#else + m_out->Print( aNestLevel+1, "(%d %s user", layer, + m_out->Quotew( aBoard->GetLayerName( layer ) ).c_str() ); +#endif + + if( !( aBoard->GetVisibleLayers() & mask ) ) + m_out->Print( 0, "hide" ); + + m_out->Print( 0, ")\n" ); + } + + mask <<= 1; + layer++; + } + + m_out->Print( aNestLevel, ")\n\n" ); + + // Setup + m_out->Print( aNestLevel, "(setup\n" ); + + // Save current default track width, for compatibility with older Pcbnew version; + m_out->Print( aNestLevel+1, "(last_trace_width %s)\n", + FMTIU( aBoard->GetCurrentTrackWidth() ).c_str() ); + + // Save custom tracks width list (the first is not saved here: this is the netclass value + for( unsigned ii = 1; ii < aBoard->m_TrackWidthList.size(); ii++ ) + m_out->Print( aNestLevel+1, "(user_trace_width %s)\n", + FMTIU( aBoard->m_TrackWidthList[ii] ).c_str() ); + + m_out->Print( aNestLevel+1, "(trace_clearance %s)\n", + FMTIU( aBoard->m_NetClasses.GetDefault()->GetClearance() ).c_str() ); + + // ZONE_SETTINGS + m_out->Print( aNestLevel+1, "(zone_clearance %s)\n", + FMTIU( aBoard->GetZoneSettings().m_ZoneClearance ).c_str() ); + m_out->Print( aNestLevel+1, "(zone_45_only %s)\n", + aBoard->GetZoneSettings().m_Zone_45_Only ? "yes" : "no" ); + + m_out->Print( aNestLevel+1, "(trace_min %s)\n", + FMTIU( aBoard->GetDesignSettings().m_TrackMinWidth ).c_str() ); + + m_out->Print( aNestLevel+1, "(segment_width %s)\n", + FMTIU( aBoard->GetDesignSettings().m_DrawSegmentWidth ).c_str() ); + m_out->Print( aNestLevel+1, "(edge_width %s)\n", + FMTIU( aBoard->GetDesignSettings().m_EdgeSegmentWidth ).c_str() ); + + // Save current default via size, for compatibility with older Pcbnew version; + m_out->Print( aNestLevel+1, "(via_size %s)\n", + FMTIU( aBoard->m_NetClasses.GetDefault()->GetViaDiameter() ).c_str() ); + m_out->Print( aNestLevel+1, "(via_drill %s)\n", + FMTIU( aBoard->m_NetClasses.GetDefault()->GetViaDrill() ).c_str() ); + m_out->Print( aNestLevel+1, "(via_min_size %s)\n", + FMTIU( aBoard->GetDesignSettings().m_ViasMinSize ).c_str() ); + m_out->Print( aNestLevel+1, "(via_min_drill %s)\n", + FMTIU( aBoard->GetDesignSettings().m_ViasMinDrill ).c_str() ); + + // Save custom vias diameters list (the first is not saved here: this is + // the netclass value + for( unsigned ii = 1; ii < aBoard->m_ViasDimensionsList.size(); ii++ ) + m_out->Print( aNestLevel+1, "(user_via %s %s)\n", + FMTIU( aBoard->m_ViasDimensionsList[ii].m_Diameter ).c_str(), + FMTIU( aBoard->m_ViasDimensionsList[ii].m_Drill ).c_str() ); + + // for old versions compatibility: + m_out->Print( aNestLevel+1, "(uvia_size %s)\n", + FMTIU( aBoard->m_NetClasses.GetDefault()->GetuViaDiameter() ).c_str() ); + m_out->Print( aNestLevel+1, "(uvia_drill %s)\n", + FMTIU( aBoard->m_NetClasses.GetDefault()->GetuViaDrill() ).c_str() ); + m_out->Print( aNestLevel+1, "(uvias_allowed %s)\n", + ( aBoard->GetDesignSettings().m_MicroViasAllowed ) ? "yes" : "no" ); + m_out->Print( aNestLevel+1, "(uvia_min_size %s)\n", + FMTIU( aBoard->GetDesignSettings().m_MicroViasMinSize ).c_str() ); + m_out->Print( aNestLevel+1, "(uvia_min_drill %s)\n", + FMTIU( aBoard->GetDesignSettings().m_MicroViasMinDrill ).c_str() ); + + m_out->Print( aNestLevel+1, "(pcb_text_width %s)\n", + FMTIU( aBoard->GetDesignSettings().m_PcbTextWidth ).c_str() ); + m_out->Print( aNestLevel+1, "(pcb_text_size %s %s)\n", + FMTIU( aBoard->GetDesignSettings().m_PcbTextSize.x ).c_str(), + FMTIU( aBoard->GetDesignSettings().m_PcbTextSize.y ).c_str() ); + + m_out->Print( aNestLevel+1, "(mod_edge_width %s)\n", + FMTIU( aBoard->GetDesignSettings().m_ModuleSegmentWidth ).c_str() ); + m_out->Print( aNestLevel+1, "(mod_text_size %s %s)\n", + FMTIU( aBoard->GetDesignSettings().m_ModuleTextSize.x ).c_str(), + FMTIU( aBoard->GetDesignSettings().m_ModuleTextSize.y ).c_str() ); + m_out->Print( aNestLevel+1, "(mod_text_width %s)\n", + FMTIU( aBoard->GetDesignSettings().m_ModuleTextWidth ).c_str() ); + + m_out->Print( aNestLevel+1, "(pad_size %s %s)\n", + FMTIU( aBoard->GetDesignSettings().m_Pad_Master.GetSize().x ).c_str(), + FMTIU( aBoard->GetDesignSettings().m_Pad_Master.GetSize().y ).c_str() ); + m_out->Print( aNestLevel+1, "(pad_drill %s)\n", + FMTIU( aBoard->GetDesignSettings().m_Pad_Master.GetDrillSize().x ).c_str() ); + + m_out->Print( aNestLevel+1, "(pad_to_mask_clearance %s)\n", + FMTIU( aBoard->GetDesignSettings().m_SolderMaskMargin ).c_str() ); + + if( aBoard->GetDesignSettings().m_SolderPasteMargin != 0 ) + m_out->Print( aNestLevel+1, "(pad_to_paste_clearance %s)\n", + FMTIU( aBoard->GetDesignSettings().m_SolderPasteMargin ).c_str() ); + + if( aBoard->GetDesignSettings().m_SolderPasteMarginRatio != 0 ) + m_out->Print( aNestLevel+1, "(pad_to_paste_clearance_ratio %g)\n", + aBoard->GetDesignSettings().m_SolderPasteMarginRatio ); + + m_out->Print( aNestLevel+1, "(aux_axis_origin %s %s)\n", + FMTIU( aBoard->GetOriginAxisPosition().x ).c_str(), + FMTIU( aBoard->GetOriginAxisPosition().y ).c_str() ); + + m_out->Print( aNestLevel+1, "(visible_elements %X)\n", + aBoard->GetDesignSettings().GetVisibleElements() ); + + m_out->Print( aNestLevel, ")\n\n" ); + + + int netcount = aBoard->GetNetCount(); + + for( int i = 0; i < netcount; ++i ) + m_out->Print( aNestLevel, "(net %d %s)\n", + aBoard->FindNet( i )->GetNet(), + m_out->Quotew( aBoard->FindNet( i )->GetNetname() ).c_str() ); + + m_out->Print( 0, "\n" ); + + // Save the default net class first. + aBoard->m_NetClasses.GetDefault()->Format( m_out, aNestLevel, m_ctl ); + + // Save the rest of the net classes alphabetically. + for( NETCLASSES::const_iterator it = aBoard->m_NetClasses.begin(); + it != aBoard->m_NetClasses.end(); + ++it ) + { + NETCLASS* netclass = it->second; + netclass->Format( m_out, aNestLevel, m_ctl ); + } + + // Save the graphical items on the board (not owned by a module) + for( BOARD_ITEM* item = aBoard->m_Drawings; item; item = item->Next() ) + Format( item, aNestLevel ); + + m_out->Print( 0, "\n" ); + + // Save the modules. + for( MODULE* module = aBoard->m_Modules; module; module = (MODULE*) module->Next() ) + { + Format( module, aNestLevel ); + m_out->Print( 0, "\n" ); + } + + // Do not save MARKER_PCBs, they can be regenerated easily. + + // Save the tracks and vias. + for( TRACK* track = aBoard->m_Track; track; track = track->Next() ) + Format( track, aNestLevel ); + + /// @todo Add warning here that the old segment filed zones are no longer supported and + /// will not be saved. + + m_out->Print( 0, "\n" ); + + // Save the polygon (which are the newer technology) zones. + for( int i=0; i < aBoard->GetAreaCount(); ++i ) + Format( aBoard->GetArea( i ), aNestLevel ); +} + + +void PCB_IO::format( DIMENSION* aDimension, int aNestLevel ) const + throw( IO_ERROR ) +{ + m_out->Print( aNestLevel, "(dimension %s (width %s)", + FMT_IU( aDimension->m_Value ).c_str(), + FMT_IU( aDimension->m_Width ).c_str() ); + + formatLayer( aDimension ); + + if( aDimension->GetTimeStamp() ) + m_out->Print( 0, " (tstamp %lX)", aDimension->GetTimeStamp() ); + + m_out->Print( 0, "\n" ); + + Format( (TEXTE_PCB*) &aDimension->m_Text, aNestLevel+1 ); + + m_out->Print( aNestLevel+1, "(feature1 (pts (xy %s %s) (xy %s %s)))\n", + FMT_IU( aDimension->m_featureLineDOx ).c_str(), + FMT_IU( aDimension->m_featureLineDOy ).c_str(), + FMT_IU( aDimension->m_featureLineDFx ).c_str(), + FMT_IU( aDimension->m_featureLineDFy ).c_str() ); + + m_out->Print( aNestLevel+1, "(feature2 (pts (xy %s %s) (xy %s %s)))\n", + FMT_IU( aDimension->m_featureLineGOx ).c_str(), + FMT_IU( aDimension->m_featureLineGOy ).c_str(), + FMT_IU( aDimension->m_featureLineGFx ).c_str(), + FMT_IU( aDimension->m_featureLineGFy ).c_str() ); + + m_out->Print( aNestLevel+1, "(crossbar (pts (xy %s %s) (xy %s %s)))\n", + FMT_IU( aDimension->m_crossBarOx ).c_str(), + FMT_IU( aDimension->m_crossBarOy ).c_str(), + FMT_IU( aDimension->m_crossBarFx ).c_str(), + FMT_IU( aDimension->m_crossBarFy ).c_str() ); + + m_out->Print( aNestLevel+1, "(arrow1a (pts (xy %s %s) (xy %s %s)))\n", + FMT_IU( aDimension->m_arrowD1Ox ).c_str(), + FMT_IU( aDimension->m_arrowD1Oy ).c_str(), + FMT_IU( aDimension->m_arrowD1Fx ).c_str(), + FMT_IU( aDimension->m_arrowD1Fy ).c_str() ); + + m_out->Print( aNestLevel+1, "(arrow1b (pts (xy %s %s) (xy %s %s)))\n", + FMT_IU( aDimension->m_arrowD2Ox ).c_str(), + FMT_IU( aDimension->m_arrowD2Oy ).c_str(), + FMT_IU( aDimension->m_arrowD2Fx ).c_str(), + FMT_IU( aDimension->m_arrowD2Fy ).c_str() ); + + m_out->Print( aNestLevel+1, "(arrow2a (pts (xy %s %s) (xy %s %s)))\n", + FMT_IU( aDimension->m_arrowG1Ox ).c_str(), + FMT_IU( aDimension->m_arrowG1Oy ).c_str(), + FMT_IU( aDimension->m_arrowG1Fx ).c_str(), + FMT_IU( aDimension->m_arrowG1Fy ).c_str() ); + + m_out->Print( aNestLevel+1, "(arrow2b (pts (xy %s %s) (xy %s %s)))\n", + FMT_IU( aDimension->m_arrowG2Ox ).c_str(), + FMT_IU( aDimension->m_arrowG2Oy ).c_str(), + FMT_IU( aDimension->m_arrowG2Fx ).c_str(), + FMT_IU( aDimension->m_arrowG2Fy ).c_str() ); + + m_out->Print( aNestLevel, ")\n" ); +} + + +void PCB_IO::format( DRAWSEGMENT* aSegment, int aNestLevel ) const + throw( IO_ERROR ) +{ + unsigned i; + + switch( aSegment->GetShape() ) + { + case S_SEGMENT: // Line + m_out->Print( aNestLevel, "(gr_line (pts (xy %s) (xy %s))", + FMT_IU( aSegment->GetStart() ).c_str(), + FMT_IU( aSegment->GetEnd() ).c_str() ); + break; + + case S_CIRCLE: // Circle + m_out->Print( aNestLevel, "(gr_circle (center (xy %s)) (end (xy %s))", + FMT_IU( aSegment->GetStart() ).c_str(), + FMT_IU( aSegment->GetEnd() ).c_str() ); + break; + + case S_ARC: // Arc + m_out->Print( aNestLevel, "(gr_arc (start (xy %s)) (end (xy %s)) (angle %s)", + FMT_IU( aSegment->GetStart() ).c_str(), + FMT_IU( aSegment->GetEnd() ).c_str(), + FMT_ANGLE( aSegment->GetAngle() ).c_str() ); + break; + + case S_POLYGON: // Polygon + m_out->Print( aNestLevel, "(gr_poly (pts" ); + + for( i = 0; i < aSegment->GetPolyPoints().size(); ++i ) + m_out->Print( 0, " (xy %s)", FMT_IU( aSegment->GetPolyPoints()[i] ).c_str() ); + + m_out->Print( 0, ")" ); + break; + + case S_CURVE: // Bezier curve + m_out->Print( aNestLevel, "(gr_curve (pts (xy %s) (xy %s) (xy %s) (xy %s))", + FMT_IU( aSegment->GetStart() ).c_str(), + FMT_IU( aSegment->GetBezControl1() ).c_str(), + FMT_IU( aSegment->GetBezControl2() ).c_str(), + FMT_IU( aSegment->GetEnd() ).c_str() ); + break; + + default: + wxFAIL_MSG( wxT( "Cannot format invalid DRAWSEGMENT type." ) ); + }; + + formatLayer( aSegment ); + + if( aSegment->GetWidth() != 0 ) + m_out->Print( 0, " (width %s)", FMT_IU( aSegment->GetWidth() ).c_str() ); + + if( aSegment->GetTimeStamp() ) + m_out->Print( 0, " (tstamp %lX)", aSegment->GetTimeStamp() ); + + if( aSegment->GetStatus() ) + m_out->Print( 0, " (status %X)", aSegment->GetStatus() ); + + m_out->Print( 0, ")\n" ); +} + + +void PCB_IO::format( EDGE_MODULE* aModuleDrawing, int aNestLevel ) const + throw( IO_ERROR ) +{ + switch( aModuleDrawing->GetShape() ) + { + case S_SEGMENT: // Line + m_out->Print( aNestLevel, "(fp_line (pts (xy %s) (xy %s))", + FMT_IU( aModuleDrawing->GetStart0() ).c_str(), + FMT_IU( aModuleDrawing->GetEnd0() ).c_str() ); + break; + + case S_CIRCLE: // Circle + m_out->Print( aNestLevel, "(fp_circle (center (xy %s)) (end (xy %s))", + FMT_IU( aModuleDrawing->GetStart0() ).c_str(), + FMT_IU( aModuleDrawing->GetEnd0() ).c_str() ); + break; + + case S_ARC: // Arc + m_out->Print( aNestLevel, "(fp_arc (start (xy %s)) (end (xy %s)) (angle %s)", + FMT_IU( aModuleDrawing->GetStart0() ).c_str(), + FMT_IU( aModuleDrawing->GetEnd0() ).c_str(), + FMT_ANGLE( aModuleDrawing->GetAngle() ).c_str() ); + break; + + case S_POLYGON: // Polygon + m_out->Print( aNestLevel, "(fp_poly (pts" ); + + for( unsigned i = 0; i < aModuleDrawing->GetPolyPoints().size(); ++i ) + m_out->Print( 0, " (xy %s)", + FMT_IU( aModuleDrawing->GetPolyPoints()[i] ).c_str() ); + + m_out->Print( 0, ")\n" ); + break; + + case S_CURVE: // Bezier curve + m_out->Print( aNestLevel, "(fp_curve (pts (xy %s) (xy %s) (xy %s) (xy %s))", + FMT_IU( aModuleDrawing->GetStart0() ).c_str(), + FMT_IU( aModuleDrawing->GetBezControl1() ).c_str(), + FMT_IU( aModuleDrawing->GetBezControl2() ).c_str(), + FMT_IU( aModuleDrawing->GetEnd0() ).c_str() ); + break; + + default: + wxFAIL_MSG( wxT( "Cannot format invalid DRAWSEGMENT type." ) ); + }; + + formatLayer( aModuleDrawing ); + + if( aModuleDrawing->GetWidth() != 0 ) + m_out->Print( 0, " (width %s)", FMT_IU( aModuleDrawing->GetWidth() ).c_str() ); + + if( aModuleDrawing->GetTimeStamp() ) + m_out->Print( 0, " (tstamp %lX)", aModuleDrawing->GetTimeStamp() ); + + if( aModuleDrawing->GetStatus() ) + m_out->Print( 0, " (status %X)", aModuleDrawing->GetStatus() ); + + m_out->Print( 0, ")\n" ); +} + + +void PCB_IO::format( PCB_TARGET* aTarget, int aNestLevel ) const + throw( IO_ERROR ) +{ + m_out->Print( aNestLevel, "(target %s (at %s) (size %s)", + ( aTarget->GetShape() ) ? "x" : "plus", + FMT_IU( aTarget->GetPosition() ).c_str(), + FMT_IU( aTarget->GetSize() ).c_str() ); + + if( aTarget->GetWidth() != 0 ) + m_out->Print( aNestLevel, " (width %s)", FMT_IU( aTarget->GetWidth() ).c_str() ); + + formatLayer( aTarget ); + + if( aTarget->GetTimeStamp() ) + m_out->Print( aNestLevel, " (tstamp %lX)", aTarget->GetTimeStamp() ); + + m_out->Print( aNestLevel, ")\n" ); +} + + +void PCB_IO::format( MODULE* aModule, int aNestLevel ) const + throw( IO_ERROR ) +{ + m_out->Print( aNestLevel, "(module %s", m_out->Quotew( aModule->m_LibRef ).c_str() ); + + if( aModule->IsLocked() ) + m_out->Print( aNestLevel, " locked" ); + + if( aModule->IsPlaced() ) + m_out->Print( aNestLevel, " placed" ); + + formatLayer( aModule ); + + m_out->Print( 0, " (tedit %lX) (tstamp %lX)\n", + aModule->GetLastEditTime(), aModule->GetTimeStamp() ); + + m_out->Print( aNestLevel+1, "(at %s", FMT_IU( aModule->m_Pos ).c_str() ); + + if( aModule->m_Orient != 0.0 ) + m_out->Print( 0, " %s", FMT_ANGLE( aModule->m_Orient ).c_str() ); + + m_out->Print( 0, ")\n" ); + + if( !aModule->m_Doc.IsEmpty() ) + m_out->Print( aNestLevel+1, "(descr %s)\n", + m_out->Quotew( aModule->m_Doc ).c_str() ); + + if( !aModule->m_KeyWord.IsEmpty() ) + m_out->Print( aNestLevel+1, "(tags %s)\n", + m_out->Quotew( aModule->m_KeyWord ).c_str() ); + + if( !aModule->m_Path.IsEmpty() ) + m_out->Print( aNestLevel+1, "(path %s)\n", + m_out->Quotew( aModule->m_Path ).c_str() ); + + if( aModule->m_CntRot90 != 0 ) + m_out->Print( aNestLevel+1, "(autoplace_cost90 %d)\n", aModule->m_CntRot90 ); + + if( aModule->m_CntRot180 != 0 ) + m_out->Print( aNestLevel+1, "(autoplace_cost180 %d)\n", aModule->m_CntRot180 ); + + if( aModule->GetLocalSolderMaskMargin() != 0 ) + m_out->Print( aNestLevel+1, "(solder_mask_margin %s)\n", + FMT_IU( aModule->GetLocalSolderMaskMargin() ).c_str() ); + + if( aModule->GetLocalSolderPasteMargin() != 0 ) + m_out->Print( aNestLevel+1, "(solder_paste_margin %s)\n", + FMT_IU( aModule->GetLocalSolderPasteMargin() ).c_str() ); + + if( aModule->GetLocalSolderPasteMarginRatio() != 0 ) + m_out->Print( aNestLevel+1, "(solder_paste_ratio %g)\n", + aModule->GetLocalSolderPasteMarginRatio() ); + + if( aModule->GetLocalClearance() != 0 ) + m_out->Print( aNestLevel+1, "(clearance %s)\n", + FMT_IU( aModule->GetLocalClearance() ).c_str() ); + + if( aModule->m_ZoneConnection != UNDEFINED_CONNECTION ) + m_out->Print( aNestLevel+1, "(zone_connect %d)\n", aModule->m_ZoneConnection ); + + if( aModule->m_ThermalWidth != 0 ) + m_out->Print( aNestLevel+1, "(thermal_width %s)\n", + FMT_IU( aModule->m_ThermalWidth ).c_str() ); + + if( aModule->m_ThermalGap != 0 ) + m_out->Print( aNestLevel+1, "(thermal_gap %s)\n", + FMT_IU( aModule->m_ThermalGap ).c_str() ); + + // Attributes + if( aModule->m_Attributs != MOD_DEFAULT ) + { + m_out->Print( aNestLevel+1, "(attr" ); + + if( aModule->m_Attributs & MOD_CMS ) + m_out->Print( 0, " smd" ); + + if( aModule->m_Attributs & MOD_VIRTUAL ) + m_out->Print( 0, " virtual" ); + + m_out->Print( 0, ")\n" ); + } + + Format( (BOARD_ITEM*) aModule->m_Reference, aNestLevel+1 ); + Format( (BOARD_ITEM*) aModule->m_Value, aNestLevel+1 ); + + // Save drawing elements. + for( BOARD_ITEM* gr = aModule->m_Drawings; gr; gr = gr->Next() ) + Format( gr, aNestLevel+1 ); + + // Save pads. + for( D_PAD* pad = aModule->m_Pads; pad; pad = pad->Next() ) + Format( pad, aNestLevel+1 ); + + // Save 3D info. + for( S3D_MASTER* t3D = aModule->m_3D_Drawings; t3D; t3D = t3D->Next() ) + { + if( !t3D->m_Shape3DName.IsEmpty() ) + { + m_out->Print( aNestLevel+1, "(model %s\n", + m_out->Quotew( t3D->m_Shape3DName ).c_str() ); + + m_out->Print( aNestLevel+2, "(at (xyz %.16g %.16g %.16g))\n", + t3D->m_MatPosition.x, + t3D->m_MatPosition.y, + t3D->m_MatPosition.z ); + + m_out->Print( aNestLevel+2, "(scale (xyz %.16g %.16g %.16g))\n", + t3D->m_MatScale.x, + t3D->m_MatScale.y, + t3D->m_MatScale.z ); + + m_out->Print( aNestLevel+2, "(rotate (xyz %.16g %.16g %.16g))\n", + t3D->m_MatRotation.x, + t3D->m_MatRotation.y, + t3D->m_MatRotation.z ); + + m_out->Print( aNestLevel+1, ")\n" ); + } + } + + m_out->Print( aNestLevel, ")\n" ); +} + + +void PCB_IO::format( D_PAD* aPad, int aNestLevel ) const + throw( IO_ERROR ) +{ + std::string shape; + + switch( aPad->GetShape() ) + { + case PAD_CIRCLE: shape = "circle"; break; + case PAD_RECT: shape = "rectangle"; break; + case PAD_OVAL: shape = "oval"; break; + case PAD_TRAPEZOID: shape = "trapezoid"; break; + + default: + THROW_IO_ERROR( wxString::Format( _( "unknown pad type: %d"), aPad->GetShape() ) ); + } + + std::string type; + + switch( aPad->GetAttribute() ) + { + case PAD_STANDARD: type = "thru_hole"; break; + case PAD_SMD: type = "smd"; break; + case PAD_CONN: type = "connect"; break; + case PAD_HOLE_NOT_PLATED: type = "np_thru_hole"; break; + + default: + THROW_IO_ERROR( wxString::Format( _( "unknown pad attribute: %d" ), + aPad->GetAttribute() ) ); + } + + m_out->Print( aNestLevel, "(pad %s %s %s (size %s)\n", + m_out->Quotew( aPad->GetPadName() ).c_str(), + type.c_str(), shape.c_str(), + FMT_IU( aPad->GetSize() ).c_str() ); + m_out->Print( aNestLevel+1, "(at %s", FMT_IU( aPad->GetPos0() ).c_str() ); + + if( aPad->GetOrientation() != 0.0 ) + m_out->Print( 0, " %s", FMT_ANGLE( aPad->GetOrientation() ).c_str() ); + + m_out->Print( 0, ")\n" ); + + if( (aPad->GetDrillSize().GetWidth() > 0) || (aPad->GetDrillSize().GetHeight() > 0) ) + { + std::string drill = (aPad->GetDrillSize().GetHeight() > 0) ? + FMT_IU( aPad->GetDrillSize() ).c_str() : + FMT_IU( aPad->GetDrillSize().GetWidth() ).c_str(); + m_out->Print( aNestLevel+1, "(drill %s", drill.c_str() ); + + if( (aPad->GetOffset().x > 0) || (aPad->GetOffset().y > 0) ) + { + std::string drillOffset = ( aPad->GetOffset().x > 0 ) ? + FMT_IU( aPad->GetOffset() ).c_str() : + FMT_IU( aPad->GetOffset().x ).c_str(); + m_out->Print( 0, " (offset %s)", drillOffset.c_str() ); + } + + m_out->Print( 0, ")\n" ); + } + + + m_out->Print( aNestLevel+1, "(layers" ); + + unsigned layerMask = aPad->GetLayerMask() & m_board->GetEnabledLayers(); + + for( int layer = 0; layerMask; ++layer, layerMask >>= 1 ) + { + if( layerMask & 1 ) + { +#if USE_LAYER_NAMES + m_out->Print( 0, " %s", m_out->Quotew( m_board->GetLayerName( layer ) ).c_str() ); +#else + m_out->Print( 0, " %d", layer ); +#endif + } + } + + m_out->Print( 0, ")\n" ); + + m_out->Print( aNestLevel+1, "(net %d %s)\n", + aPad->GetNet(), m_out->Quotew( aPad->GetNetname() ).c_str() ); + + if( aPad->GetDieLength() != 0 ) + m_out->Print( aNestLevel+1, "(die_length %s)\n", + FMT_IU( aPad->GetDieLength() ).c_str() ); + + if( aPad->GetLocalSolderMaskMargin() != 0 ) + m_out->Print( aNestLevel+1, "(solder_mask_margin %s)\n", + FMT_IU( aPad->GetLocalSolderMaskMargin() ).c_str() ); + + if( aPad->GetLocalSolderPasteMargin() != 0 ) + m_out->Print( aNestLevel+1, "(solder_paste_margin %s)\n", + FMT_IU( aPad->GetLocalSolderPasteMargin() ).c_str() ); + + if( aPad->GetLocalSolderPasteMarginRatio() != 0 ) + m_out->Print( aNestLevel+1, "(solder_paste_margin_ratio %g)\n", + aPad->GetLocalSolderPasteMarginRatio() ); + + if( aPad->GetLocalClearance() != 0 ) + m_out->Print( aNestLevel+1, "(clearance %s)\n", + FMT_IU( aPad->GetLocalClearance() ).c_str() ); + + if( aPad->GetZoneConnection() != UNDEFINED_CONNECTION ) + m_out->Print( aNestLevel+1, "(zone_connect %d)\n", aPad->GetZoneConnection() ); + + if( aPad->GetThermalWidth() != 0 ) + m_out->Print( aNestLevel+1, "(thermal_width %s)\n", + FMT_IU( aPad->GetThermalWidth() ).c_str() ); + + if( aPad->GetThermalGap() != 0 ) + m_out->Print( aNestLevel+1, "(thermal_gap %s)\n", + FMT_IU( aPad->GetThermalGap() ).c_str() ); + + m_out->Print( aNestLevel, ")\n" ); +} + + +void PCB_IO::format( TEXTE_PCB* aText, int aNestLevel ) const + throw( IO_ERROR ) +{ + m_out->Print( aNestLevel, "(gr_text %s (at %s %s)", + m_out->Quotew( aText->GetText() ).c_str(), + FMT_IU( aText->GetPosition() ).c_str(), + FMT_ANGLE( aText->GetOrientation() ).c_str() ); + + formatLayer( aText ); + + if( aText->GetTimeStamp() ) + m_out->Print( 0, " (tstamp %lX)", aText->GetTimeStamp() ); + + m_out->Print( 0, "\n" ); + + aText->EDA_TEXT::Format( m_out, aNestLevel, m_ctl ); + + m_out->Print( aNestLevel, ")\n" ); +} + + +void PCB_IO::format( TEXTE_MODULE* aText, int aNestLevel ) const + throw( IO_ERROR ) +{ + MODULE* parent = (MODULE*) aText->GetParent(); + double orient = aText->GetOrientation(); + wxString type; + + switch( aText->GetType() ) + { + case 0: type = wxT( "reference" ); break; + case 1: type = wxT( "value" ); break; + default: type = wxT( "user" ); + } + + // Due to the Pcbnew history, m_Orient is saved in screen value + // but it is handled as relative to its parent footprint + if( parent ) + orient += parent->GetOrientation(); + + m_out->Print( aNestLevel, "(fp_text %s %s (at %s %s)%s\n", + 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" : "" ); + + aText->EDA_TEXT::Format( m_out, aNestLevel, m_ctl ); + + m_out->Print( aNestLevel, ")\n" ); +} + + +void PCB_IO::format( TRACK* aTrack, int aNestLevel ) const + throw( IO_ERROR ) +{ + if( aTrack->Type() == PCB_VIA_T ) + { + std::string type; + int layer1, layer2; + + SEGVIA* via = (SEGVIA*) aTrack; + BOARD* board = (BOARD*) via->GetParent(); + + wxCHECK_RET( board != 0, wxT( "Via " ) + via->GetSelectMenuText() + + wxT( " has no parent." ) ); + + via->ReturnLayerPair( &layer1, &layer2 ); + + switch( aTrack->GetShape() ) + { + case VIA_THROUGH: type = "thru"; break; + case VIA_BLIND_BURIED: type = "blind"; break; + case VIA_MICROVIA: type = "micro"; break; + default: + THROW_IO_ERROR( wxString::Format( _( "unknown via type %d" ), aTrack->GetShape() ) ); + } + + m_out->Print( aNestLevel, "(via %s (at %s) (size %s)", type.c_str(), + FMT_IU( aTrack->GetStart() ).c_str(), + FMT_IU( aTrack->GetWidth() ).c_str() ); + + if( aTrack->GetDrill() != UNDEFINED_DRILL_DIAMETER ) + m_out->Print( 0, " (drill %s)", FMT_IU( aTrack->GetDrill() ).c_str() ); + +#if USE_LAYER_NAMES + m_out->Print( 0, " (layers %s %s)", + m_out->Quotew( m_board->GetLayerName( layer1 ) ).c_str(), + m_out->Quotew( m_board->GetLayerName( layer2 ) ).c_str() ); +#else + m_out->Print( 0, " (layers %d %d)", layer1, layer2 ); +#endif + } + else + { + m_out->Print( aNestLevel, "(segment (start %s) (end %s) (width %s)", + FMT_IU( aTrack->GetStart() ).c_str(), FMT_IU( aTrack->GetEnd() ).c_str(), + FMT_IU( aTrack->GetWidth() ).c_str() ); + +#if USE_LAYER_NAMES + m_out->Print( 0, " (layer %s)", m_out->Quotew( aTrack->GetLayerName() ).c_str() ); +#else + m_out->Print( 0, " (layer %d)", aTrack->GetLayer() ); +#endif + } + + m_out->Print( 0, " (net %d)", aTrack->GetNet() ); + + if( aTrack->GetTimeStamp() != 0 ) + m_out->Print( 0, " (tstamp %lX)", aTrack->GetTimeStamp() ); + + if( aTrack->GetStatus() != 0 ) + m_out->Print( 0, " (status %X)", aTrack->GetStatus() ); + + m_out->Print( 0, ")\n" ); +} + + +void PCB_IO::format( ZONE_CONTAINER* aZone, int aNestLevel ) const + throw( IO_ERROR ) +{ + m_out->Print( aNestLevel, "(zone (net %d) (net_name %s)", + aZone->GetNet(), m_out->Quotew( aZone->GetNetName() ).c_str() ); + + formatLayer( aZone ); + + m_out->Print( 0, " (tstamp %lX)", aZone->GetTimeStamp() ); + + // Save the outline aux info + std::string hatch; + + switch( aZone->GetHatchStyle() ) + { + default: + case CPolyLine::NO_HATCH: hatch = "none"; break; + case CPolyLine::DIAGONAL_EDGE: hatch = "edge"; break; + case CPolyLine::DIAGONAL_FULL: hatch = "full"; break; + } + + m_out->Print( 0, " (hatch %s %s)\n", hatch.c_str(), + FMT_IU( aZone->m_Poly->GetHatchPitch() ).c_str() ); + + if( aZone->GetPriority() > 0 ) + m_out->Print( aNestLevel+1, " (priority %d)\n", aZone->GetPriority() ); + + // Save pad option and clearance + std::string padoption; + + switch( aZone->GetPadConnection() ) + { + default: + case PAD_IN_ZONE: padoption = "yes"; break; + case THERMAL_PAD: padoption = "use_thermal"; break; + case PAD_NOT_IN_ZONE: padoption = "no"; break; + } + + m_out->Print( aNestLevel+1, "(connect_pads %s (clearance %s))\n", + padoption.c_str(), FMT_IU( aZone->GetZoneClearance() ).c_str() ); + + m_out->Print( aNestLevel+1, "(min_thickness %s)\n", + FMT_IU( aZone->GetMinThickness() ).c_str() ); + + m_out->Print( aNestLevel+1, + "(fill %s (mode %s) (arc_segments %d) (thermal_gap %s) (thermal_bridge_width %s)\n", + (aZone->IsFilled()) ? "yes" : "no", + (aZone->GetFillMode()) ? "segment" : "polygon", + aZone->GetArcSegCount(), + FMT_IU( aZone->GetThermalReliefGap() ).c_str(), + FMT_IU( aZone->GetThermalReliefCopperBridge() ).c_str() ); + + std::string smoothing; + + switch( aZone->GetCornerSmoothingType() ) + { + case ZONE_SETTINGS::SMOOTHING_NONE: smoothing = "none"; break; + case ZONE_SETTINGS::SMOOTHING_CHAMFER: smoothing = "chamfer"; break; + case ZONE_SETTINGS::SMOOTHING_FILLET: smoothing = "fillet"; break; + default: + THROW_IO_ERROR( wxString::Format( _( "unknown zone corner smoothing type %d" ), + aZone->GetCornerSmoothingType() ) ); + } + + m_out->Print( aNestLevel+1, "(smoothing %s) (radius %s))\n", + smoothing.c_str(), FMT_IU( aZone->GetCornerRadius() ).c_str() ); + + const std::vector< CPolyPt >& cv = aZone->m_Poly->corner; + + if( cv.size() ) + { + m_out->Print( aNestLevel+1, "(polygon\n"); + m_out->Print( aNestLevel+2, "(pts\n" ); + + for( std::vector< CPolyPt >::const_iterator it = cv.begin(); it != cv.end(); ++it ) + { + m_out->Print( aNestLevel+3, "(xy %s %s)\n", + FMT_IU( it->x ).c_str(), FMT_IU( it->y ).c_str() ); + + if( it->end_contour ) + { + m_out->Print( aNestLevel+2, ")\n" ); + + if( it+1 != cv.end() ) + { + m_out->Print( aNestLevel+1, ")\n" ); + m_out->Print( aNestLevel+1, "(polygon\n" ); + m_out->Print( aNestLevel+2, "(pts\n" ); + } + } + } + + m_out->Print( aNestLevel+1, ")\n" ); + } + + // Save the PolysList + const std::vector< CPolyPt >& fv = aZone->GetFilledPolysList(); + + if( fv.size() ) + { + m_out->Print( aNestLevel+1, "(filled_polygon\n" ); + m_out->Print( aNestLevel+2, "(pts\n" ); + + for( std::vector< CPolyPt >::const_iterator it = fv.begin(); it != fv.end(); ++it ) + { + m_out->Print( aNestLevel+3, "(xy %s %s)\n", + FMT_IU( it->x ).c_str(), FMT_IU( it->y ).c_str() ); + + if( it->end_contour ) + { + m_out->Print( aNestLevel+2, ")\n" ); + + if( it+1 != fv.end() ) + { + m_out->Print( aNestLevel+1, ")\n" ); + m_out->Print( aNestLevel+1, "(filled_polygon\n" ); + m_out->Print( aNestLevel+2, "(pts\n" ); + } + } + } + + m_out->Print( aNestLevel+1, ")\n" ); + } + + // Save the filling segments list + const std::vector< SEGMENT >& segs = aZone->m_FillSegmList; + + if( segs.size() ) + { + m_out->Print( aNestLevel+1, "(fill_segments\n" ); + + for( std::vector< SEGMENT >::const_iterator it = segs.begin(); it != segs.end(); ++it ) + { + m_out->Print( aNestLevel+2, "(pts (xy %s) (xy %s))\n", + FMT_IU( it->m_Start ).c_str(), + FMT_IU( it->m_End ).c_str() ); + } + + m_out->Print( aNestLevel+1, ")\n" ); + } + + m_out->Print( aNestLevel, ")\n" ); +} + + +PCB_IO::PCB_IO() +{ + m_out = &m_sf; +} + + +BOARD* PCB_IO::Load( const wxString& aFileName, BOARD* aAppendToMe, PROPERTIES* aProperties ) +{ + wxFFile file( aFileName, "r" ); + + if( !file.IsOpened() ) + { + THROW_IO_ERROR( _( "Unable to read file \"" ) + GetChars( aFileName ) + wxT( "\"" ) ); + } + + PCB_PARSER parser( new FILE_LINE_READER( file.fp(), aFileName ), aAppendToMe ); + + return (BOARD*) parser.Parse(); +} diff --git a/pcbnew/kicad_plugin.h b/pcbnew/kicad_plugin.h index 8805066bf5..98fb908a2e 100644 --- a/pcbnew/kicad_plugin.h +++ b/pcbnew/kicad_plugin.h @@ -1,137 +1,149 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 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 - */ - -#ifndef KICAD_PLUGIN_H_ -#define KICAD_PLUGIN_H_ - -#include -#include - -class BOARD; -class BOARD_ITEM; - - -/** Current s-expression file format version. 2 was the last legacy format version. */ -#define SEXPR_BOARD_FILE_VERSION 3 - -/** Format output for the clipboard instead of a file. */ -#define CTL_CLIPBOARD (1 << 0) - - -/** - * Class PCB_IO - * is a PLUGIN derivation for saving and loading Pcbnew s-expression formatted files. - * - * @note This class is not thread safe, but it is re-entrant multiple times in sequence. - */ -class PCB_IO : public PLUGIN -{ - -public: - const wxString& PluginName() const - { - static const wxString name = wxT( "KiCad" ); - return name; - } - - const wxString& GetFileExtension() const - { - static const wxString extension = wxT( "kicad_pcb" ); - return extension; - } - - void Save( const wxString& aFileName, BOARD* aBoard, - PROPERTIES* aProperties = NULL ); // overload - - /** - * Function Format - * outputs \a aItem to \a aFormatter in s-expression format. - * - * @param aItem A pointer the an #BOARD_ITEM object to format. - * @param aFormatter The #OUTPUTFORMATTER object to write to. - * @param aNestLevel The indentation nest level. - * @param aControlBits The control bit definition for object specific formatting. - * @throw IO_ERROR on write error. - */ - void Format( BOARD_ITEM* aItem, OUTPUTFORMATTER* aFormatter, int aNestLevel, - int aControlBits ) const - throw( IO_ERROR ); - -protected: - - wxString m_error; ///< for throwing exceptions - BOARD* m_board; ///< which BOARD, no ownership here - PROPERTIES* m_props; ///< passed via Save() or Load(), no ownership, may be NULL. - - LINE_READER* m_reader; ///< no ownership here. - wxString m_filename; ///< for saves only, name is in m_reader for loads - - int m_loading_format_version; ///< which BOARD_FORMAT_VERSION am I Load()ing? - -private: - void format( BOARD* aBoard, OUTPUTFORMATTER* aFormatter, int aNestLevel, - int aControlBits ) const - throw( IO_ERROR ); - - void format( DIMENSION* aDimension, OUTPUTFORMATTER* aFormatter, int aNestLevel, - int aControlBits ) const - throw( IO_ERROR ); - - void format( EDGE_MODULE* aModuleDrawing, OUTPUTFORMATTER* aFormatter, int aNestLevel, - int aControlBits ) const - throw( IO_ERROR ); - - void format( DRAWSEGMENT* aSegment, OUTPUTFORMATTER* aFormatter, int aNestLevel, - int aControlBits ) const - throw( IO_ERROR ); - - void format( PCB_TARGET* aTarget, OUTPUTFORMATTER* aFormatter, int aNestLevel, - int aControlBits ) const - throw( IO_ERROR ); - - void format( MODULE* aModule, OUTPUTFORMATTER* aFormatter, int aNestLevel, - int aControlBits ) const - throw( IO_ERROR ); - - void format( D_PAD* aPad, OUTPUTFORMATTER* aFormatter, int aNestLevel, - int aControlBits ) const - throw( IO_ERROR ); - - void format( TEXTE_PCB* aText, OUTPUTFORMATTER* aFormatter, int aNestLevel, - int aControlBits ) const - throw( IO_ERROR ); - - void format( TEXTE_MODULE* aText, OUTPUTFORMATTER* aFormatter, int aNestLevel, - int aControlBits ) const - throw( IO_ERROR ); - - void format( TRACK* aTrack, OUTPUTFORMATTER* aFormatter, int aNestLevel, - int aControlBits ) const - throw( IO_ERROR ); - - void format( ZONE_CONTAINER* aZone, OUTPUTFORMATTER* aFormatter, int aNestLevel, - int aControlBits ) const - throw( IO_ERROR ); -}; - -#endif // KICAD_PLUGIN_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 + */ + +#ifndef KICAD_PLUGIN_H_ +#define KICAD_PLUGIN_H_ + +#include +#include + +class BOARD; +class BOARD_ITEM; + + +/** Current s-expression file format version. 2 was the last legacy format version. */ +#define SEXPR_BOARD_FILE_VERSION 3 + +/** Format output for the clipboard instead of a file. */ +#define CTL_CLIPBOARD (1 << 0) + + +/** + * Class PCB_IO + * is a PLUGIN derivation for saving and loading Pcbnew s-expression formatted files. + * + * @note This class is not thread safe, but it is re-entrant multiple times in sequence. + */ +class PCB_IO : public PLUGIN +{ + +public: + + //-------------------------------------------------------------- + + const wxString& PluginName() const + { + static const wxString name = wxT( "KiCad" ); + return name; + } + + const wxString& GetFileExtension() const + { + static const wxString extension = wxT( "kicad_pcb" ); + return extension; + } + + void Save( const wxString& aFileName, BOARD* aBoard, + PROPERTIES* aProperties = NULL ); // overload + + BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, PROPERTIES* aProperties = NULL ); + + //------------------------------------------------------------- + + PCB_IO(); + + /** + * Function Format + * outputs \a aItem to \a aFormatter in s-expression format. + * + * @param aItem A pointer the an #BOARD_ITEM object to format. + * @param aNestLevel The indentation nest level. + * @throw IO_ERROR on write error. + */ + void Format( BOARD_ITEM* aItem, int aNestLevel = 0 ) const + throw( IO_ERROR ); + + std::string GetStringOutput( bool doClear ) + { + std::string ret = m_sf.GetString(); + if( doClear ) + m_sf.Clear(); + + return ret; + } + + +protected: + + wxString m_error; ///< for throwing exceptions + BOARD* m_board; ///< which BOARD, no ownership here + PROPERTIES* m_props; ///< passed via Save() or Load(), no ownership, may be NULL. + + LINE_READER* m_reader; ///< no ownership here. + wxString m_filename; ///< for saves only, name is in m_reader for loads + + int m_loading_format_version; ///< which BOARD_FORMAT_VERSION am I Load()ing? + + STRING_FORMATTER m_sf; + OUTPUTFORMATTER* m_out; ///< output any Format()s to this, no ownership + int m_ctl; + + +private: + void format( BOARD* aBoard, int aNestLevel = 0 ) const + throw( IO_ERROR ); + + void format( DIMENSION* aDimension, int aNestLevel = 0 ) const + throw( IO_ERROR ); + + void format( EDGE_MODULE* aModuleDrawing, int aNestLevel = 0 ) const + throw( IO_ERROR ); + + void format( DRAWSEGMENT* aSegment, int aNestLevel = 0 ) const + throw( IO_ERROR ); + + void format( PCB_TARGET* aTarget, int aNestLevel = 0 ) const + throw( IO_ERROR ); + + void format( MODULE* aModule, int aNestLevel = 0 ) const + throw( IO_ERROR ); + + void format( D_PAD* aPad, int aNestLevel = 0 ) const + throw( IO_ERROR ); + + void format( TEXTE_PCB* aText, int aNestLevel = 0 ) const + throw( IO_ERROR ); + + void format( TEXTE_MODULE* aText, int aNestLevel = 0 ) const + throw( IO_ERROR ); + + void format( TRACK* aTrack, int aNestLevel = 0 ) const + throw( IO_ERROR ); + + void format( ZONE_CONTAINER* aZone, int aNestLevel = 0 ) const + throw( IO_ERROR ); + + void formatLayer( const BOARD_ITEM* aItem ) const; +}; + +#endif // KICAD_PLUGIN_H_ diff --git a/pcbnew/legacy_plugin.cpp b/pcbnew/legacy_plugin.cpp index a1636740ee..451fcfa27d 100644 --- a/pcbnew/legacy_plugin.cpp +++ b/pcbnew/legacy_plugin.cpp @@ -403,7 +403,7 @@ void LEGACY_PLUGIN::loadGENERAL() else if( TESTLINE( "BoardThickness" ) ) { BIU thickn = biuParse( line + SZ( "BoardThickness" ) ); - m_board->GetDesignSettings().m_BoardThickness = thickn; + m_board->GetDesignSettings().SetBoardThickness( thickn ); } /* @@ -2215,7 +2215,7 @@ void LEGACY_PLUGIN::loadZONE_CONTAINER() arcsegcount = 32; zc->SetArcSegCount( arcsegcount ); - zc->SetIsFilled( fillstate == 'S' ? true : false ); + zc->SetIsFilled( fillstate == 'F' ? true : false ); zc->SetThermalReliefGap( thermalReliefGap ); zc->SetThermalReliefCopperBridge( thermalReliefCopperBridge ); } @@ -2825,7 +2825,7 @@ void LEGACY_PLUGIN::saveGENERAL( const BOARD* aBoard ) const fprintf( m_fp, "Ndraw %d\n", aBoard->m_Drawings.GetCount() ); fprintf( m_fp, "Ntrack %d\n", aBoard->GetNumSegmTrack() ); fprintf( m_fp, "Nzone %d\n", aBoard->GetNumSegmZone() ); - fprintf( m_fp, "BoardThickness %s\n", fmtBIU( aBoard->GetDesignSettings().m_BoardThickness ).c_str() ); + fprintf( m_fp, "BoardThickness %s\n", fmtBIU( aBoard->GetDesignSettings().GetBoardThickness() ).c_str() ); fprintf( m_fp, "Nmodule %d\n", aBoard->m_Modules.GetCount() ); fprintf( m_fp, "Nnets %d\n", aBoard->GetNetCount() ); fprintf( m_fp, "$EndGENERAL\n\n" ); diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp new file mode 100644 index 0000000000..7117aa5971 --- /dev/null +++ b/pcbnew/pcb_parser.cpp @@ -0,0 +1,2499 @@ +/* + * 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(); +} + diff --git a/pcbnew/pcb_parser.h b/pcbnew/pcb_parser.h new file mode 100644 index 0000000000..45252bee9f --- /dev/null +++ b/pcbnew/pcb_parser.h @@ -0,0 +1,214 @@ +/* + * 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_