Commit 46fcb07b authored by jean-pierre charras's avatar jean-pierre charras
Browse files

Gerbview: export_to_pcbnew enhancement and fixes.

parent 4dee08c3
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}
set(DIALOGS_SRCS
set(DIALOGS_SRCS
    dialogs/gerbview_dialog_display_options_frame_base.cpp
    dialogs/gerbview_dialog_display_options_frame_base.cpp
    dialogs/gerbview_dialog_display_options_frame.cpp
    dialogs/gerbview_dialog_display_options_frame.cpp
    dialogs/dialog_layers_select_to_pcb_base.cpp
    dialogs/dialog_print_using_printer.cpp
    dialogs/dialog_print_using_printer.cpp
    dialogs/dialog_print_using_printer_base.cpp
    dialogs/dialog_print_using_printer_base.cpp
    )
    )
+228 −125
Original line number Original line Diff line number Diff line
@@ -10,13 +10,50 @@
#include "confirm.h"
#include "confirm.h"
#include "kicad_string.h"
#include "kicad_string.h"
#include "gestfich.h"
#include "gestfich.h"
#include "trigo.h"


#include "gerbview.h"
#include "gerbview.h"
#include "class_board_design_settings.h"
#include "class_board_design_settings.h"
#include "class_gerber_draw_item.h"
#include "class_gerber_draw_item.h"


static int SavePcbFormatAscii( GERBVIEW_FRAME* frame,

                               FILE* File, int* LayerLookUpTable );
/* A helper class to export a Gerber set of files to Pcbnew
*/
class GBR_TO_PCB_EXPORTER
{
    GERBVIEW_FRAME* m_gerbview_frame;   // the maint gerber frame
    FILE * m_file;      // .brd file to write to
    BOARD* m_pcb;       // the board to populate and export

public:
    GBR_TO_PCB_EXPORTER(GERBVIEW_FRAME * aFrame, FILE * aFile );
    ~GBR_TO_PCB_EXPORTER();
    bool ExportPcb( int* LayerLookUpTable );

private:
    bool WriteSetup( );  // Write the SETUP section data file
    bool WriteGeneralDescrPcb( );
    void export_non_copper_item( GERBER_DRAW_ITEM* aGbrItem, int aLayer );
    void export_copper_item( GERBER_DRAW_ITEM* aGbrItem, int aLayer );
    void export_flashed_copper_item( GERBER_DRAW_ITEM* aGbrItem, int aLayer );
    void export_segline_copper_item( GERBER_DRAW_ITEM* aGbrItem, int aLayer );
    void export_segarc_copper_item( GERBER_DRAW_ITEM* aGbrItem, int aLayer );
    void cleanBoard();
};

GBR_TO_PCB_EXPORTER::GBR_TO_PCB_EXPORTER( GERBVIEW_FRAME * aFrame, FILE * aFile )
{
    m_gerbview_frame = aFrame;
    m_file = aFile;
    m_pcb = NULL;
}

GBR_TO_PCB_EXPORTER::~GBR_TO_PCB_EXPORTER()
{
    // the destructor should destroy all owned sub-objects
    delete m_pcb;
}





/* Export data in pcbnew format
/* Export data in pcbnew format
@@ -45,8 +82,6 @@ void GERBVIEW_FRAME::ExportDataInPcbnewFormat( wxCommandEvent& event )


    wxString PcbExt( wxT( ".brd" ) );
    wxString PcbExt( wxT( ".brd" ) );


    FILE*    dest;

    msg = wxT( "*" ) + PcbExt;
    msg = wxT( "*" ) + PcbExt;
    FullFileName = EDA_FileSelector( _( "Board file name:" ),
    FullFileName = EDA_FileSelector( _( "Board file name:" ),
                                     wxEmptyString,
                                     wxEmptyString,
@@ -68,53 +103,83 @@ void GERBVIEW_FRAME::ExportDataInPcbnewFormat( wxCommandEvent& event )
            if( !IsOK( this, _( "Ok to change the existing file ?" ) ) )
            if( !IsOK( this, _( "Ok to change the existing file ?" ) ) )
                return;
                return;
        }
        }
        dest = wxFopen( FullFileName, wxT( "wt" ) );
        FILE * file = wxFopen( FullFileName, wxT( "wt" ) );
        if( dest == 0 )
        if( file == NULL )
        {
        {
            msg = _( "Unable to create " ) + FullFileName;
            msg = _( "Unable to create " ) + FullFileName;
            DisplayError( this, msg );
            DisplayError( this, msg );
            return;
            return;
        }
        }
        GetScreen()->SetFileName( FullFileName );
        GetScreen()->SetFileName( FullFileName );
        SavePcbFormatAscii( this, dest, LayerLookUpTable );
        GBR_TO_PCB_EXPORTER gbr_exporter( this, file );
        fclose( dest );
        gbr_exporter.ExportPcb( LayerLookUpTable );
        fclose( file );
    }
    }
}
}


void GBR_TO_PCB_EXPORTER::cleanBoard()
{
    // delete redundant vias
    for( TRACK * track = m_pcb->m_Track; track; track = track->Next() )
    {
        if( track->m_Shape != VIA_THROUGH )
            continue;


static int WriteSetup( FILE* File, BOARD* Pcb )
        // Search and delete others vias
        TRACK* next_track;
        TRACK* alt_track = track->Next();
        for( ; alt_track; alt_track = next_track )
        {
        {
    char text[1024];
            next_track = alt_track->Next();
            if( alt_track->m_Shape != VIA_THROUGH )
                continue;


    fprintf( File, "$SETUP\n" );
            if( alt_track->m_Start != track->m_Start )
    sprintf( text, "InternalUnit %f INCH\n", 1.0 / PCB_INTERNAL_UNIT );
                continue;
    fprintf( File, "%s", text );


    fprintf( File, "Layers %d\n", Pcb->GetCopperLayerCount() );
            // delete track
            alt_track->UnLink();
            delete alt_track;
        }
    }
}


    fprintf( File, "$EndSETUP\n\n" );
bool GBR_TO_PCB_EXPORTER::WriteSetup( )
    return 1;
{
    fprintf( m_file, "$SETUP\n" );
    fprintf( m_file, "InternalUnit %f INCH\n", 1.0 / PCB_INTERNAL_UNIT );

    fprintf( m_file, "Layers %d\n", m_pcb->GetCopperLayerCount() );

    fprintf( m_file, "$EndSETUP\n\n" );
    return true;
}
}




static bool WriteGeneralDescrPcb( BOARD* Pcb, FILE* File )
bool GBR_TO_PCB_EXPORTER::WriteGeneralDescrPcb( )
{
{
    int NbLayers;
    int nbLayers;


    /* Print the copper layer count */
    /* Print the copper layer count */
    NbLayers = Pcb->GetCopperLayerCount();
    nbLayers = m_pcb->GetCopperLayerCount();
    fprintf( File, "$GENERAL\n" );
    if( nbLayers <= 1 )  // Minimal layers count in Pcbnew is 2
    fprintf( File, "LayerCount %d\n", NbLayers );
    {
        nbLayers = 2;
        m_pcb->SetCopperLayerCount(2);
    }
    fprintf( m_file, "$GENERAL\n" );
    fprintf( m_file, "encoding utf-8\n");
    fprintf( m_file, "LayerCount %d\n", nbLayers );


    /* Compute and print the board bounding box */
    /* Compute and print the board bounding box */
    Pcb->ComputeBoundingBox();
    m_pcb->ComputeBoundingBox();
    fprintf( File, "Di %d %d %d %d\n",
    fprintf( m_file, "Di %d %d %d %d\n",
            Pcb->m_BoundaryBox.GetX(), Pcb->m_BoundaryBox.GetY(),
            m_pcb->m_BoundaryBox.GetX(), m_pcb->m_BoundaryBox.GetY(),
            Pcb->m_BoundaryBox.GetRight(),
            m_pcb->m_BoundaryBox.GetRight(),
            Pcb->m_BoundaryBox.GetBottom() );
            m_pcb->m_BoundaryBox.GetBottom() );


    fprintf( File, "$EndGENERAL\n\n" );
    fprintf( m_file, "$EndGENERAL\n\n" );
    return TRUE;
    return true;
}
}




@@ -124,17 +189,13 @@ static bool WriteGeneralDescrPcb( BOARD* Pcb, FILE* File )
 * @param LayerLookUpTable = look up table: pcbnew layer for each gerber layer
 * @param LayerLookUpTable = look up table: pcbnew layer for each gerber layer
 * @return 1 if OK, 0 if fail
 * @return 1 if OK, 0 if fail
 */
 */
static int SavePcbFormatAscii( GERBVIEW_FRAME* frame, FILE* aFile,
bool GBR_TO_PCB_EXPORTER::ExportPcb( int* LayerLookUpTable )
                               int* LayerLookUpTable )
{
{
    char   line[256];
    char   line[256];
    BOARD* gerberPcb = frame->GetBoard();
    BOARD* gerberPcb = m_gerbview_frame->GetBoard();
    BOARD* pcb;

    wxBeginBusyCursor();


    // create an image of gerber data
    // create an image of gerber data
    pcb = new BOARD( NULL, frame );
    m_pcb = new BOARD( NULL, m_gerbview_frame );
    BOARD_ITEM* item = gerberPcb->m_Drawings;
    BOARD_ITEM* item = gerberPcb->m_Drawings;
    for( ; item; item = item->Next() )
    for( ; item; item = item->Next() )
    {
    {
@@ -145,105 +206,147 @@ static int SavePcbFormatAscii( GERBVIEW_FRAME* frame, FILE* aFile,
            continue;
            continue;


        if( pcb_layer_number > LAST_COPPER_LAYER )
        if( pcb_layer_number > LAST_COPPER_LAYER )
        {
            export_non_copper_item( gerb_item, pcb_layer_number );
            DRAWSEGMENT* drawitem = new DRAWSEGMENT( pcb, TYPE_DRAWSEGMENT );


            drawitem->SetLayer( pcb_layer_number );
        else
            drawitem->m_Start = gerb_item->m_Start;
            export_copper_item( gerb_item, pcb_layer_number );
            drawitem->m_End   = gerb_item->m_End;
    }
            drawitem->m_Width = gerb_item->m_Size.x;


            if( gerb_item->m_Shape == GBR_ARC )
    cleanBoard();
            {
                double cx = gerb_item->m_ArcCentre.x;
                double cy = gerb_item->m_ArcCentre.y;
                double a  = atan2( gerb_item->m_Start.y - cy,
                                   gerb_item->m_Start.x - cx );
                double b  = atan2( gerb_item->m_End.y - cy, gerb_item->m_End.x - cx );


                drawitem->m_Shape   = S_ARC;
    // Switch the locale to standard C (needed to print floating point numbers)
                drawitem->m_Angle   = (int) fmod(
    SetLocaleTo_C_standard();
                     (a - b) / M_PI * 1800.0 + 3600.0, 3600.0 );

                drawitem->m_Start.x = (int) cx;
    // write PCB header
                drawitem->m_Start.y = (int) cy;
    fprintf( m_file, "PCBNEW-BOARD Version %d date %s\n\n", g_CurrentVersionPCB,
            }
            DateAndTime( line ) );
    WriteGeneralDescrPcb( );
    WriteSetup( );

    // write items on file
    m_pcb->Save( m_file );


            pcb->Add( drawitem );
    SetLocaleTo_Default();       // revert to the current locale
    return true;
}
}
        else

void GBR_TO_PCB_EXPORTER::export_non_copper_item( GERBER_DRAW_ITEM* aGbrItem, int aLayer )
{
{
            TRACK* newtrack;
    DRAWSEGMENT* drawitem = new DRAWSEGMENT( m_pcb, TYPE_DRAWSEGMENT );


            // replace spots with vias when possible
    drawitem->SetLayer( aLayer );
            if( gerb_item->m_Shape == GBR_SPOT_CIRCLE
    drawitem->m_Start = aGbrItem->m_Start;
                || gerb_item->m_Shape == GBR_SPOT_RECT
    drawitem->m_End   = aGbrItem->m_End;
                || gerb_item->m_Shape == GBR_SPOT_OVAL )
    drawitem->m_Width = aGbrItem->m_Size.x;

    if( aGbrItem->m_Shape == GBR_ARC )
    {
    {
                newtrack = new SEGVIA( pcb );
        double a  = atan2( (double)( aGbrItem->m_Start.y - aGbrItem->m_ArcCentre.y),
                           (double)( aGbrItem->m_Start.x - aGbrItem->m_ArcCentre.x ) );
        double b  = atan2( (double)( aGbrItem->m_End.y - aGbrItem->m_ArcCentre.y ),
                            (double)( aGbrItem->m_End.x - aGbrItem->m_ArcCentre.x ) );


                // A spot is found, and can be a via: change it to via, and
        drawitem->m_Shape   = S_ARC;
                // delete other
        drawitem->m_Angle   = wxRound( (a - b) / M_PI * 1800.0 );
                // spots at same location
        drawitem->m_Start = aGbrItem->m_ArcCentre;
                newtrack->m_Shape = VIA_THROUGH;
        if( drawitem->m_Angle < 0 )
                newtrack->SetLayer( 0x0F );  // Layers are 0 to 15 (Cu/Cmp)
                newtrack->SetDrillDefault();
                newtrack->m_Start = newtrack->m_End = gerb_item->m_Start;
                newtrack->m_Width = (gerb_item->m_Size.x + gerb_item->m_Size.y) / 2;
            }
            else    // a true TRACK
        {
        {
                newtrack = new TRACK( pcb );
            NEGATE( drawitem->m_Angle );
                newtrack->SetLayer( pcb_layer_number );
            drawitem->m_End = aGbrItem->m_Start;
                newtrack->m_Start = gerb_item->m_Start;
                newtrack->m_End = gerb_item->m_End;
                newtrack->m_Width = gerb_item->m_Size.x;
        }
        }

            pcb->Add( newtrack );
    }
    }

    m_pcb->Add( drawitem );
}
}


    // delete redundant vias
void GBR_TO_PCB_EXPORTER::export_copper_item( GERBER_DRAW_ITEM* aGbrItem, int aLayer )
    for( TRACK * track = pcb->m_Track; track; track = track->Next() )
{
{
        if( track->m_Shape != VIA_THROUGH )
    switch( aGbrItem->m_Shape )
            continue;

        // Search and delete others vias
        TRACK* next_track;
        TRACK* alt_track = track->Next();
        for( ; alt_track; alt_track = next_track )
    {
    {
            next_track = alt_track->Next();
        case GBR_SPOT_CIRCLE:
            if( alt_track->m_Shape != VIA_THROUGH )
        case GBR_SPOT_RECT:
                continue;
        case GBR_SPOT_OVAL:
            // replace spots with vias when possible
            export_flashed_copper_item( aGbrItem, aLayer );
            break;


            if( alt_track->m_Start != track->m_Start )
        case GBR_ARC:
                continue;
//            export_segarc_copper_item( aGbrItem, aLayer );
            break;


            // delete track
        default:
            alt_track->UnLink();
            export_segline_copper_item( aGbrItem, aLayer );
            delete alt_track;
            break;
    }
    }
}
}


    // Switch the locale to standard C (needed to print floating point numbers
void GBR_TO_PCB_EXPORTER::export_segline_copper_item( GERBER_DRAW_ITEM* aGbrItem, int aLayer )
    // like 1.3)
{
    SetLocaleTo_C_standard();
    TRACK * newtrack = new TRACK( m_pcb );
    newtrack->SetLayer( aLayer );
    newtrack->m_Start = aGbrItem->m_Start;
    newtrack->m_End = aGbrItem->m_End;
    newtrack->m_Width = aGbrItem->m_Size.x;
    m_pcb->Add( newtrack );
}


    // write the PCB heading
void GBR_TO_PCB_EXPORTER::export_segarc_copper_item( GERBER_DRAW_ITEM* aGbrItem, int aLayer )
    fprintf( aFile, "PCBNEW-BOARD Version %d date %s\n\n", g_CurrentVersionPCB,
{
            DateAndTime( line ) );
    double a  = atan2( (double)( aGbrItem->m_Start.y - aGbrItem->m_ArcCentre.y ),
    WriteGeneralDescrPcb( pcb, aFile );
                        (double)( aGbrItem->m_Start.x - aGbrItem->m_ArcCentre.x ) );
    WriteSetup( aFile, pcb );
    double b  = atan2( (double)( aGbrItem->m_End.y - aGbrItem->m_ArcCentre.y ),
                        (double)( aGbrItem->m_End.x - aGbrItem->m_ArcCentre.x ) );

    int arc_angle   = wxRound( ( (a - b) / M_PI * 1800.0 ) );
    wxPoint start = aGbrItem->m_Start;
    wxPoint end = aGbrItem->m_End;
    /* Because Pcbnew does not know arcs in tracks,
     * approximate arc by segments (16 segment per 360 deg)
     */
    #define DELTA 3600/16
    if( arc_angle < 0 )
    {
        NEGATE( arc_angle );
        EXCHG( start, end );
    }
    wxPoint curr_start = start;
    for( int rot = DELTA; rot < (arc_angle - DELTA); rot += DELTA )
    {
        TRACK * newtrack = new TRACK( m_pcb );
        newtrack->SetLayer( aLayer );
        newtrack->m_Start = curr_start;
        wxPoint curr_end = start;
        RotatePoint( &curr_end, aGbrItem->m_ArcCentre, rot );
        newtrack->m_End = curr_end;
        newtrack->m_Width = aGbrItem->m_Size.x;
        m_pcb->Add( newtrack );
        curr_start = curr_end;
    }
    if( end != curr_start )
    {
        TRACK * newtrack = new TRACK( m_pcb );
        newtrack->SetLayer( aLayer );
        newtrack->m_Start = curr_start;
        newtrack->m_End = end;
        newtrack->m_Width = aGbrItem->m_Size.x;
        m_pcb->Add( newtrack );
    }
}


    // write the useful part of the pcb
    pcb->Save( aFile );


    // the destructor should destroy all owned sub-objects
/*
    delete pcb;
 * creates a via from a flashed gerber item.
 * Flashed items are usually pads or vias, so we try to export all of them
 * using vias
 */
void GBR_TO_PCB_EXPORTER::export_flashed_copper_item( GERBER_DRAW_ITEM* aGbrItem, int aLayer )
{
    SEGVIA * newtrack = new SEGVIA( m_pcb );


    SetLocaleTo_Default();       // revert to the current locale
    newtrack->m_Shape = VIA_THROUGH;
    wxEndBusyCursor();
    newtrack->SetLayer( 0x0F );  // Layers are 0 to 15 (Cu/Cmp)
    return 1;
    newtrack->SetDrillDefault();
    newtrack->m_Start = newtrack->m_End = aGbrItem->m_Start;
    newtrack->m_Width = (aGbrItem->m_Size.x + aGbrItem->m_Size.y) / 2;
    m_pcb->Add( newtrack );
}
}