← Back to team overview

kicad-developers team mailing list archive

Re: patches for basic IDFv3 support

 

----- Original Message -----

> From: jp charras <jp.charras@xxxxxxxxxx>
> To: kicad-developers@xxxxxxxxxxxxxxxxxxx
> Cc: 
> Sent: Monday, December 16, 2013 9:13 PM
> Subject: Re: [Kicad-developers] patches for basic IDFv3 support
> 
> Le 15/12/2013 12:47, Cirilo Bernardo a écrit :
>>  Hi folks,
>> 
>>   Here are initial patches for consideration to introduce IDFv3 export 
> support. At the moment an IDF board (.emn) and library file (.emp) are produced 
> and the user has the option of producing the files in units of MM (default) or 
> THOU as per IDFv3 spec. The board file uses the board outline if a valid one has 
> been defined, otherwise the bounding box.
>> 
>>   The library file is currently not populated but I plan to develop that 
> incrementally - at first I will implement a simple solution where all components 
> are 5mm extrusions of the component bounding boxes. Any further development of 
> the IDF library file would require much more work since it will be more 
> instrusive but I can set aside some time to work on that if people really want a 
> more refined IDF export.
>> 
>>   The export function is in the same sub-menu as the GenCad, Specctra, and 
> VRML exports.
>> 
>>   I have tested the export using a few crazy outlines which I made up and 
> also using the projects in the KiCad demo directory; all boards including the 
> non-rectangular 'video' demo board were rendered correctly. Outlines 
> with arcs (including hand-crafted arcs which are not 90 degrees) also render 
> fine.
>> 
>>   The patches are against version 4555.
>> 
>>  Regards,
>>  Cirilo
> 
> Thanks, Cirilo.
> 
> I am thinking only one patch could be more easier to apply than 12
> patches, for those who are able to test the IDF3 files ( I do not have
> an IDF3 reader).
> 
> 
> -- 
> Jean-Pierre CHARRAS
> 


Thanks Jean-Pierre,

 I have attached the single patch.  The results have been tested with SolidWorks, but hopefully I get some feedback from people who have other MCAD software.

Cheers,
Cirilo
=== modified file 'include/wxPcbStruct.h'
--- include/wxPcbStruct.h	2013-12-05 12:24:27 +0000
+++ include/wxPcbStruct.h	2013-12-14 11:00:12 +0000
@@ -956,6 +956,12 @@
                           bool aExport3DFiles, const wxString & a3D_Subdir );
 
     /**
+     * Function ExportToIDF3
+     * will export the current BOARD to a IDFv3 board and lib files.
+     */
+    void ExportToIDF3( wxCommandEvent& event );
+
+    /**
      * Function ExporttoSPECCTRA
      * will export the current BOARD to a specctra dsn file.  See
      * See http://www.autotraxeda.com/docs/SPECCTRA/SPECCTRA.pdf for the

=== modified file 'pcbnew/CMakeLists.txt'
--- pcbnew/CMakeLists.txt	2013-12-10 13:43:04 +0000
+++ pcbnew/CMakeLists.txt	2013-12-15 09:07:04 +0000
@@ -55,6 +55,8 @@
     dialogs/dialog_edit_module_text.cpp
     dialogs/dialog_edit_module_text_base.cpp
     dialogs/dialog_exchange_modules_base.cpp
+    dialogs/dialog_export_idf.cpp
+    dialogs/dialog_export_idf_base.cpp
     dialogs/dialog_export_vrml_base.cpp
     dialogs/dialog_export_vrml.cpp
     dialogs/dialog_find_base.cpp
@@ -173,6 +175,7 @@
     event_handlers_tracks_vias_sizes.cpp
     export_d356.cpp
     export_gencad.cpp
+    export_idf.cpp
     export_vrml.cpp
     files.cpp
     gen_drill_report_files.cpp
@@ -183,6 +186,7 @@
     hotkeys.cpp
     hotkeys_board_editor.cpp
     hotkeys_module_editor.cpp
+    idf.cpp
     initpcb.cpp
     layer_widget.cpp
     librairi.cpp

=== added file 'pcbnew/dialogs/dialog_export_idf.cpp'
--- pcbnew/dialogs/dialog_export_idf.cpp	1970-01-01 00:00:00 +0000
+++ pcbnew/dialogs/dialog_export_idf.cpp	2013-12-15 09:19:33 +0000
@@ -0,0 +1,121 @@
+/**
+ * @file dialog_export_idf.cpp
+ */
+
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2013  Cirilo Bernardo
+ *
+ * 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 <wxPcbStruct.h>
+#include <appl_wxstruct.h>
+#include <pcbnew.h>
+#include <class_board.h>
+
+// IDF export header generated by wxFormBuilder
+#include <dialog_export_idf_base.h>
+
+#define OPTKEY_IDF_THOU wxT( "IDFExportThou" )
+
+
+bool Export_IDF3( BOARD *aPcb, const wxString & aFullFileName, double aUseThou );
+
+
+class DIALOG_EXPORT_IDF3: public DIALOG_EXPORT_IDF3_BASE
+{
+private:
+    PCB_EDIT_FRAME* m_parent;
+    wxConfig* m_config;
+    bool m_idfThouOpt;  // remember last preference for units in THOU
+
+    void OnCancelClick( wxCommandEvent& event )
+    {
+        EndModal( wxID_CANCEL );
+    }
+    void OnOkClick( wxCommandEvent& event )
+    {
+        EndModal( wxID_OK );
+    }
+
+public:
+    DIALOG_EXPORT_IDF3( PCB_EDIT_FRAME* parent ) :
+            DIALOG_EXPORT_IDF3_BASE( parent )
+    {
+        m_parent = parent;
+        m_config = wxGetApp().GetSettings();
+        SetFocus();
+        m_idfThouOpt = false;
+        m_config->Read( OPTKEY_IDF_THOU, &m_idfThouOpt );
+        m_chkThou->SetValue( m_idfThouOpt );
+
+        GetSizer()->SetSizeHints( this );
+        Centre();
+    }
+    
+    ~DIALOG_EXPORT_IDF3()
+    {
+        m_idfThouOpt = m_chkThou->GetValue();
+        m_config->Write( OPTKEY_IDF_THOU, m_idfThouOpt );
+    }
+
+    bool GetThouOption()
+    {
+        return m_chkThou->GetValue();
+    }
+
+    wxFilePickerCtrl* FilePicker()
+    {
+        return m_filePickerIDF;
+    }
+};
+
+
+/**
+ * Function OnExportIDF3
+ * will export the current BOARD to IDF board and lib files.
+ */
+void PCB_EDIT_FRAME::ExportToIDF3( wxCommandEvent& event )
+{
+    wxFileName fn;
+
+    // Build default file name
+    fn = GetBoard()->GetFileName();
+    fn.SetExt( wxT( "emn" ) );
+
+    DIALOG_EXPORT_IDF3 dlg( this );
+    dlg.FilePicker()->SetPath( fn.GetFullPath() );
+
+    if ( dlg.ShowModal() != wxID_OK )
+        return;
+
+    bool thou = dlg.GetThouOption();
+
+    wxBusyCursor dummy;
+
+    wxString fullFilename = dlg.FilePicker()->GetPath();
+
+    if ( !Export_IDF3( GetBoard(), fullFilename, thou ) )
+    {
+        wxString msg = _("Unable to create ") + fullFilename;
+        wxMessageBox( msg );
+        return;
+    }
+}

=== added file 'pcbnew/dialogs/dialog_export_idf_base.cpp'
--- pcbnew/dialogs/dialog_export_idf_base.cpp	1970-01-01 00:00:00 +0000
+++ pcbnew/dialogs/dialog_export_idf_base.cpp	2013-12-14 03:40:08 +0000
@@ -0,0 +1,49 @@
+///////////////////////////////////////////////////////////////////////////
+// C++ code generated with wxFormBuilder (version Oct  8 2012)
+// http://www.wxformbuilder.org/
+//
+// PLEASE DO "NOT" EDIT THIS FILE!
+///////////////////////////////////////////////////////////////////////////
+
+#include "dialog_export_idf_base.h"
+
+///////////////////////////////////////////////////////////////////////////
+
+DIALOG_EXPORT_IDF3_BASE::DIALOG_EXPORT_IDF3_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : DIALOG_SHIM( parent, id, title, pos, size, style )
+{
+	this->SetSizeHints( wxDefaultSize, wxDefaultSize );
+	
+	wxBoxSizer* bSizerIDFFile;
+	bSizerIDFFile = new wxBoxSizer( wxVERTICAL );
+	
+	m_txtBrdFile = new wxStaticText( this, wxID_ANY, wxT("IDF Board file"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_txtBrdFile->Wrap( -1 );
+	bSizerIDFFile->Add( m_txtBrdFile, 0, wxALL, 5 );
+	
+	m_filePickerIDF = new wxFilePickerCtrl( this, wxID_ANY, wxEmptyString, wxT("Select a board file"), wxT("*.emn"), wxDefaultPosition, wxDefaultSize, wxFLP_OVERWRITE_PROMPT|wxFLP_SAVE|wxFLP_USE_TEXTCTRL );
+	m_filePickerIDF->SetMinSize( wxSize( 420,30 ) );
+	
+	bSizerIDFFile->Add( m_filePickerIDF, 0, wxALL, 5 );
+	
+	m_chkThou = new wxCheckBox( this, wxID_ANY, wxT("unit: THOU"), wxDefaultPosition, wxDefaultSize, 0 );
+	bSizerIDFFile->Add( m_chkThou, 0, wxALL, 5 );
+	
+	m_sdbSizer1 = new wxStdDialogButtonSizer();
+	m_sdbSizer1OK = new wxButton( this, wxID_OK );
+	m_sdbSizer1->AddButton( m_sdbSizer1OK );
+	m_sdbSizer1Cancel = new wxButton( this, wxID_CANCEL );
+	m_sdbSizer1->AddButton( m_sdbSizer1Cancel );
+	m_sdbSizer1->Realize();
+	
+	bSizerIDFFile->Add( m_sdbSizer1, 1, wxEXPAND, 5 );
+	
+	
+	this->SetSizer( bSizerIDFFile );
+	this->Layout();
+	
+	this->Centre( wxBOTH );
+}
+
+DIALOG_EXPORT_IDF3_BASE::~DIALOG_EXPORT_IDF3_BASE()
+{
+}

=== added file 'pcbnew/dialogs/dialog_export_idf_base.fbp'
--- pcbnew/dialogs/dialog_export_idf_base.fbp	1970-01-01 00:00:00 +0000
+++ pcbnew/dialogs/dialog_export_idf_base.fbp	2013-12-14 03:40:08 +0000
@@ -0,0 +1,383 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<wxFormBuilder_Project>
+    <FileVersion major="1" minor="11" />
+    <object class="Project" expanded="1">
+        <property name="class_decoration"></property>
+        <property name="code_generation">C++</property>
+        <property name="disconnect_events">1</property>
+        <property name="disconnect_mode">source_name</property>
+        <property name="disconnect_php_events">0</property>
+        <property name="disconnect_python_events">0</property>
+        <property name="embedded_files_path">res</property>
+        <property name="encoding">UTF-8</property>
+        <property name="event_generation">connect</property>
+        <property name="file">dialog_export_idf_base</property>
+        <property name="first_id">1000</property>
+        <property name="help_provider">none</property>
+        <property name="internationalize">0</property>
+        <property name="name">dialog_export_idf3_base</property>
+        <property name="namespace"></property>
+        <property name="path">.</property>
+        <property name="precompiled_header"></property>
+        <property name="relative_path">1</property>
+        <property name="skip_php_events">1</property>
+        <property name="skip_python_events">1</property>
+        <property name="use_enum">1</property>
+        <property name="use_microsoft_bom">0</property>
+        <object class="Dialog" expanded="1">
+            <property name="aui_managed">0</property>
+            <property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
+            <property name="bg"></property>
+            <property name="center">wxBOTH</property>
+            <property name="context_help"></property>
+            <property name="context_menu">1</property>
+            <property name="enabled">1</property>
+            <property name="event_handler">impl_virtual</property>
+            <property name="extra_style"></property>
+            <property name="fg"></property>
+            <property name="font"></property>
+            <property name="hidden">0</property>
+            <property name="id">wxID_ANY</property>
+            <property name="maximum_size"></property>
+            <property name="minimum_size"></property>
+            <property name="name">DIALOG_EXPORT_IDF3_BASE</property>
+            <property name="pos"></property>
+            <property name="size">458,177</property>
+            <property name="style">wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</property>
+            <property name="subclass">DIALOG_SHIM; dialog_shim.h</property>
+            <property name="title">Export IDFv3</property>
+            <property name="tooltip"></property>
+            <property name="window_extra_style"></property>
+            <property name="window_name"></property>
+            <property name="window_style"></property>
+            <event name="OnActivate"></event>
+            <event name="OnActivateApp"></event>
+            <event name="OnAuiFindManager"></event>
+            <event name="OnAuiPaneButton"></event>
+            <event name="OnAuiPaneClose"></event>
+            <event name="OnAuiPaneMaximize"></event>
+            <event name="OnAuiPaneRestore"></event>
+            <event name="OnAuiRender"></event>
+            <event name="OnChar"></event>
+            <event name="OnClose"></event>
+            <event name="OnEnterWindow"></event>
+            <event name="OnEraseBackground"></event>
+            <event name="OnHibernate"></event>
+            <event name="OnIconize"></event>
+            <event name="OnIdle"></event>
+            <event name="OnInitDialog"></event>
+            <event name="OnKeyDown"></event>
+            <event name="OnKeyUp"></event>
+            <event name="OnKillFocus"></event>
+            <event name="OnLeaveWindow"></event>
+            <event name="OnLeftDClick"></event>
+            <event name="OnLeftDown"></event>
+            <event name="OnLeftUp"></event>
+            <event name="OnMiddleDClick"></event>
+            <event name="OnMiddleDown"></event>
+            <event name="OnMiddleUp"></event>
+            <event name="OnMotion"></event>
+            <event name="OnMouseEvents"></event>
+            <event name="OnMouseWheel"></event>
+            <event name="OnPaint"></event>
+            <event name="OnRightDClick"></event>
+            <event name="OnRightDown"></event>
+            <event name="OnRightUp"></event>
+            <event name="OnSetFocus"></event>
+            <event name="OnSize"></event>
+            <event name="OnUpdateUI"></event>
+            <object class="wxBoxSizer" expanded="1">
+                <property name="minimum_size"></property>
+                <property name="name">bSizerIDFFile</property>
+                <property name="orient">wxVERTICAL</property>
+                <property name="permission">none</property>
+                <object class="sizeritem" expanded="1">
+                    <property name="border">5</property>
+                    <property name="flag">wxALL</property>
+                    <property name="proportion">0</property>
+                    <object class="wxStaticText" expanded="1">
+                        <property name="BottomDockable">1</property>
+                        <property name="LeftDockable">1</property>
+                        <property name="RightDockable">1</property>
+                        <property name="TopDockable">1</property>
+                        <property name="aui_layer"></property>
+                        <property name="aui_name"></property>
+                        <property name="aui_position"></property>
+                        <property name="aui_row"></property>
+                        <property name="best_size"></property>
+                        <property name="bg"></property>
+                        <property name="caption"></property>
+                        <property name="caption_visible">1</property>
+                        <property name="center_pane">0</property>
+                        <property name="close_button">1</property>
+                        <property name="context_help"></property>
+                        <property name="context_menu">1</property>
+                        <property name="default_pane">0</property>
+                        <property name="dock">Dock</property>
+                        <property name="dock_fixed">0</property>
+                        <property name="docking">Left</property>
+                        <property name="enabled">1</property>
+                        <property name="fg"></property>
+                        <property name="floatable">1</property>
+                        <property name="font"></property>
+                        <property name="gripper">0</property>
+                        <property name="hidden">0</property>
+                        <property name="id">wxID_ANY</property>
+                        <property name="label">IDF Board file</property>
+                        <property name="max_size"></property>
+                        <property name="maximize_button">0</property>
+                        <property name="maximum_size"></property>
+                        <property name="min_size"></property>
+                        <property name="minimize_button">0</property>
+                        <property name="minimum_size"></property>
+                        <property name="moveable">1</property>
+                        <property name="name">m_txtBrdFile</property>
+                        <property name="pane_border">1</property>
+                        <property name="pane_position"></property>
+                        <property name="pane_size"></property>
+                        <property name="permission">protected</property>
+                        <property name="pin_button">1</property>
+                        <property name="pos"></property>
+                        <property name="resize">Resizable</property>
+                        <property name="show">1</property>
+                        <property name="size"></property>
+                        <property name="style"></property>
+                        <property name="subclass"></property>
+                        <property name="toolbar_pane">0</property>
+                        <property name="tooltip"></property>
+                        <property name="window_extra_style"></property>
+                        <property name="window_name"></property>
+                        <property name="window_style"></property>
+                        <property name="wrap">-1</property>
+                        <event name="OnChar"></event>
+                        <event name="OnEnterWindow"></event>
+                        <event name="OnEraseBackground"></event>
+                        <event name="OnKeyDown"></event>
+                        <event name="OnKeyUp"></event>
+                        <event name="OnKillFocus"></event>
+                        <event name="OnLeaveWindow"></event>
+                        <event name="OnLeftDClick"></event>
+                        <event name="OnLeftDown"></event>
+                        <event name="OnLeftUp"></event>
+                        <event name="OnMiddleDClick"></event>
+                        <event name="OnMiddleDown"></event>
+                        <event name="OnMiddleUp"></event>
+                        <event name="OnMotion"></event>
+                        <event name="OnMouseEvents"></event>
+                        <event name="OnMouseWheel"></event>
+                        <event name="OnPaint"></event>
+                        <event name="OnRightDClick"></event>
+                        <event name="OnRightDown"></event>
+                        <event name="OnRightUp"></event>
+                        <event name="OnSetFocus"></event>
+                        <event name="OnSize"></event>
+                        <event name="OnUpdateUI"></event>
+                    </object>
+                </object>
+                <object class="sizeritem" expanded="1">
+                    <property name="border">5</property>
+                    <property name="flag">wxALL</property>
+                    <property name="proportion">0</property>
+                    <object class="wxFilePickerCtrl" expanded="1">
+                        <property name="BottomDockable">1</property>
+                        <property name="LeftDockable">1</property>
+                        <property name="RightDockable">1</property>
+                        <property name="TopDockable">1</property>
+                        <property name="aui_layer"></property>
+                        <property name="aui_name"></property>
+                        <property name="aui_position"></property>
+                        <property name="aui_row"></property>
+                        <property name="best_size"></property>
+                        <property name="bg"></property>
+                        <property name="caption"></property>
+                        <property name="caption_visible">1</property>
+                        <property name="center_pane">0</property>
+                        <property name="close_button">1</property>
+                        <property name="context_help"></property>
+                        <property name="context_menu">1</property>
+                        <property name="default_pane">0</property>
+                        <property name="dock">Dock</property>
+                        <property name="dock_fixed">0</property>
+                        <property name="docking">Left</property>
+                        <property name="enabled">1</property>
+                        <property name="fg"></property>
+                        <property name="floatable">1</property>
+                        <property name="font"></property>
+                        <property name="gripper">0</property>
+                        <property name="hidden">0</property>
+                        <property name="id">wxID_ANY</property>
+                        <property name="max_size"></property>
+                        <property name="maximize_button">0</property>
+                        <property name="maximum_size"></property>
+                        <property name="message">Select a board file</property>
+                        <property name="min_size"></property>
+                        <property name="minimize_button">0</property>
+                        <property name="minimum_size">420,30</property>
+                        <property name="moveable">1</property>
+                        <property name="name">m_filePickerIDF</property>
+                        <property name="pane_border">1</property>
+                        <property name="pane_position"></property>
+                        <property name="pane_size"></property>
+                        <property name="permission">protected</property>
+                        <property name="pin_button">1</property>
+                        <property name="pos"></property>
+                        <property name="resize">Resizable</property>
+                        <property name="show">1</property>
+                        <property name="size"></property>
+                        <property name="style">wxFLP_OVERWRITE_PROMPT|wxFLP_SAVE|wxFLP_USE_TEXTCTRL</property>
+                        <property name="subclass"></property>
+                        <property name="toolbar_pane">0</property>
+                        <property name="tooltip"></property>
+                        <property name="validator_data_type"></property>
+                        <property name="validator_style">wxFILTER_NONE</property>
+                        <property name="validator_type">wxDefaultValidator</property>
+                        <property name="validator_variable"></property>
+                        <property name="value"></property>
+                        <property name="wildcard">*.emn</property>
+                        <property name="window_extra_style"></property>
+                        <property name="window_name"></property>
+                        <property name="window_style"></property>
+                        <event name="OnChar"></event>
+                        <event name="OnEnterWindow"></event>
+                        <event name="OnEraseBackground"></event>
+                        <event name="OnFileChanged"></event>
+                        <event name="OnKeyDown"></event>
+                        <event name="OnKeyUp"></event>
+                        <event name="OnKillFocus"></event>
+                        <event name="OnLeaveWindow"></event>
+                        <event name="OnLeftDClick"></event>
+                        <event name="OnLeftDown"></event>
+                        <event name="OnLeftUp"></event>
+                        <event name="OnMiddleDClick"></event>
+                        <event name="OnMiddleDown"></event>
+                        <event name="OnMiddleUp"></event>
+                        <event name="OnMotion"></event>
+                        <event name="OnMouseEvents"></event>
+                        <event name="OnMouseWheel"></event>
+                        <event name="OnPaint"></event>
+                        <event name="OnRightDClick"></event>
+                        <event name="OnRightDown"></event>
+                        <event name="OnRightUp"></event>
+                        <event name="OnSetFocus"></event>
+                        <event name="OnSize"></event>
+                        <event name="OnUpdateUI"></event>
+                    </object>
+                </object>
+                <object class="sizeritem" expanded="1">
+                    <property name="border">5</property>
+                    <property name="flag">wxALL</property>
+                    <property name="proportion">0</property>
+                    <object class="wxCheckBox" expanded="1">
+                        <property name="BottomDockable">1</property>
+                        <property name="LeftDockable">1</property>
+                        <property name="RightDockable">1</property>
+                        <property name="TopDockable">1</property>
+                        <property name="aui_layer"></property>
+                        <property name="aui_name"></property>
+                        <property name="aui_position"></property>
+                        <property name="aui_row"></property>
+                        <property name="best_size"></property>
+                        <property name="bg"></property>
+                        <property name="caption"></property>
+                        <property name="caption_visible">1</property>
+                        <property name="center_pane">0</property>
+                        <property name="checked">0</property>
+                        <property name="close_button">1</property>
+                        <property name="context_help"></property>
+                        <property name="context_menu">1</property>
+                        <property name="default_pane">0</property>
+                        <property name="dock">Dock</property>
+                        <property name="dock_fixed">0</property>
+                        <property name="docking">Left</property>
+                        <property name="enabled">1</property>
+                        <property name="fg"></property>
+                        <property name="floatable">1</property>
+                        <property name="font"></property>
+                        <property name="gripper">0</property>
+                        <property name="hidden">0</property>
+                        <property name="id">wxID_ANY</property>
+                        <property name="label">unit: THOU</property>
+                        <property name="max_size"></property>
+                        <property name="maximize_button">0</property>
+                        <property name="maximum_size"></property>
+                        <property name="min_size"></property>
+                        <property name="minimize_button">0</property>
+                        <property name="minimum_size"></property>
+                        <property name="moveable">1</property>
+                        <property name="name">m_chkThou</property>
+                        <property name="pane_border">1</property>
+                        <property name="pane_position"></property>
+                        <property name="pane_size"></property>
+                        <property name="permission">protected</property>
+                        <property name="pin_button">1</property>
+                        <property name="pos"></property>
+                        <property name="resize">Resizable</property>
+                        <property name="show">1</property>
+                        <property name="size"></property>
+                        <property name="style"></property>
+                        <property name="subclass"></property>
+                        <property name="toolbar_pane">0</property>
+                        <property name="tooltip"></property>
+                        <property name="validator_data_type"></property>
+                        <property name="validator_style">wxFILTER_NONE</property>
+                        <property name="validator_type">wxDefaultValidator</property>
+                        <property name="validator_variable"></property>
+                        <property name="window_extra_style"></property>
+                        <property name="window_name"></property>
+                        <property name="window_style"></property>
+                        <event name="OnChar"></event>
+                        <event name="OnCheckBox"></event>
+                        <event name="OnEnterWindow"></event>
+                        <event name="OnEraseBackground"></event>
+                        <event name="OnKeyDown"></event>
+                        <event name="OnKeyUp"></event>
+                        <event name="OnKillFocus"></event>
+                        <event name="OnLeaveWindow"></event>
+                        <event name="OnLeftDClick"></event>
+                        <event name="OnLeftDown"></event>
+                        <event name="OnLeftUp"></event>
+                        <event name="OnMiddleDClick"></event>
+                        <event name="OnMiddleDown"></event>
+                        <event name="OnMiddleUp"></event>
+                        <event name="OnMotion"></event>
+                        <event name="OnMouseEvents"></event>
+                        <event name="OnMouseWheel"></event>
+                        <event name="OnPaint"></event>
+                        <event name="OnRightDClick"></event>
+                        <event name="OnRightDown"></event>
+                        <event name="OnRightUp"></event>
+                        <event name="OnSetFocus"></event>
+                        <event name="OnSize"></event>
+                        <event name="OnUpdateUI"></event>
+                    </object>
+                </object>
+                <object class="sizeritem" expanded="1">
+                    <property name="border">5</property>
+                    <property name="flag">wxEXPAND</property>
+                    <property name="proportion">1</property>
+                    <object class="wxStdDialogButtonSizer" expanded="1">
+                        <property name="Apply">0</property>
+                        <property name="Cancel">1</property>
+                        <property name="ContextHelp">0</property>
+                        <property name="Help">0</property>
+                        <property name="No">0</property>
+                        <property name="OK">1</property>
+                        <property name="Save">0</property>
+                        <property name="Yes">0</property>
+                        <property name="minimum_size"></property>
+                        <property name="name">m_sdbSizer1</property>
+                        <property name="permission">protected</property>
+                        <event name="OnApplyButtonClick"></event>
+                        <event name="OnCancelButtonClick"></event>
+                        <event name="OnContextHelpButtonClick"></event>
+                        <event name="OnHelpButtonClick"></event>
+                        <event name="OnNoButtonClick"></event>
+                        <event name="OnOKButtonClick"></event>
+                        <event name="OnSaveButtonClick"></event>
+                        <event name="OnYesButtonClick"></event>
+                    </object>
+                </object>
+            </object>
+        </object>
+    </object>
+</wxFormBuilder_Project>

=== added file 'pcbnew/dialogs/dialog_export_idf_base.h'
--- pcbnew/dialogs/dialog_export_idf_base.h	1970-01-01 00:00:00 +0000
+++ pcbnew/dialogs/dialog_export_idf_base.h	2013-12-14 03:40:08 +0000
@@ -0,0 +1,52 @@
+///////////////////////////////////////////////////////////////////////////
+// C++ code generated with wxFormBuilder (version Oct  8 2012)
+// http://www.wxformbuilder.org/
+//
+// PLEASE DO "NOT" EDIT THIS FILE!
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef __DIALOG_EXPORT_IDF_BASE_H__
+#define __DIALOG_EXPORT_IDF_BASE_H__
+
+#include <wx/artprov.h>
+#include <wx/xrc/xmlres.h>
+class DIALOG_SHIM;
+
+#include "dialog_shim.h"
+#include <wx/string.h>
+#include <wx/stattext.h>
+#include <wx/gdicmn.h>
+#include <wx/font.h>
+#include <wx/colour.h>
+#include <wx/settings.h>
+#include <wx/filepicker.h>
+#include <wx/checkbox.h>
+#include <wx/sizer.h>
+#include <wx/button.h>
+#include <wx/dialog.h>
+
+///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+/// Class DIALOG_EXPORT_IDF3_BASE
+///////////////////////////////////////////////////////////////////////////////
+class DIALOG_EXPORT_IDF3_BASE : public DIALOG_SHIM
+{
+	private:
+	
+	protected:
+		wxStaticText* m_txtBrdFile;
+		wxFilePickerCtrl* m_filePickerIDF;
+		wxCheckBox* m_chkThou;
+		wxStdDialogButtonSizer* m_sdbSizer1;
+		wxButton* m_sdbSizer1OK;
+		wxButton* m_sdbSizer1Cancel;
+	
+	public:
+		
+		DIALOG_EXPORT_IDF3_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Export IDFv3"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 458,177 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); 
+		~DIALOG_EXPORT_IDF3_BASE();
+	
+};
+
+#endif //__DIALOG_EXPORT_IDF_BASE_H__

=== added file 'pcbnew/export_idf.cpp'
--- pcbnew/export_idf.cpp	1970-01-01 00:00:00 +0000
+++ pcbnew/export_idf.cpp	2013-12-15 09:33:54 +0000
@@ -0,0 +1,332 @@
+/**
+ * @file export_idf.cpp
+ */
+
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2013  Cirilo Bernardo
+ *
+ * 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 <list>
+#include <wxPcbStruct.h>
+#include <macros.h>
+#include <pcbnew.h>
+#include <class_board.h>
+#include <class_module.h>
+#include <class_edge_mod.h>
+#include <idf.h>
+
+// assumed default graphical line thickness: 10000 IU == 0.1mm
+#define LINE_WIDTH (100000)
+
+/**
+ * Function idf_export_outline
+ * retrieves line segment information from the edge layer and compiles
+ * the data into a form which can be output as an IDFv3 compliant
+ * BOARD_OUTLINE section.
+ */
+static void idf_export_outline( BOARD* aPcb, IDF_BOARD& aIDFBoard )
+{
+    double scale = aIDFBoard.GetScale();
+
+    DRAWSEGMENT* graphic;               // KiCad graphical item
+    IDF_POINT sp, ep;                   // start and end points from KiCad item
+
+    std::list< IDF_SEGMENT* > lines;    // IDF intermediate form of KiCad graphical item
+    IDF_OUTLINE outline;                // graphical items forming an outline or cutout
+
+    // NOTE: IMPLEMENTATION
+    // If/when component cutouts are allowed, we must implement them separately. Cutouts
+    // must be added to the board outline section and not to the Other Outline section.
+    // The module cutouts should be handled via the idf_export_module() routine.
+
+    // Retrieve segments and arcs from the board
+    for( BOARD_ITEM* item = aPcb->m_Drawings; item; item = item->Next() )
+    {
+        if( item->Type() != PCB_LINE_T || item->GetLayer() != EDGE_N )
+            continue;
+
+        graphic = (DRAWSEGMENT*) item;
+
+        switch( graphic->GetShape() )
+        {
+        case S_SEGMENT:
+            {
+                sp.x    = graphic->GetStart().x * scale;
+                sp.y    = graphic->GetStart().y * scale;
+                ep.x    = graphic->GetEnd().x * scale;
+                ep.y    = graphic->GetEnd().y * scale;
+                IDF_SEGMENT* seg = new IDF_SEGMENT( sp, ep );
+
+                if( seg )
+                    lines.push_back( seg );
+            }
+            break;
+
+        case S_ARC:
+            {
+                sp.x = graphic->GetCenter().x * scale;
+                sp.y = graphic->GetCenter().y * scale;
+                ep.x = graphic->GetArcStart().x * scale;
+                ep.y = graphic->GetArcStart().y * scale;
+                IDF_SEGMENT* seg = new IDF_SEGMENT( sp, ep, graphic->GetAngle() / 10.0, true );
+
+                if( seg )
+                    lines.push_back( seg );
+            }
+            break;
+
+        case S_CIRCLE:
+            {
+                sp.x = graphic->GetCenter().x * scale;
+                sp.y = graphic->GetCenter().y * scale;
+                ep.x = sp.x - graphic->GetRadius() * scale;
+                ep.y = sp.y;
+                // Circles must always have an angle of +360 deg. to appease
+                // quirky MCAD implementations of IDF.
+                IDF_SEGMENT* seg = new IDF_SEGMENT( sp, ep, 360.0, true );
+
+                if( seg )
+                    lines.push_back( seg );
+            }
+            break;
+
+        default:
+            break;
+        }
+    }
+
+    // if there is no outline then use the bounding box
+    if( lines.empty() )
+    {
+        goto UseBoundingBox;
+    }
+
+    // get the board outline and write it out
+    // note: we do not use a try/catch block here since we intend
+    // to simply ignore unclosed loops and continue processing
+    // until we're out of segments to process
+    IDF3::GetOutline( lines, outline );
+
+    if( outline.empty() )
+        goto UseBoundingBox;
+
+    aIDFBoard.AddOutline( outline );
+
+    // get all cutouts and write them out
+    while( !lines.empty() )
+    {
+        IDF3::GetOutline( lines, outline );
+
+        if( outline.empty() )
+            continue;
+
+        aIDFBoard.AddOutline( outline );
+    }
+
+    return;
+
+UseBoundingBox:
+
+    // clean up if necessary
+    while( !lines.empty() )
+    {
+        delete lines.front();
+        lines.pop_front();
+    }
+
+    outline.Clear();
+
+    // fetch a rectangular bounding box for the board;
+    // there is always some uncertainty in the board dimensions
+    // computed via ComputeBoundingBox() since this depends on the
+    // individual module entities.
+    EDA_RECT bbbox = aPcb->ComputeBoundingBox( true );
+
+    // convert to mm and compensate for an assumed LINE_WIDTH line thickness
+    double  x   = ( bbbox.GetOrigin().x + LINE_WIDTH / 2 ) * scale;
+    double  y   = ( bbbox.GetOrigin().y + LINE_WIDTH / 2 ) * scale;
+    double  dx  = ( bbbox.GetSize().x - LINE_WIDTH ) * scale;
+    double  dy  = ( bbbox.GetSize().y - LINE_WIDTH ) * scale;
+
+    double px[4], py[4];
+    px[0]   = x;
+    py[0]   = y;
+
+    px[1]   = x;
+    py[1]   = y + dy;
+
+    px[2]   = x + dx;
+    py[2]   = y + dy;
+
+    px[3]   = x + dx;
+    py[3]   = y;
+
+    IDF_POINT p1, p2;
+
+    p1.x    = px[3];
+    p1.y    = py[3];
+    p2.x    = px[0];
+    p2.y    = py[0];
+
+    outline.push( new IDF_SEGMENT( p1, p2 ) );
+
+    for( int i = 1; i < 4; ++i )
+    {
+        p1.x    = px[i - 1];
+        p1.y    = py[i - 1];
+        p2.x    = px[i];
+        p2.y    = py[i];
+        
+        outline.push( new IDF_SEGMENT( p1, p2 ) );
+    }
+
+    aIDFBoard.AddOutline( outline );
+}
+
+
+/**
+ * Function idf_export_module
+ * retrieves information from all board modules, adds drill holes to
+ * the DRILLED_HOLES or BOARD_OUTLINE section as appropriate,
+ * compiles data for the PLACEMENT section and compiles data for
+ * the library ELECTRICAL section.
+ */
+static void idf_export_module( BOARD* aPcb, MODULE* aModule,
+        IDF_BOARD& aIDFBoard )
+{
+    // Reference Designator
+    std::string crefdes = TO_UTF8( aModule->GetReference() );
+
+    if( crefdes.empty() || !crefdes.compare( "~" ) )
+    {
+        std::string cvalue = TO_UTF8( aModule->GetValue() );
+
+        // if both the RefDes and Value are empty or set to '~' the board owns the part,
+        // otherwise associated parts of the module must be marked NOREFDES.
+        if( cvalue.empty() || !cvalue.compare( "~" ) )
+            crefdes = "BOARD";
+        else
+            crefdes = "NOREFDES";
+    }
+
+    // TODO: If module cutouts are supported we must add code here
+    // for( EDA_ITEM* item = aModule->GraphicalItems();  item != NULL;  item = item->Next() )
+    // {
+    // if( ( item->Type() != PCB_MODULE_EDGE_T )
+    // || (item->GetLayer() != EDGE_N ) ) continue;
+    // code to export cutouts
+    // }
+
+    // Export pads
+    double  drill, x, y;
+    double  scale = aIDFBoard.GetScale();
+    IDF3::KEY_PLATING kplate;
+    std::string pintype;
+    std::string tstr;
+
+    for( D_PAD* pad = aModule->Pads(); pad; pad = pad->Next() )
+    {
+        drill = (double) pad->GetDrillSize().x * scale;
+        x     = pad->GetPosition().x * scale;
+        y     = pad->GetPosition().y * scale;
+
+        // Export the hole on the edge layer
+        if( drill > 0.0 )
+        {
+            // plating
+            if( pad->GetAttribute() == PAD_HOLE_NOT_PLATED )
+                kplate = IDF3::NPTH;
+            else
+                kplate = IDF3::PTH;
+
+            // hole type
+            tstr = TO_UTF8( pad->GetPadName() );
+
+            if( tstr.empty() || !tstr.compare( "0" ) || !tstr.compare( "~" )
+                || ( kplate == IDF3::NPTH ) )
+                pintype = "MTG";
+            else
+                pintype = "PIN";
+
+            // fields:
+            // 1. hole dia. : float
+            // 2. X coord : float
+            // 3. Y coord : float
+            // 4. plating : PTH | NPTH
+            // 5. Assoc. part : BOARD | NOREFDES | PANEL | {"refdes"}
+            // 6. type : PIN | VIA | MTG | TOOL | { "other" }
+            // 7. owner : MCAD | ECAD | UNOWNED
+            if( pad->GetDrillShape() == PAD_OVAL )
+            {
+                // NOTE: IDF does not have direct support for slots;
+                // slots are implemented as a board cutout and we
+                // cannot represent plating or reference designators
+
+                double dlength = pad->GetDrillSize().y * scale;
+
+                if( dlength < drill )
+                    std::swap( drill, dlength );
+
+                aIDFBoard.AddSlot( drill, dlength, pad->GetOrientation() / 10.0, x, y );
+            }
+            else
+            {
+                aIDFBoard.AddDrill( drill, x, y, kplate, crefdes, pintype, IDF3::ECAD );
+            }
+        }
+    }
+
+    // TODO
+    // add to the library item list
+}
+
+
+/**
+ * Function Export_IDF3
+ * generates IDFv3 compliant board (*.emn) and library (*.emp)
+ * files representing the user's PCB design.
+ */
+bool Export_IDF3( BOARD* aPcb, const wxString& aFullFileName, double aUseThou )
+{
+    IDF_BOARD idfBoard;
+
+    SetLocaleTo_C_standard();
+
+    // NOTE:
+    // XXX We may enclose all this in a TRY .. CATCH block
+    idfBoard.Setup( aPcb->GetFileName(), aFullFileName, aUseThou,
+            aPcb->GetDesignSettings().GetBoardThickness() );
+
+    // Export the board outline
+    idf_export_outline( aPcb, idfBoard );
+
+    // Output the drill holes and module (library) data.
+    for( MODULE* module = aPcb->m_Modules; module != 0; module = module->Next() )
+        idf_export_module( aPcb, module, idfBoard );
+
+    idfBoard.Finish();
+
+    SetLocaleTo_Default();
+
+    return true;
+}

=== added file 'pcbnew/idf.cpp'
--- pcbnew/idf.cpp	1970-01-01 00:00:00 +0000
+++ pcbnew/idf.cpp	2013-12-15 23:58:22 +0000
@@ -0,0 +1,990 @@
+/**
+ * file: idf.cpp
+ *
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2013  Cirilo Bernardo
+ *
+ * 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
+ */
+
+// TODO: Consider using different precision formats for THOU vs MM output
+// Keep in mind that THOU cannot represent MM very well although MM can
+// represent 1 THOU with 4 decimal places. For modern manufacturing we
+// are interested in a resolution of about 0.1 THOU.
+
+#include <list>
+#include <string>
+#include <algorithm>
+#include <cstdio>
+#include <cmath>
+#include <ctime>
+#include <wx/filename.h>
+#include <macros.h>
+#include <idf.h>
+#include <build_version.h>
+
+// differences in angle smaller than MIN_ANG are considered equal
+#define MIN_ANG     (0.01)
+// minimum drill diameter (nanometers) - 10000 is a 0.01mm drill
+#define IDF_MIN_DIA ( 10000.0 )
+
+// minimum board thickness; this is about 0.012mm (0.5 mils)
+// which is about the thickness of a single kapton layer typically
+// used in a flexible design.
+#define IDF_MIN_BRD_THICKNESS (12000)
+
+bool IDF_POINT::Matches( const IDF_POINT& aPoint, double aRadius )
+{
+    double dx = x - aPoint.x;
+    double dy = y - aPoint.y;
+
+    double d2 = dx * dx + dy * dy;
+
+    if( d2 <= aRadius * aRadius )
+        return true;
+
+    return false;
+}
+
+
+double IDF_POINT::CalcDistance( const IDF_POINT& aPoint ) const
+{
+    double dx   = aPoint.x - x;
+    double dy   = aPoint.y - y;
+    double dist = sqrt( dx * dx + dy * dy );
+
+    return dist;
+}
+
+
+double IDF3::CalcAngleRad( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint )
+{
+    // calculate the angle between the start point (center) and end point
+    double ang;
+    double dx = aEndPoint.x - aStartPoint.x;
+    double dy = aEndPoint.y - aStartPoint.y;
+
+    if( ( dx * dx ) < ( 0.1 * dy * dy ) )
+    {
+        // we have a steep dY/dX; use an alternative calculation of the angle
+        ang = M_PI2 - atan( dx / dy );
+
+        if( dy < 0.0 )
+            ang += M_PI;
+    }
+    else
+    {
+        ang = atan( dy / dx );
+
+        if( dx < 0.0 )
+        {
+            if( dy < 0.0 )
+                ang -= M_PI;
+            else
+                ang += M_PI;
+        }
+    }
+
+    return ang;
+}
+
+
+double IDF3::CalcAngleDeg( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint )
+{
+    double ang = CalcAngleRad( aStartPoint, aEndPoint );
+
+    // round to thousandths of a degree
+    int iang = int (ang / M_PI * 1800000.0);
+
+    ang = iang / 10000.0;
+
+    return ang;
+}
+
+
+IDF_SEGMENT::IDF_SEGMENT()
+{
+    angle = 0.0;
+    offsetAngle = 0.0;
+    radius = 0.0;
+}
+
+
+IDF_SEGMENT::IDF_SEGMENT( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint )
+{
+    angle = 0.0;
+    offsetAngle = 0.0;
+    radius = 0.0;
+    startPoint = aStartPoint;
+    endPoint = aEndPoint;
+}
+
+
+IDF_SEGMENT::IDF_SEGMENT( const IDF_POINT& aStartPoint,
+        const IDF_POINT& aEndPoint,
+        double aAngle,
+        bool aFromKicad )
+{
+    double diff = abs( aAngle ) - 360.0;
+
+    if( ( diff < MIN_ANG
+          && diff > -MIN_ANG ) || ( aAngle < MIN_ANG && aAngle > -MIN_ANG ) || (!aFromKicad) )
+    {
+        angle = 0.0;
+        startPoint = aStartPoint;
+        endPoint = aEndPoint;
+
+        if( diff < MIN_ANG && diff > -MIN_ANG )
+        {
+            angle = 360.0;
+            center = aStartPoint;
+            offsetAngle = 0.0;
+            radius = aStartPoint.CalcDistance( aEndPoint );
+        }
+        else if( aAngle < MIN_ANG && aAngle > -MIN_ANG )
+        {
+            CalcCenterAndRadius();
+        }
+
+        return;
+    }
+
+    // we need to convert from the KiCad arc convention
+    angle = aAngle;
+
+    center = aStartPoint;
+
+    offsetAngle = IDF3::CalcAngleDeg( aStartPoint, aEndPoint );
+
+    radius = aStartPoint.CalcDistance( aEndPoint );
+
+    startPoint = aEndPoint;
+
+    double ang = offsetAngle + aAngle;
+    ang = (ang / 180.0) * M_PI;
+
+    endPoint.x  = ( radius * cos( ang ) ) + center.x;
+    endPoint.y  = ( radius * sin( ang ) ) + center.y;
+}
+
+
+bool IDF_SEGMENT::MatchesStart( const IDF_POINT& aPoint, double aRadius )
+{
+    return startPoint.Matches( aPoint, aRadius );
+}
+
+
+bool IDF_SEGMENT::MatchesEnd( const IDF_POINT& aPoint, double aRadius )
+{
+    return endPoint.Matches( aPoint, aRadius );
+}
+
+
+void IDF_SEGMENT::CalcCenterAndRadius( void )
+{
+    // NOTE:  this routine does not check if the points are the same
+    // or too close to be sensible in a production setting.
+
+    double offAng = IDF3::CalcAngleRad( startPoint, endPoint );
+    double d = startPoint.CalcDistance( endPoint ) / 2.0;
+    double xm   = ( startPoint.x + endPoint.x ) * 0.5;
+    double ym   = ( startPoint.y + endPoint.y ) * 0.5;
+
+    radius = d / sin( angle * M_PI / 180.0 );
+
+    if( radius < 0.0 )
+    {
+        radius = -radius;
+    }
+
+    // calculate the height of the triangle with base d and hypotenuse r
+    double dh2 = radius * radius - d * d;
+
+    if( dh2 < 0 )
+    {
+        // this should only ever happen due to rounding errors when r == d
+        dh2 = 0;
+    }
+
+    double h = sqrt( dh2 );
+
+    if( angle > 0.0 )
+        offAng += M_PI2;
+    else
+        offAng -= M_PI2;
+
+    if( ( angle > M_PI ) || ( angle < -M_PI ) )
+        offAng += M_PI;
+
+    center.x = h * cos( offAng ) + xm;
+    center.y = h * sin( offAng ) + ym;
+
+    offsetAngle = IDF3::CalcAngleDeg( center, startPoint );
+}
+
+
+bool IDF_SEGMENT::IsCircle( void )
+{
+    double diff = abs( angle ) - 360.0;
+
+    if( ( diff < MIN_ANG ) && ( diff > -MIN_ANG ) )
+        return true;
+
+    return false;
+}
+
+
+double IDF_SEGMENT::GetMinX( void )
+{
+    if( angle == 0.0 )
+        return std::min( startPoint.x, endPoint.x );
+
+    // Calculate the leftmost point of the circle or arc
+
+    if( IsCircle() )
+    {
+        // if only everything were this easy
+        return center.x - radius;
+    }
+
+    // cases:
+    // 1. CCW arc: if offset + included angle >= 180 deg then
+    // MinX = center.x - radius, otherwise MinX is the
+    // same as for the case of a line.
+    // 2. CW arc: if offset + included angle <= -180 deg then
+    // MinX = center.x - radius, otherwise MinX is the
+    // same as for the case of a line.
+
+    if( angle > 0 )
+    {
+        // CCW case
+        if( ( offsetAngle + angle ) >= 180.0 )
+        {
+            return center.x - radius;
+        }
+        else
+        {
+            return std::min( startPoint.x, endPoint.x );
+        }
+    }
+
+    // CW case
+    if( ( offsetAngle + angle ) <= -180.0 )
+    {
+        return center.x - radius;
+    }
+
+    return std::min( startPoint.x, endPoint.x );
+}
+
+
+void IDF_SEGMENT::SwapEnds( void )
+{
+    if( IsCircle() )
+    {
+        // reverse the direction
+        angle = -angle;
+        return;
+    }
+
+    IDF_POINT tmp = startPoint;
+    startPoint = endPoint;
+    endPoint = tmp;
+
+    if( ( angle < MIN_ANG ) && ( angle > -MIN_ANG ) )
+        return;         // nothing more to do
+
+    // change the direction of the arc
+    angle = -angle;
+    // calculate the new offset angle
+    offsetAngle = IDF3::CalcAngleDeg( center, startPoint );
+}
+
+
+IDF_DRILL_DATA::IDF_DRILL_DATA( double aDrillDia, double aPosX, double aPosY,
+        IDF3::KEY_PLATING aPlating,
+        const std::string aRefDes,
+        const std::string aHoleType,
+        IDF3::KEY_OWNER aOwner )
+{
+    if( aDrillDia < 0.3 )
+        dia = 0.3;
+    else
+        dia = aDrillDia;
+
+    x = aPosX;
+    y = aPosY;
+    plating = aPlating;
+
+    if( !aRefDes.compare( "BOARD" ) )
+    {
+        kref = IDF3::BOARD;
+    }
+    else if( aRefDes.empty() || !aRefDes.compare( "NOREFDES" ) )
+    {
+        kref = IDF3::NOREFDES;
+    }
+    else if( !aRefDes.compare( "PANEL" ) )
+    {
+        kref = IDF3::PANEL;
+    }
+    else
+    {
+        kref = IDF3::REFDES;
+        refdes = aRefDes;
+    }
+
+    if( !aHoleType.compare( "PIN" ) )
+    {
+        khole = IDF3::PIN;
+    }
+    else if( !aHoleType.compare( "VIA" ) )
+    {
+        khole = IDF3::VIA;
+    }
+    else if( aHoleType.empty() || !aHoleType.compare( "MTG" ) )
+    {
+        khole = IDF3::MTG;
+    }
+    else if( !aHoleType.compare( "TOOL" ) )
+    {
+        khole = IDF3::TOOL;
+    }
+    else
+    {
+        khole = IDF3::OTHER;
+        holetype = aHoleType;
+    }
+
+    owner = aOwner;
+}    // IDF_DRILL_DATA::IDF_DRILL_DATA( ... )
+
+
+bool IDF_DRILL_DATA::Write( FILE* aLayoutFile )
+{
+    // TODO: check stream integrity and return 'false' as appropriate
+
+    if( !aLayoutFile )
+        return false;
+
+    std::string holestr;
+    std::string refstr;
+    std::string ownstr;
+    std::string pltstr;
+
+    switch( khole )
+    {
+    case IDF3::PIN:
+        holestr = "PIN";
+        break;
+
+    case IDF3::VIA:
+        holestr = "VIA";
+        break;
+
+    case IDF3::TOOL:
+        holestr = "TOOL";
+        break;
+
+    case IDF3::OTHER:
+        holestr = "\"" + holetype + "\"";
+        break;
+
+    default:
+        holestr = "MTG";
+        break;
+    }
+
+    switch( kref )
+    {
+    case IDF3::BOARD:
+        refstr = "BOARD";
+        break;
+
+    case IDF3::PANEL:
+        refstr = "PANEL";
+        break;
+
+    case IDF3::REFDES:
+        refstr = "\"" + refdes + "\"";
+        break;
+
+    default:
+        refstr = "NOREFDES";
+        break;
+    }
+
+    if( plating == IDF3::PTH )
+        pltstr = "PTH";
+    else
+        pltstr = "NPTH";
+
+    switch( owner )
+    {
+    case IDF3::MCAD:
+        ownstr = "MCAD";
+        break;
+
+    case IDF3::ECAD:
+        ownstr = "ECAD";
+        break;
+
+    default:
+        ownstr = "UNOWNED";
+    }
+
+    fprintf( aLayoutFile, "%.3f %.5f %.5f %s %s %s %s\n",
+            dia, x, y, pltstr.c_str(), refstr.c_str(), holestr.c_str(), ownstr.c_str() );
+
+    return true;
+}    // IDF_DRILL_DATA::Write( aLayoutFile )
+
+
+IDF_BOARD::IDF_BOARD()
+{
+    outlineIndex = 0;
+    scale = 1e-6;
+    boardThickness = 1.6;       // default to 1.6mm thick boards
+
+    useThou = false;            // by default we want mm output
+    hasBrdOutlineHdr = false;
+
+    layoutFile = NULL;
+    libFile = NULL;
+}
+
+
+IDF_BOARD::~IDF_BOARD()
+{
+    Finish();
+}
+
+
+bool IDF_BOARD::Setup( wxString aBoardName,
+        wxString aFullFileName,
+        bool aUseThou,
+        int aBoardThickness )
+{
+    if( aBoardThickness < IDF_MIN_BRD_THICKNESS )
+        return false;
+
+    if( aUseThou )
+    {
+        useThou = true;
+        scale = 1e-3 / 25.4;
+    }
+    else
+    {
+        useThou = false;
+        scale = 1e-6;
+    }
+
+    boardThickness = aBoardThickness * scale;
+
+    wxFileName brdname( aBoardName );
+    wxFileName idfname( aFullFileName );
+
+    // open the layout file
+    idfname.SetExt( wxT( "emn" ) );
+    layoutFile = wxFopen( aFullFileName, wxT( "wt" ) );
+
+    if( layoutFile == NULL )
+        return false;
+
+    // open the library file
+    idfname.SetExt( wxT( "emp" ) );
+    libFile = wxFopen( idfname.GetFullPath(), wxT( "wt" ) );
+
+    if( libFile == NULL )
+    {
+        fclose( layoutFile );
+        layoutFile = NULL;
+        return false;
+    }
+
+
+    time_t date;
+    time( &date );
+    struct tm tdate;
+
+    time( &date );
+    localtime_r( &date, &tdate );
+
+    fprintf( layoutFile, ".HEADER\n"
+                         "BOARD_FILE 3.0 \"Created by KiCad %s\""
+                         " %.4d/%.2d/%.2d.%.2d:%.2d:%.2d 1\n"
+                         "\"%s\" %s\n"
+                         ".END_HEADER\n\n",
+            TO_UTF8( GetBuildVersion() ),
+            tdate.tm_year + 1900, tdate.tm_mon + 1, tdate.tm_mday,
+            tdate.tm_hour, tdate.tm_min, tdate.tm_sec,
+            TO_UTF8( brdname.GetFullName() ), useThou ? "THOU" : "MM" );
+
+    fprintf( libFile, ".HEADER\n"
+                      "BOARD_FILE 3.0 \"Created by KiCad %s\" %.4d/%.2d/%.2d.%.2d:%.2d:%.2d 1\n"
+                      ".END_HEADER\n\n",
+            TO_UTF8( GetBuildVersion() ),
+            tdate.tm_year + 1900, tdate.tm_mon + 1, tdate.tm_mday,
+            tdate.tm_hour, tdate.tm_min, tdate.tm_sec );
+
+    return true;
+}
+
+
+bool IDF_BOARD::Finish( void )
+{
+    // Steps to finalize the board and library files:
+    // 1. (emp) finalize the library file
+    // 2. (emn) close the BOARD_OUTLINE section
+    // 3. (emn) write out the DRILLED_HOLES section
+    // 4. (emn) write out the COMPONENT_PLACEMENT section
+
+    // TODO:
+    // idfLib.Finish();
+    if( libFile != NULL )
+    {
+        fclose( libFile );
+        libFile = NULL;
+    }
+
+    if( layoutFile == NULL )
+        return false;
+
+    // Finalize the board outline section
+    fprintf( layoutFile, ".END_BOARD_OUTLINE\n\n" );
+
+    // Write out the drill section
+    if( WriteDrills() )
+    {
+        fclose( layoutFile );
+        layoutFile = NULL;
+        return false;
+    }
+
+    // TODO: Write out the component placement section
+    // IDF3::export_placement();
+
+    fclose( layoutFile );
+    layoutFile = NULL;
+
+    return true;
+}
+
+
+bool IDF_BOARD::AddOutline( IDF_OUTLINE& aOutline )
+{
+    if( !layoutFile )
+        return false;
+
+    // TODO: check the stream integrity
+
+    std::list<IDF_SEGMENT*>::iterator bo;
+    std::list<IDF_SEGMENT*>::iterator eo;
+
+    if( !hasBrdOutlineHdr )
+    {
+        fprintf( layoutFile, ".BOARD_OUTLINE ECAD\n%.5f\n", boardThickness );
+        hasBrdOutlineHdr = true;
+    }
+
+    if( aOutline.size() == 1 )
+    {
+        if( !aOutline.front()->IsCircle() )
+            return false;                   // this is a bad outline
+
+        // NOTE: a circle always has an angle of 360, never -360,
+        // otherwise SolidWorks chokes on the file.
+        fprintf( layoutFile, "%d %.5f %.5f 0\n", outlineIndex,
+                aOutline.front()->startPoint.x, aOutline.front()->startPoint.y );
+        fprintf( layoutFile, "%d %.5f %.5f 360\n", outlineIndex,
+                aOutline.front()->endPoint.x, aOutline.front()->endPoint.y );
+
+        ++outlineIndex;
+        return true;
+    }
+
+    // ensure that the very last point is the same as the very first point
+    aOutline.back()-> endPoint = aOutline.front()->startPoint;
+
+    // check if we must reverse things
+    if( ( aOutline.IsCCW() && ( outlineIndex > 0 ) )
+        || ( ( !aOutline.IsCCW() ) && ( outlineIndex == 0 ) ) )
+    {
+        eo  = aOutline.begin();
+        bo  = aOutline.end();
+        --bo;
+
+        // for the first item we write out both points
+        if( aOutline.front()->angle < MIN_ANG && aOutline.front()->angle > -MIN_ANG )
+        {
+            fprintf( layoutFile, "%d %.5f %.5f 0\n", outlineIndex,
+                    aOutline.front()->endPoint.x, aOutline.front()->endPoint.y );
+            fprintf( layoutFile, "%d %.5f %.5f 0\n", outlineIndex,
+                    aOutline.front()->startPoint.x, aOutline.front()->startPoint.y );
+        }
+        else
+        {
+            fprintf( layoutFile, "%d %.5f %.5f 0\n", outlineIndex,
+                    aOutline.front()->endPoint.x, aOutline.front()->endPoint.y );
+            fprintf( layoutFile, "%d %.5f %.5f %.5f\n", outlineIndex,
+                    aOutline.front()->startPoint.x, aOutline.front()->startPoint.y,
+                    -aOutline.front()->angle );
+        }
+
+        // for all other segments we only write out the start point
+        while( bo != eo )
+        {
+            if( (*bo)->angle < MIN_ANG && (*bo)->angle > -MIN_ANG )
+            {
+                fprintf( layoutFile, "%d %.5f %.5f 0\n", outlineIndex,
+                        (*bo)->startPoint.x, (*bo)->startPoint.y );
+            }
+            else
+            {
+                fprintf( layoutFile, "%d %.5f %.5f %.5f\n", outlineIndex,
+                        (*bo)->startPoint.x, (*bo)->startPoint.y, -(*bo)->angle );
+            }
+
+            --bo;
+        }
+    }
+    else
+    {
+        bo  = aOutline.begin();
+        eo  = aOutline.end();
+
+        // for the first item we write out both points
+        if( (*bo)->angle < MIN_ANG && (*bo)->angle > -MIN_ANG )
+        {
+            fprintf( layoutFile, "%d %.5f %.5f 0\n", outlineIndex,
+                    (*bo)->startPoint.x, (*bo)->startPoint.y );
+            fprintf( layoutFile, "%d %.5f %.5f 0\n", outlineIndex,
+                    (*bo)->endPoint.x, (*bo)->endPoint.y );
+        }
+        else
+        {
+            fprintf( layoutFile, "%d %.5f %.5f 0\n", outlineIndex,
+                    (*bo)->startPoint.x, (*bo)->startPoint.y );
+            fprintf( layoutFile, "%d %.5f %.5f %.5f\n", outlineIndex,
+                    (*bo)->endPoint.x, (*bo)->endPoint.y, (*bo)->angle );
+        }
+
+        ++bo;
+
+        // for all other segments we only write out the last point
+        while( bo != eo )
+        {
+            if( (*bo)->angle < MIN_ANG && (*bo)->angle > -MIN_ANG )
+            {
+                fprintf( layoutFile, "%d %.5f %.5f 0\n", outlineIndex,
+                        (*bo)->endPoint.x, (*bo)->endPoint.y );
+            }
+            else
+            {
+                fprintf( layoutFile, "%d %.5f %.5f %.5f\n", outlineIndex,
+                        (*bo)->endPoint.x, (*bo)->endPoint.y, (*bo)->angle );
+            }
+
+            ++bo;
+        }
+    }
+
+    ++outlineIndex;
+
+    return true;
+}
+
+
+bool IDF_BOARD::AddDrill( double dia, double x, double y,
+        IDF3::KEY_PLATING plating,
+        const std::string refdes,
+        const std::string holeType,
+        IDF3::KEY_OWNER owner )
+{
+    if( dia < IDF_MIN_DIA * scale )
+        return false;
+
+    IDF_DRILL_DATA* dp = new IDF_DRILL_DATA( dia, x, y, plating, refdes, holeType, owner );
+    drills.push_back( dp );
+
+    return true;
+}
+
+
+bool IDF_BOARD::AddSlot( double aWidth, double aLength, double aOrientation,
+        double aX, double aY )
+{
+    if( aWidth < IDF_MIN_DIA * scale )
+        return false;
+
+    if( aLength < IDF_MIN_DIA * scale )
+        return false;
+
+    // this is a round hole; in this case we create a PTH MTG drill hole owned by the board
+    // TO IMPLEMENT
+    if( aWidth == aLength )
+    {
+        AddDrill( aWidth, aX, aY, IDF3::PTH, "BOARD", "MTG", IDF3::ECAD );
+    }
+
+    if( aWidth > aLength )
+        std::swap( aWidth, aLength );
+
+    IDF_POINT c[2];     // centers
+    IDF_POINT pt[4];
+
+    double a1 = aOrientation / 180.0 * M_PI;
+    double a2 = a1 + M_PI2;
+    double d1 = aLength / 2.0;
+    double d2 = aWidth / 2.0;
+    double sa1 = sin( a1 );
+    double ca1 = cos( a1 );
+    double dsa2 = d2 * sin( a2 );
+    double dca2 = d2 * cos( a2 );
+
+    c[0].x  = aX + d1 * ca1;
+    c[0].y  = aY + d1 * sa1;
+
+    c[1].x  = aX - d1 * ca1;
+    c[1].y  = aY - d1 * sa1;
+
+    pt[0].x = c[0].x + dca2;
+    pt[0].y = c[0].y + dsa2;
+
+    pt[1].x = c[1].x + dca2;
+    pt[1].y = c[1].y + dsa2;
+
+    pt[2].x = c[1].x - dca2;
+    pt[2].y = c[1].y - dsa2;
+
+    pt[3].x = c[0].x - dca2;
+    pt[3].y = c[0].y - dsa2;
+
+    IDF_OUTLINE outline;
+
+    // first straight run
+    IDF_SEGMENT* seg = new IDF_SEGMENT( pt[0], pt[1] );
+    outline.push( seg );
+    // first 180 degree cap
+    seg = new IDF_SEGMENT( pt[1], pt[2], 180.0, false );
+    outline.push( seg );
+    // final straight run
+    seg = new IDF_SEGMENT( pt[2], pt[3] );
+    outline.push( seg );
+    // final 180 degree cap
+    seg = new IDF_SEGMENT( pt[3], pt[0], 180.0, false );
+    outline.push( seg );
+
+    return AddOutline( outline );
+}
+
+
+bool IDF_BOARD::WriteDrills( void )
+{
+    if( !layoutFile )
+        return false;
+
+    // TODO: check the stream integrity and return false as appropriate
+    if( drills.empty() )
+        return true;
+
+    fprintf( layoutFile, ".DRILLED_HOLES\n" );
+
+    std::list<struct IDF_DRILL_DATA*>::iterator ds  = drills.begin();
+    std::list<struct IDF_DRILL_DATA*>::iterator de  = drills.end();
+
+    while( ds != de )
+    {
+        if( !(*ds)->Write( layoutFile ) )
+            return false;
+
+        ++ds;
+    }
+
+    fprintf( layoutFile, ".END_DRILLED_HOLES\n" );
+
+    return true;
+}
+
+
+double IDF_BOARD::GetScale( void )
+{
+    return scale;
+}
+
+
+void IDF3::GetOutline( std::list<IDF_SEGMENT*>& aLines,
+        IDF_OUTLINE& aOutline )
+{
+    aOutline.Clear();
+
+    // NOTE: To tell if the point order is CCW or CW,
+    // sum all:  (endPoint.X[n] - startPoint.X[n])*(endPoint[n] + startPoint.Y[n])
+    // If the result is >0, the direction is CW, otherwise
+    // it is CCW. Note that the result cannot be 0 unless
+    // we have a bounded area of 0.
+
+    // First we find the segment with the leftmost point
+    std::list<IDF_SEGMENT*>::iterator bl    = aLines.begin();
+    std::list<IDF_SEGMENT*>::iterator el    = aLines.end();
+    std::list<IDF_SEGMENT*>::iterator idx   = bl++;       // iterator for the object with minX
+
+    double minx = (*idx)->GetMinX();
+    double curx;
+
+    while( bl != el )
+    {
+        curx = (*bl)->GetMinX();
+
+        if( curx < minx )
+        {
+            minx = curx;
+            idx = bl;
+        }
+
+        ++bl;
+    }
+
+    aOutline.push( *idx );
+    aLines.erase( idx );
+
+    // If the item is a circle then we're done
+    if( aOutline.front()->IsCircle() )
+        return;
+
+    // Assemble the loop
+    bool complete = false;  // set if loop is complete
+    bool matched;           // set if a segment's end point was matched
+
+    while( !complete )
+    {
+        matched = false;
+        bl  = aLines.begin();
+        el  = aLines.end();
+
+        while( bl != el && !matched )
+        {
+            if( (*bl)->MatchesStart( aOutline.back()->endPoint ) )
+            {
+                if( (*bl)->IsCircle() )
+                {
+                    // a circle on the perimeter is pathological but we just ignore it
+                    ++bl;
+                }
+                else
+                {
+                    matched = true;
+                    aOutline.push( *bl );
+                    aLines.erase( bl );
+                }
+
+                continue;
+            }
+
+            ++bl;
+        }
+
+        if( !matched )
+        {
+            // attempt to match the end points
+            bl  = aLines.begin();
+            el  = aLines.end();
+
+            while( bl != el && !matched )
+            {
+                if( (*bl)->MatchesEnd( aOutline.back()->endPoint ) )
+                {
+                    if( (*bl)->IsCircle() )
+                    {
+                        // a circle on the perimeter is pathological but we just ignore it
+                        ++bl;
+                    }
+                    else
+                    {
+                        matched = true;
+                        (*bl)->SwapEnds();
+                        aOutline.push( *bl );
+                        aLines.erase( bl );
+                    }
+
+                    continue;
+                }
+
+                ++bl;
+            }
+        }
+
+        if( !matched )
+        {
+            // still no match - attempt to close the loop
+            if( (aOutline.size() > 1) || ( aOutline.front()->angle < -MIN_ANG )
+                || ( aOutline.front()->angle > MIN_ANG ) )
+            {
+                // close the loop
+                IDF_SEGMENT* seg = new IDF_SEGMENT( aOutline.back()->endPoint,
+                        aOutline.front()->startPoint );
+
+                if( seg )
+                {
+                    complete = true;
+                    aOutline.push( seg );
+                    break;
+                }
+            }
+
+            // the outline is bad; drop the segments
+            aOutline.Clear();
+
+            return;
+        }
+
+        // check if the loop is complete
+        if( aOutline.front()->MatchesStart( aOutline.back()->endPoint ) )
+        {
+            complete = true;
+            break;
+        }
+    }
+}
+
+
+bool IDF_LIB::WriteLib( FILE* aLibFile )
+{
+    if( !aLibFile )
+        return false;
+
+    // TODO: check stream integrity and return false as appropriate
+
+    // TODO: export models
+
+    return true;
+}
+
+
+bool IDF_LIB::WriteBrd( FILE* aLayoutFile )
+{
+    if( !aLayoutFile )
+        return false;
+
+    // TODO: check stream integrity and return false as appropriate
+
+    // TODO: write out the board placement information
+
+    return true;
+}

=== added file 'pcbnew/idf.h'
--- pcbnew/idf.h	1970-01-01 00:00:00 +0000
+++ pcbnew/idf.h	2013-12-15 09:42:28 +0000
@@ -0,0 +1,434 @@
+/**
+ * @file idf.h
+ */
+
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2013  Cirilo Bernardo
+ *
+ * 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 <wx/string.h>
+
+#ifndef M_PI
+#define M_PI 3.1415926535897932384626433832795028841
+#endif
+
+#ifndef M_PI2
+#define M_PI2 ( M_PI / 2.0 )
+#endif
+
+#ifndef M_PI4
+#define M_PI4 ( M_PI / 4.0 )
+#endif
+
+class IDF_POINT;
+class IDF_SEGMENT;
+class IDF_DRILL_DATA;
+class IDF_OUTLINE;
+
+namespace IDF3 {
+enum KEY_OWNER
+{
+    UNOWNED = 0,        // < either MCAD or ECAD may modify a feature
+    MCAD,               // < only MCAD may modify a feature
+    ECAD                // < only ECAD may modify a feature
+};
+
+enum KEY_HOLETYPE
+{
+    PIN = 0,            // < drill hole is for a pin
+    VIA,                // < drill hole is for a via
+    MTG,                // < drill hole is for mounting
+    TOOL,               // < drill hole is for tooling
+    OTHER               // < user has specified a custom type
+};
+
+enum KEY_PLATING
+{
+    PTH = 0,            // < Plate-Through Hole
+    NPTH                // < Non-Plate-Through Hole
+};
+
+enum KEY_REFDES
+{
+    BOARD = 0,          // < feature is associated with the board
+    NOREFDES,           // < feature is associated with a component with no RefDes
+    PANEL,              // < feature is associated with an IDF panel
+    REFDES              // < reference designator as assigned by the CAD software
+};
+
+// calculate the angle between the horizon and the segment aStartPoint to aEndPoint
+double  CalcAngleRad( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint );
+double  CalcAngleDeg( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint );
+
+// take contiguous elements from 'lines' and stuff them into 'outline'
+void GetOutline( std::list<IDF_SEGMENT*>& aLines,
+        IDF_OUTLINE& aOutline );
+}
+
+
+/**
+ * @Class IDF_POINT
+ * represents a point
+ */
+class IDF_POINT
+{
+public:
+    double x;   // < X coordinate
+    double y;   // < Y coordinate
+
+    IDF_POINT()
+    {
+        x = 0.0;
+        y = 0.0;
+    }
+
+    /**
+     * Function Matches()
+     * returns true if the given coordinate point is within the given radius
+     * of the point.
+     * @param aPoint : coordinates of the point being compared
+     * @param aRadius : radius within which the points are considered the same
+     */
+    bool    Matches( const IDF_POINT& aPoint, double aRadius = 1e-5 );
+    double  CalcDistance( const IDF_POINT& aPoint ) const;
+};
+
+
+/**
+ * @Class IDF_SEGMENT
+ * represents a geometry segment as used in IDFv3 outlines
+ */
+class IDF_SEGMENT
+{
+private:
+    /**
+     * Function CalcCenterAndRadius()
+     * Calculates the center, radius, and angle between center and start point given the
+     * IDF compliant points and included angle.
+     * @var startPoint, @var endPoint, and @var angle must be set prior as per IDFv3
+     */
+    void CalcCenterAndRadius( void );
+
+public:
+    IDF_POINT startPoint;   // starting point in IDF coordinates
+    IDF_POINT endPoint;     // end point in IDF coordinates
+    IDF_POINT   center;     // center of an arc or circle; used primarily for calculating min X
+    double  angle;          // included angle (degrees) according to IDFv3 specification
+    double  offsetAngle;    // angle between center and start of arc; used to speed up some calcs.
+    double  radius;         // radius of the arc or circle; used to speed up some calcs.
+
+    /**
+     * Function IDF_SEGMENT()
+     * initializes the internal variables
+     */
+    IDF_SEGMENT();
+
+    /**
+     * Function IDF_SEGMENT( start, end )
+     * creates a straight segment
+     */
+    IDF_SEGMENT( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint );
+
+    /**
+     * Function IDF_SEGMENT( start, end )
+     * creates a straight segment, arc, or circle depending on the angle
+     * @param aStartPoint : start point (center if using KiCad convention, otherwise IDF convention)
+     * @param aEndPoint : end point (start of arc if using KiCad convention, otherwise IDF convention)
+     * @param aAngle : included angle; the KiCad convention is equivalent to the IDF convention
+     * @param fromKicad : set true if we need to convert from KiCad to IDF convention
+     */
+    IDF_SEGMENT( const IDF_POINT& aStartPoint,
+            const IDF_POINT& aEndPoint,
+            double aAngle,
+            bool aFromKicad );
+
+    /**
+     * Function MatchesStart()
+     * returns true if the given coordinate is within a radius 'rad'
+     * of the start point.
+     * @param aPoint : coordinates of the point being compared
+     * @param aRadius : radius within which the points are considered the same
+     */
+    bool MatchesStart( const IDF_POINT& aPoint, double aRadius = 1e-3 );
+
+    /**
+     * Function MatchesEnd()
+     * returns true if the given coordinate is within a radius 'rad'
+     * of the end point.
+     * @param aPoint : coordinates of the point being compared
+     * @param aRadius : radius within which the points are considered the same
+     */
+    bool MatchesEnd( const IDF_POINT& aPoint, double aRadius = 1e-3 );
+
+    /**
+     * Function IsCircle()
+     * returns true if this segment is a circle
+     */
+    bool IsCircle( void );
+
+    /**
+     * Function GetMinX()
+     * returns the minimum X coordinate of this segment
+     */
+    double GetMinX( void );
+
+    /**
+     * Function SwapEnds()
+     * Swaps the start and end points and alters internal
+     * variables as necessary for arcs
+     */
+    void SwapEnds( void );
+};
+
+
+/**
+ * @Class IDF_OUTLINE
+ * contains segment and winding information for an IDF outline
+ */
+class IDF_OUTLINE
+{
+private:
+    double dir;
+    std::list<IDF_SEGMENT*> outline;
+
+public:
+    IDF_OUTLINE() { dir = 0.0; }
+    ~IDF_OUTLINE() { Clear(); }
+
+    // returns true if the current list of points represents a counterclockwise winding
+    bool IsCCW( void )
+    {
+        if( dir > 0.0 )
+            return false;
+
+        return true;
+    }
+
+    // clears the internal list of outline segments
+    void Clear( void )
+    {
+        dir = 0.0;
+
+        while( !outline.empty() )
+        {
+            delete outline.front();
+            outline.pop_front();
+        }
+    }
+
+    // returns the size of the internal segment list
+    size_t size( void )
+    {
+        return outline.size();
+    }
+
+    // returns true if the internal segment list is empty
+    bool empty( void )
+    {
+        return outline.empty();
+    }
+
+    // return the front() of the internal segment list
+    IDF_SEGMENT*& front( void )
+    {
+        return outline.front();
+    }
+
+    // return the back() of the internal segment list
+    IDF_SEGMENT*& back( void )
+    {
+        return outline.back();
+    }
+
+    // return the begin() iterator of the internal segment list
+    std::list<IDF_SEGMENT*>::iterator begin( void )
+    {
+        return outline.begin();
+    }
+
+    // return the end() iterator of the internal segment list
+    std::list<IDF_SEGMENT*>::iterator end( void )
+    {
+        return outline.end();
+    }
+
+    // push a segment onto the internal list
+    void push( IDF_SEGMENT* item )
+    {
+        // XXX - check that startPoint[N] == endPoint[N -1], otherwise THROW
+        // XXX - a Circle must stand alone; if we add to a circle or add a
+        // circle to an existing list, we should throw an exception.
+        outline.push_back( item );
+        dir += ( outline.back()->endPoint.x - outline.back()->startPoint.x )
+               * ( outline.back()->endPoint.y + outline.back()->startPoint.y );
+    }
+};
+
+
+/**
+ * @Class IDF_BOARD
+ * contains objects necessary for the maintenance of the IDF board and library files.
+ */
+class IDF_BOARD
+{
+private:
+    std::list<IDF_DRILL_DATA*> drills;      // /< IDF drill data
+    int outlineIndex;                       // /< next outline index to use
+    bool useThou;                           // /< true if output is THOU
+    double scale;                           // /< scale from KiCad IU to IDF output units
+    double boardThickness;                  // /< total thickness of the PCB
+    bool hasBrdOutlineHdr;                  // /< true when a board outline header has been written
+
+    FILE* layoutFile;                       // /< IDF board file (*.emn)
+    FILE* libFile;                          // /< IDF library file (*.emp)
+
+    /**
+     * Function Write
+     * outputs a .DRILLED_HOLES section compliant with the
+     * IDFv3 specification.
+     * @param aLayoutFile : open file (*.emn) for output
+     */
+    bool WriteDrills( void );
+
+public:
+    IDF_BOARD();
+
+    ~IDF_BOARD();
+
+    // Set up the output files and scale factor;
+    // return TRUE if everything is OK
+    bool Setup( wxString aBoardName, wxString aFullFileName, bool aUseThou, int aBoardThickness );
+
+    // Finish a board
+    // Write out all current data and close files.
+    // Return true for success
+    bool Finish( void );
+
+    /**
+     * Function GetScale
+     * returns the output scaling factor
+     */
+    double GetScale( void );
+
+    // Add an outline; the very first outline is the board perimeter;
+    // all additional outlines are cutouts.
+    bool AddOutline( IDF_OUTLINE& aOutline );
+
+    /**
+     * Function AddDrill
+     * creates a drill entry and adds it to the list of PCB holes
+     * @param dia : drill diameter
+     * @param x : X coordinate of the drill center
+     * @param y : Y coordinate of the drill center
+     * @param plating : flag, PTH or NPTH
+     * @param refdes : component Reference Designator
+     * @param holetype : purpose of hole
+     * @param owner : one of MCAD, ECAD, UNOWNED
+     */
+    bool AddDrill( double dia, double x, double y,
+            IDF3::KEY_PLATING plating,
+            const std::string refdes,
+            const std::string holeType,
+            IDF3::KEY_OWNER owner );
+
+    /**
+     * Function AddSlot
+     * creates a slot cutout within the IDF BOARD section; this is a deficient representation
+     * of a KiCad 'oval' drill; IDF is unable to represent a plated slot and unable to
+     * represent the Reference Designator association with a slot.
+     */
+    bool AddSlot( double aWidth, double aLength, double aOrientation, double aX, double aY );
+};
+
+
+/**
+ * @Class IDF_DRILL_DATA
+ * contains information describing a drilled hole and is responsible for
+ * writing this information to a file in compliance with the IDFv3 specification.
+ */
+class IDF_DRILL_DATA
+{
+private:
+    double dia;
+    double x;
+    double y;
+    IDF3::KEY_PLATING plating;
+    IDF3::KEY_REFDES kref;
+    IDF3::KEY_HOLETYPE khole;
+    std::string refdes;
+    std::string holetype;
+    IDF3::KEY_OWNER owner;
+
+public:
+    /**
+     * Constructor IDF_DRILL_DATA
+     * creates a drill entry with information compliant with the
+     * IDFv3 specifications.
+     * @param aDrillDia : drill diameter
+     * @param aPosX : X coordinate of the drill center
+     * @param aPosY : Y coordinate of the drill center
+     * @param aPlating : flag, PTH or NPTH
+     * @param aRefDes : component Reference Designator
+     * @param aHoleType : purpose of hole
+     * @param aOwner : one of MCAD, ECAD, UNOWNED
+     */
+    IDF_DRILL_DATA( double aDrillDia, double aPosX, double aPosY,
+            IDF3::KEY_PLATING aPlating,
+            const std::string aRefDes,
+            const std::string aHoleType,
+            IDF3::KEY_OWNER aOwner );
+
+    /**
+     * Function Write
+     * writes a single line representing the hole within a .DRILLED_HOLES section
+     */
+    bool Write( FILE* aLayoutFile );
+};
+
+
+/**
+ * @Class IDF_LIB
+ * stores information on IDF models ( also has an inbuilt NOMODEL model )
+ * and is responsible for writing the ELECTRICAL sections of the library file
+ * (*.emp) and the PLACEMENT section of the board file.
+ */
+class IDF_LIB
+{
+    // TODO: IMPLEMENT
+
+public:
+    /**
+     * Function WriteLib
+     * writes all current library information to the output file
+     */
+    bool WriteLib( FILE* aLibFile );
+
+    // write placement information to the board file
+    bool WriteBrd( FILE* aLayoutFile );
+
+    // bool Finish( void )
+    // {
+    // TODO: Write out the library (*.emp) file
+    // idf_lib.Write( lib_file );
+    // TODO: fclose( lib_file );
+    // }
+};

=== modified file 'pcbnew/menubar_pcbframe.cpp'
--- pcbnew/menubar_pcbframe.cpp	2013-12-12 16:01:03 +0000
+++ pcbnew/menubar_pcbframe.cpp	2013-12-15 09:07:04 +0000
@@ -204,6 +204,11 @@
                  _( "Export a VRML board representation" ),
                  KiBitmap( three_d_xpm ) );
 
+    // IDF3
+    AddMenuItem( submenuexport, ID_GEN_EXPORT_FILE_IDF3,
+                 _( "I&DFv3" ), _( "Export IDFv3 format" ),
+                 KiBitmap( export_xpm ) );
+
     AddMenuItem( filesMenu, submenuexport,
                  ID_GEN_EXPORT_FILE, _( "E&xport" ),
                  _( "Export board" ), KiBitmap( export_xpm ) );

=== modified file 'pcbnew/pcbframe.cpp'
--- pcbnew/pcbframe.cpp	2013-12-12 16:01:03 +0000
+++ pcbnew/pcbframe.cpp	2013-12-15 09:07:04 +0000
@@ -108,6 +108,7 @@
     EVT_MENU( ID_GEN_EXPORT_FILE_GENCADFORMAT, PCB_EDIT_FRAME::ExportToGenCAD )
     EVT_MENU( ID_GEN_EXPORT_FILE_MODULE_REPORT, PCB_EDIT_FRAME::GenFootprintsReport )
     EVT_MENU( ID_GEN_EXPORT_FILE_VRML, PCB_EDIT_FRAME::OnExportVRML )
+    EVT_MENU( ID_GEN_EXPORT_FILE_IDF3, PCB_EDIT_FRAME::ExportToIDF3 )
 
     EVT_MENU( ID_GEN_IMPORT_SPECCTRA_SESSION,PCB_EDIT_FRAME::ImportSpecctraSession )
     EVT_MENU( ID_GEN_IMPORT_SPECCTRA_DESIGN, PCB_EDIT_FRAME::ImportSpecctraDesign )

=== modified file 'pcbnew/pcbnew_id.h'
--- pcbnew/pcbnew_id.h	2013-12-05 12:24:27 +0000
+++ pcbnew/pcbnew_id.h	2013-12-14 21:04:57 +0000
@@ -246,6 +246,7 @@
     ID_MENU_PCB_SWAP_LAYERS,
     ID_MENU_PCB_RESET_TEXTMODULE_FIELDS_SIZES,
 
+    ID_GEN_EXPORT_FILE_IDF3,
     ID_GEN_EXPORT_FILE_VRML,
     ID_GEN_EXPORT_SPECCTRA,
     ID_GEN_EXPORT_FILE_GENCADFORMAT,


References