void PCB_BASE_FRAME::OnTogglePadDrawMode( wxCommandEvent& aEvent )
{
    DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)GetDisplayOptions();

    displ_opts->m_DisplayPadFill = !displ_opts->m_DisplayPadFill;
    EDA_DRAW_PANEL_GAL* gal = GetGalCanvas();

    if( gal )
    {
    // Apply new display options to the GAL canvas
        KIGFX::PCB_PAINTER* painter =
                static_cast<KIGFX::PCB_PAINTER*> ( gal->GetView()->GetPainter() );
        KIGFX::PCB_RENDER_SETTINGS* settings =
                static_cast<KIGFX::PCB_RENDER_SETTINGS*> ( painter->GetSettings() );
        settings->LoadDisplayOptions( displ_opts );

        // Update pads
        BOARD* board = GetBoard();
        for( MODULE* module = board->m_Modules; module; module = module->Next() )
        {
            for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() )
                pad->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
        }
    }

    m_canvas->Refresh();
}
void FOOTPRINT_EDIT_FRAME::SaveCopyInUndoList( BOARD_ITEM*    aItem,
                                               UNDO_REDO_T    aTypeCommand,
                                               const wxPoint& aTransformPoint )
{
    EDA_ITEM*          item;
    MODULE*            CopyItem;
    PICKED_ITEMS_LIST* lastcmd;

    CopyItem = new MODULE( *( (MODULE*) aItem ) );
    CopyItem->SetParent( GetBoard() );

    lastcmd = new PICKED_ITEMS_LIST();
    ITEM_PICKER wrapper( CopyItem, UR_MODEDIT );
    lastcmd->PushItem( wrapper );

    GetScreen()->PushCommandToUndoList( lastcmd );

    /* Clear current flags (which can be temporary set by a current edit command) */
    for( item = CopyItem->GraphicalItems(); item != NULL; item = item->Next() )
        item->ClearFlags();

    for( D_PAD* pad = CopyItem->Pads();  pad;  pad = pad->Next() )
        pad->ClearFlags();

    CopyItem->Reference().ClearFlags();
    CopyItem->Value().ClearFlags();

    /* Clear redo list, because after new save there is no redo to do */
    GetScreen()->ClearUndoORRedoList( GetScreen()->m_RedoList );
}
示例#3
0
bool FOOTPRINT_EDIT_FRAME::Load_Module_From_BOARD( MODULE* aModule )
{
    MODULE* newModule;
    PCB_EDIT_FRAME* frame = (PCB_EDIT_FRAME*) Kiway().Player( FRAME_PCB, false );

    if( frame == NULL )     // happens if no board editor opened
        return false;

    if( aModule == NULL )
    {
        if( ! frame->GetBoard() || ! frame->GetBoard()->m_Modules )
            return false;

        aModule = SelectFootprint( frame->GetBoard() );
    }

    if( aModule == NULL )
        return false;

    SetCurItem( NULL );

    Clear_Pcb( false );

    GetBoard()->m_Status_Pcb = 0;
    newModule = new MODULE( *aModule );
    newModule->SetParent( GetBoard() );
    newModule->SetLink( aModule->GetTimeStamp() );

    aModule = newModule;

    GetBoard()->Add( newModule );

    newModule->ClearFlags();

    // Clear references to net info, because the footprint editor
    // does know any thing about nets handled by the current edited board.
    // Morever the main board can change or the net info relative to this main board
    // can change while editing this footprint in the footprint editor
    for( D_PAD* pad = newModule->Pads(); pad; pad = pad->Next() )
        pad->SetNetCode( NETINFO_LIST::UNCONNECTED );

    SetCrossHairPosition( wxPoint( 0, 0 ) );
    PlaceModule( newModule, NULL );

    // Put it on FRONT layer,
    // because this is the default in ModEdit, and in libs
    if( newModule->GetLayer() != LAYER_N_FRONT )
        newModule->Flip( newModule->GetPosition() );

    // Put it in orientation 0,
    // because this is the default orientation in ModEdit, and in libs
    Rotate_Module( NULL, newModule, 0, false );
    GetScreen()->ClrModify();
    Zoom_Automatique( false );

    return true;
}
/* Creates the footprint shape list.
 * Since module shape is customizable after the placement we cannot share them;
 * instead we opt for the one-module-one-shape-one-component-one-device approach
 */
static void CreateShapesSection( FILE* aFile, BOARD* aPcb )
{
    MODULE*     module;
    D_PAD*      pad;
    const char* layer;
    wxString    pinname;
    const char* mirror = "0";

    fputs( "$SHAPES\n", aFile );

    const LSET all_cu = LSET::AllCuMask();

    for( module = aPcb->m_Modules; module; module = module->Next() )
    {
        FootprintWriteShape( aFile, module );

        for( pad = module->Pads(); pad; pad = pad->Next() )
        {
            /* Funny thing: GenCAD requires the pad side even if you use
             *  padstacks (which are theorically optional but gerbtools
             *requires* them). Now the trouble thing is that 'BOTTOM'
             *  is interpreted by someone as a padstack flip even
             *  if the spec explicitly says it's not... */
            layer = "ALL";

            if( ( pad->GetLayerSet() & all_cu ) == LSET( B_Cu ) )
            {
                layer = module->GetFlag() ? "TOP" : "BOTTOM";
            }
            else if( ( pad->GetLayerSet() & all_cu ) == LSET( F_Cu ) )
            {
                layer = module->GetFlag() ? "BOTTOM" : "TOP";
            }

            pad->StringPadName( pinname );

            if( pinname.IsEmpty() )
                pinname = wxT( "none" );

            double orient = pad->GetOrientation() - module->GetOrientation();
            NORMALIZE_ANGLE_POS( orient );

            // Bottom side modules use the flipped padstack
            fprintf( aFile, (module->GetFlag()) ?
                     "PIN %s PAD%dF %g %g %s %g %s\n" :
                     "PIN %s PAD%d %g %g %s %g %s\n",
                     TO_UTF8( pinname ), pad->GetSubRatsnest(),
                     pad->GetPos0().x / SCALE_FACTOR,
                     -pad->GetPos0().y / SCALE_FACTOR,
                     layer, orient / 10.0, mirror );
        }
    }

    fputs( "$ENDSHAPES\n\n", aFile );
}
示例#5
0
PNS_PCBNEW_RULE_RESOLVER::PNS_PCBNEW_RULE_RESOLVER( BOARD* aBoard, PNS::ROUTER* aRouter ) :
    m_router( aRouter ),
    m_board( aBoard )
{
    PNS::NODE* world = m_router->GetWorld();

    PNS::TOPOLOGY topo( world );
    m_netClearanceCache.resize( m_board->GetNetCount() );

    for( unsigned int i = 0; i < m_board->GetNetCount(); i++ )
    {
        NETINFO_ITEM* ni = m_board->FindNet( i );

        if( ni == NULL )
            continue;

        CLEARANCE_ENT ent;
        ent.coupledNet = DpCoupledNet( i );

        wxString netClassName = ni->GetClassName();
        NETCLASSPTR nc = m_board->GetDesignSettings().m_NetClasses.Find( netClassName );

        int clearance = nc->GetClearance();
        ent.clearance = clearance;
        m_netClearanceCache[i] = ent;

        wxLogTrace( "PNS", "Add net %u netclass %s clearance %d", i, netClassName.mb_str(), clearance );
    }

    for( MODULE* mod = m_board->m_Modules; mod ; mod = mod->Next() )
    {
        auto moduleClearance = mod->GetLocalClearance();

        for( D_PAD* pad = mod->Pads(); pad; pad = pad->Next() )
        {
            int padClearance = pad->GetLocalClearance();

            if( padClearance > 0 )
                m_localClearanceCache[ pad ] = padClearance;

            else if( moduleClearance > 0 )
                m_localClearanceCache[ pad ] = moduleClearance;
        }
    }

    //printf("DefaultCL : %d\n",  m_board->GetDesignSettings().m_NetClasses.Find ("Default clearance")->GetClearance());

    m_overrideEnabled = false;
    m_defaultClearance = Millimeter2iu( 0.254 );    // m_board->m_NetClasses.Find ("Default clearance")->GetClearance();
    m_overrideNetA = 0;
    m_overrideNetB = 0;
    m_overrideClearance = 0;
}
示例#6
0
MODULE* PCB_EDIT_FRAME::Create_MuWaveBasicShape( const wxString& name, int pad_count )
{
    MODULE*  module;
    int      pad_num = 1;
    wxString Line;

    module = Create_1_Module( name );

    if( module == NULL )
        return NULL;

    #define DEFAULT_SIZE 30
    module->SetTimeStamp( GetNewTimeStamp() );

    module->Value().SetSize( wxSize( DEFAULT_SIZE, DEFAULT_SIZE ) );

    module->Value().SetPos0( wxPoint( 0, -DEFAULT_SIZE ) );

    module->Value().Offset( wxPoint( 0, module->Value().GetPos0().y ) );

    module->Value().SetThickness( DEFAULT_SIZE / 4 );

    module->Reference().SetSize( wxSize( DEFAULT_SIZE, DEFAULT_SIZE ) );

    module->Reference().SetPos0( wxPoint( 0, DEFAULT_SIZE ) );

    module->Reference().Offset( wxPoint( 0, module->Reference().GetPos0().y ) );

    module->Reference().SetThickness( DEFAULT_SIZE / 4 );

    // Create 2 pads used in gaps and stubs.  The gap is between these 2 pads
    // the stub is the pad 2
    while( pad_count-- )
    {
        D_PAD* pad = new D_PAD( module );

        module->Pads().PushFront( pad );

        int tw = GetBoard()->GetCurrentTrackWidth();
        pad->SetSize( wxSize( tw, tw ) );

        pad->SetPosition( module->GetPosition() );
        pad->SetShape( PAD_RECT );
        pad->SetAttribute( PAD_SMD );
        pad->SetLayerMask( LAYER_FRONT );

        Line.Printf( wxT( "%d" ), pad_num );
        pad->SetPadName( Line );
        pad_num++;
    }

    return module;
}
/* Extract the D356 record from the modules (pads) */
static void build_pad_testpoints( BOARD *aPcb,
    std::vector <D356_RECORD>& aRecords )
{
    wxPoint origin = aPcb->GetAuxOrigin();

    for( MODULE *module = aPcb->m_Modules;
        module; module = module->Next() )
    {
        for( D_PAD *pad = module->Pads();  pad; pad = pad->Next() )
        {
            D356_RECORD rk;
            rk.access = compute_pad_access_code( aPcb, pad->GetLayerSet() );

            // It could be a mask only pad, we only handle pads with copper here
            if( rk.access != -1 )
            {
                rk.netname = pad->GetNetname();
                rk.refdes = module->GetReference();
                pad->StringPadName( rk.pin );
                rk.midpoint = false; // XXX MAYBE need to be computed (how?)
                const wxSize& drill = pad->GetDrillSize();
                rk.drill = std::min( drill.x, drill.y );
                rk.hole = (rk.drill != 0);
                rk.smd = pad->GetAttribute() == PAD_ATTRIB_SMD;
                rk.mechanical = (pad->GetAttribute() == PAD_ATTRIB_HOLE_NOT_PLATED);
                rk.x_location = pad->GetPosition().x - origin.x;
                rk.y_location = origin.y - pad->GetPosition().y;
                rk.x_size = pad->GetSize().x;

                // Rule: round pads have y = 0
                if( pad->GetShape() == PAD_SHAPE_CIRCLE )
                    rk.y_size = 0;
                else
                    rk.y_size = pad->GetSize().y;

                rk.rotation = -KiROUND( pad->GetOrientation() ) / 10;
                if( rk.rotation < 0 ) rk.rotation += 360;

                // the value indicates which sides are *not* accessible
                rk.soldermask = 3;
                if( pad->GetLayerSet()[F_Mask] )
                    rk.soldermask &= ~1;
                if( pad->GetLayerSet()[B_Mask] )
                    rk.soldermask &= ~2;

                aRecords.push_back( rk );
            }
        }
    }
}
/* Emit the netlist (which is actually the thing for which GenCAD is used these
 * days!); tracks are handled later */
static void CreateSignalsSection( FILE* aFile, BOARD* aPcb )
{
    wxString      msg;
    NETINFO_ITEM* net;
    D_PAD*        pad;
    MODULE*       module;
    int           NbNoConn = 1;

    fputs( "$SIGNALS\n", aFile );

    for( unsigned ii = 0; ii < aPcb->GetNetCount(); ii++ )
    {
        net = aPcb->FindNet( ii );

        if( net->GetNetname() == wxEmptyString ) // dummy netlist (no connection)
        {
            wxString msg; msg << wxT( "NoConnection" ) << NbNoConn++;
        }

        if( net->GetNet() <= 0 )  // dummy netlist (no connection)
            continue;

        msg = wxT( "SIGNAL " ) + net->GetNetname();

        fputs( TO_UTF8( msg ), aFile );
        fputs( "\n", aFile );

        for( module = aPcb->m_Modules; module; module = module->Next() )
        {
            for( pad = module->Pads(); pad; pad = pad->Next() )
            {
                wxString padname;

                if( pad->GetNetCode() != net->GetNet() )
                    continue;

                pad->StringPadName( padname );
                msg.Printf( wxT( "NODE %s %s" ),
                            GetChars( module->GetReference() ),
                            GetChars( padname ) );

                fputs( TO_UTF8( msg ), aFile );
                fputs( "\n", aFile );
            }
        }
    }

    fputs( "$ENDSIGNALS\n\n", aFile );
}
void BRDITEMS_PLOTTER::PlotDrillMarks()
{
    /* If small drills marks were requested prepare a clamp value to pass
       to the helper function */
    int small_drill = (GetDrillMarksType() == PCB_PLOT_PARAMS::SMALL_DRILL_SHAPE) ?
                        SMALL_DRILL : 0;

    /* In the filled trace mode drill marks are drawn white-on-black to scrape
       the underlying pad. This works only for drivers supporting color change,
       obviously... it means that:
       - PS, SVG and PDF output is correct (i.e. you have a 'donut' pad)
       - In HPGL you can't see them
       - In gerbers you can't see them, too. This is arguably the right thing to
         do since having drill marks and high speed drill stations is a sure
         recipe for broken tools and angry manufacturers. If you *really* want them
         you could start a layer with negative polarity to scrape the film.
       - In DXF they go into the 'WHITE' layer. This could be useful.
     */
    if( GetMode() == FILLED )
         m_plotter->SetColor( WHITE );

    for( TRACK *pts = m_board->m_Track; pts != NULL; pts = pts->Next() )
    {
        const VIA* via = dyn_cast<const VIA*>( pts );

        if( via )
            plotOneDrillMark( PAD_DRILL_CIRCLE, via->GetStart(),
                    wxSize( via->GetDrillValue(), 0 ),
                    wxSize( via->GetWidth(), 0 ), 0, small_drill );
    }

    for( MODULE *Module = m_board->m_Modules; Module != NULL; Module = Module->Next() )
    {
        for( D_PAD *pad = Module->Pads(); pad != NULL; pad = pad->Next() )
        {
            if( pad->GetDrillSize().x == 0 )
                continue;

            plotOneDrillMark( pad->GetDrillShape(),
                              pad->GetPosition(), pad->GetDrillSize(),
                              pad->GetSize(), pad->GetOrientation(),
                              small_drill );
        }
    }

    if( GetMode() == FILLED )
        m_plotter->SetColor( GetColor() );
}
示例#10
0
void PNS_ROUTER::SyncWorld()
{
    if( !m_board )
    {
        TRACEn( 0, "No board attached, aborting sync." );
        return;
    }

    ClearWorld();

    m_world = new PNS_NODE();

    for( MODULE* module = m_board->m_Modules; module; module = module->Next() )
    {
        for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() )
        {
            PNS_ITEM* solid = syncPad( pad );

            if( solid )
                m_world->Add( solid );
        }
    }

    for( TRACK* t = m_board->m_Track; t; t = t->Next() )
    {
        KICAD_T type = t->Type();
        PNS_ITEM* item = NULL;

        if( type == PCB_TRACE_T )
            item = syncTrack( t );
        else if( type == PCB_VIA_T )
            item = syncVia( static_cast<VIA*>( t ) );

        if( item )
            m_world->Add( item );
    }

    // TODO: Create resolvers in ctor, call resolver->SetBoard() in this->SetBoard() and delete it in dtor
    // TBD: Same remark as with m_sizes.SetMinimumTrackWidth in startRouting()
    int worstClearance = m_board->GetDesignSettings().GetBiggestClearanceValue();
    m_clearanceResolver = new PNS_PCBNEW_CLEARANCE_RESOLVER( this );
    m_world->SetClearanceResolver( m_clearanceResolver );
    m_world->SetMaxClearance( 4 * worstClearance );

    m_pairingResolver = new PCBNEW_PAIRING_RESOLVER( m_board );
    m_world->SetPairingResolver( m_pairingResolver );
}
示例#11
0
void PNS_KICAD_IFACE::SyncWorld( PNS::NODE *aWorld )
{
    if( !m_board )
    {
        wxLogTrace( "PNS", "No board attached, aborting sync." );
        return;
    }

    for( MODULE* module = m_board->m_Modules; module; module = module->Next() )
    {
        for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() )
        {
            std::unique_ptr< PNS::SOLID > solid = syncPad( pad );

            if( solid )
                aWorld->Add( std::move( solid ) );
        }
    }

    for( TRACK* t = m_board->m_Track; t; t = t->Next() )
    {
        KICAD_T type = t->Type();

        if( type == PCB_TRACE_T ) {
            std::unique_ptr< PNS::SEGMENT > segment = syncTrack( t );
            if( segment ) {
                aWorld->Add( std::move( segment ) );
            }
        } else if( type == PCB_VIA_T ) {
            std::unique_ptr< PNS::VIA > via = syncVia( static_cast<VIA*>( t ) );
            if( via ) {
                aWorld->Add( std::move( via ) );
            }
        }
    }

    int worstClearance = m_board->GetDesignSettings().GetBiggestClearanceValue();

    delete m_ruleResolver;
    m_ruleResolver = new PNS_PCBNEW_RULE_RESOLVER( m_board, m_router );

    aWorld->SetRuleResolver( m_ruleResolver );
    aWorld->SetMaxClearance( 4 * worstClearance );
}
示例#12
0
void PNS_ROUTER::SyncWorld()
{
    if( !m_board )
    {
        TRACEn( 0, "No board attached, aborting sync." );
        return;
    }

    ClearWorld();

    m_world = new PNS_NODE();

    for( MODULE* module = m_board->m_Modules; module; module = module->Next() )
    {
        for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() )
        {
            PNS_ITEM* solid = syncPad( pad );

            if( solid )
                m_world->Add( solid );
        }
    }

    for( TRACK* t = m_board->m_Track; t; t = t->Next() )
    {
        KICAD_T type = t->Type();
        PNS_ITEM* item = NULL;

        if( type == PCB_TRACE_T )
            item = syncTrack( t );
        else if( type == PCB_VIA_T )
            item = syncVia( static_cast<VIA*>( t ) );

        if( item )
            m_world->Add( item );
    }

    int worstClearance = m_board->GetDesignSettings().GetBiggestClearanceValue();
    m_clearanceFunc = new PNS_PCBNEW_CLEARANCE_FUNC( this );
    m_world->SetClearanceFunctor( m_clearanceFunc );
    m_world->SetMaxClearance( 4 * worstClearance );
}
示例#13
0
void BOARD::DrawHighLight( EDA_DRAW_PANEL* am_canvas, wxDC* DC, int aNetCode )
{
    GR_DRAWMODE draw_mode;

    if( IsHighLightNetON() )
        draw_mode = GR_HIGHLIGHT | GR_OR;
    else
        draw_mode = GR_AND | GR_HIGHLIGHT;

    // Redraw zones
    for( int ii = 0; ii < GetAreaCount(); ii++ )
    {
        ZONE_CONTAINER* zone = GetArea( ii );

        if( zone->GetNetCode() == aNetCode )
        {
            zone->Draw( am_canvas, DC, draw_mode );
        }
    }

    // Redraw any pads that have aNetCode
    for( MODULE* module = m_Modules; module; module = module->Next() )
    {
        for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() )
        {
            if( pad->GetNetCode() == aNetCode )
            {
                pad->Draw( am_canvas, DC, draw_mode );
            }
        }
    }

    // Redraw track and vias that have aNetCode
    for( TRACK* seg = m_Track; seg; seg = seg->Next() )
    {
        if( seg->GetNetCode() == aNetCode )
        {
            seg->Draw( am_canvas, DC, draw_mode );
        }
    }
}
示例#14
0
void BOARD::DrawHighLight( EDA_DRAW_PANEL* am_canvas, wxDC* DC, int aNetCode )
{
    GR_DRAWMODE draw_mode;

    if( IsHighLightNetON() )
        draw_mode = GR_HIGHLIGHT | GR_OR;
    else
        draw_mode = GR_AND | GR_HIGHLIGHT;

    // Redraw ZONE_CONTAINERS
    BOARD::ZONE_CONTAINERS& zones = m_ZoneDescriptorList;

    for( BOARD::ZONE_CONTAINERS::iterator zc = zones.begin(); zc!=zones.end(); ++zc )
    {
        if( (*zc)->GetNet() == aNetCode )
        {
            (*zc)->Draw( am_canvas, DC, draw_mode );
        }
    }

    // Redraw any pads that have aNetCode
    for( MODULE* module = m_Modules; module; module = module->Next() )
    {
        for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() )
        {
            if( pad->GetNet() == aNetCode )
            {
                pad->Draw( am_canvas, DC, draw_mode );
            }
        }
    }

    // Redraw track and vias that have aNetCode
    for( TRACK* seg = m_Track; seg; seg = seg->Next() )
    {
        if( seg->GetNet() == aNetCode )
        {
            seg->Draw( am_canvas, DC, draw_mode );
        }
    }
}
示例#15
0
MODULE* PCB_EDIT_FRAME::CreateMuWaveBaseFootprint( const wxString& aValue,
                                                   int aTextSize, int aPadCount )
{
    MODULE* module = CreateNewModule( aValue );

    if( aTextSize > 0 )
    {
        module->Reference().SetSize( wxSize( aTextSize, aTextSize ) );
        module->Reference().SetThickness( aTextSize/5 );
        module->Value().SetSize( wxSize( aTextSize, aTextSize ) );
        module->Value().SetThickness( aTextSize/5 );
    }

    // Create 2 pads used in gaps and stubs.  The gap is between these 2 pads
    // the stub is the pad 2
    wxString Line;
    int pad_num = 1;

    while( aPadCount-- )
    {
        D_PAD* pad = new D_PAD( module );

        module->Pads().PushFront( pad );

        int tw = GetDesignSettings().GetCurrentTrackWidth();
        pad->SetSize( wxSize( tw, tw ) );

        pad->SetPosition( module->GetPosition() );
        pad->SetShape( PAD_SHAPE_RECT );
        pad->SetAttribute( PAD_ATTRIB_SMD );
        pad->SetLayerSet( F_Cu );

        Line.Printf( wxT( "%d" ), pad_num );
        pad->SetPadName( Line );
        pad_num++;
    }

    return module;
}
int PCBNEW_CONTROL::PadDisplayMode( const TOOL_EVENT& aEvent )
{
    KIGFX::PCB_PAINTER* painter =
            static_cast<KIGFX::PCB_PAINTER*>( m_frame->GetGalCanvas()->GetView()->GetPainter() );
    KIGFX::PCB_RENDER_SETTINGS* settings =
            static_cast<KIGFX::PCB_RENDER_SETTINGS*>( painter->GetSettings() );
    DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)m_frame->GetDisplayOptions();

    // Apply new display options to the GAL canvas
    displ_opts->m_DisplayPadFill = !displ_opts->m_DisplayPadFill;
    settings->LoadDisplayOptions( displ_opts );

    for( MODULE* module = getModel<BOARD>()->m_Modules; module; module = module->Next() )
    {
        for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() )
            pad->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
    }

    m_frame->GetGalCanvas()->Refresh();

    return 0;
}
void NETINFO_LIST::buildPadsFullList()
{
    /*
     * initialize:
     *   m_Pads (list of pads)
     * set m_Status_Pcb = LISTE_PAD_OK;
     * also clear m_Pcb->m_FullRatsnest that could have bad data
     *   (m_Pcb->m_FullRatsnest uses pointer to pads)
     * Be aware NETINFO_ITEM* BOARD::FindNet( const wxString& aNetname )
     * when search a net by its net name does a binary search
     * and expects to have a nets list sorted by an alphabetic case sensitive sort
     * So do not change the sort function used here
     */

    if( m_Parent->m_Status_Pcb & LISTE_PAD_OK )
        return;

    // empty the old list
    m_PadsFullList.clear();
    m_Parent->m_FullRatsnest.clear();

    // Clear variables used in ratsnest computation
    for( MODULE* module = m_Parent->m_Modules;  module;  module = module->Next() )
    {
        for( D_PAD* pad = module->Pads();  pad;  pad = pad->Next() )
        {
            m_PadsFullList.push_back( pad );

            pad->SetSubRatsnest( 0 );
            pad->SetParent( module );
        }
    }

    // Sort pad list per net
    sort( m_PadsFullList.begin(), m_PadsFullList.end(), padlistSortByNetnames );

    m_Parent->m_Status_Pcb = LISTE_PAD_OK;
}
void NETINFO_MAPPING::Update()
{
    // Collect all the used nets
    std::set<int> nets;

    // Be sure that the unconnected gets 0 and is mapped as 0
    nets.insert( 0 );

    // Zones
    for( int i = 0; i < m_board->GetAreaCount(); ++i )
        nets.insert( m_board->GetArea( i )->GetNetCode() );

    // Tracks
    for( TRACK* track = m_board->m_Track; track; track = track->Next() )
        nets.insert( track->GetNetCode() );

    // Modules/pads
    for( MODULE* module = m_board->m_Modules; module; module = module->Next() )
    {
        for( D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() )
        {
            nets.insert( pad->GetNetCode() );
        }
    }

    // Segzones
    for( SEGZONE* zone = m_board->m_Zone; zone; zone = zone->Next() )
        nets.insert( zone->GetNetCode() );

    // Prepare the new mapping
    m_netMapping.clear();

    // Now the nets variable stores all the used net codes (not only for pads) and we are ready to
    // assign new consecutive net numbers
    int newNetCode = 0;
    for( std::set<int>::const_iterator it = nets.begin(), itEnd = nets.end(); it != itEnd; ++it )
        m_netMapping[*it] = newNetCode++;
}
void PCB_BASE_FRAME::OnTogglePadDrawMode( wxCommandEvent& aEvent )
{
    auto displ_opts = (PCB_DISPLAY_OPTIONS*)GetDisplayOptions();

    displ_opts->m_DisplayPadFill = !displ_opts->m_DisplayPadFill;
    EDA_DRAW_PANEL_GAL* gal = GetGalCanvas();

    if( gal )
    {
        // Apply new display options to the GAL canvas
        auto view = static_cast<KIGFX::PCB_VIEW*>( gal->GetView() );
        view->UpdateDisplayOptions( displ_opts );

        // Update pads
        BOARD* board = GetBoard();
        for( MODULE* module = board->m_Modules; module; module = module->Next() )
        {
            for( auto pad : module->Pads() )
                view->Update( pad, KIGFX::GEOMETRY );
        }
    }

    m_canvas->Refresh();
}
void EDA_3D_CANVAS::buildTechLayers3DView( REPORTER* aErrorMessages, REPORTER* aActivity )
{
    BOARD* pcb = GetBoard();
    bool useTextures = isRealisticMode() && isEnabled( FL_RENDER_TEXTURES );

    // Number of segments to draw a circle using segments
    const int       segcountforcircle   = 18;
    double          correctionFactor    = 1.0 / cos( M_PI / (segcountforcircle * 2) );
    const int       segcountLowQuality  = 12;   // segments to draw a circle with low quality
                                                // to reduce time calculations
                                                // for holes and items which do not need
                                                // a fine representation

    double          correctionFactorLQ = 1.0 / cos( M_PI / (segcountLowQuality * 2) );

    // segments to draw a circle to build texts. Is is used only to build
    // the shape of each segment of the stroke font, therefore no need to have
    // many segments per circle.
    const int       segcountInStrokeFont = 8;

    SHAPE_POLY_SET bufferPolys;
    SHAPE_POLY_SET allLayerHoles;              // Contains through holes, calculated only once
    SHAPE_POLY_SET bufferPcbOutlines;          // stores the board main outlines

    // Build a polygon from edge cut items
    wxString msg;

    if( !pcb->GetBoardPolygonOutlines( bufferPcbOutlines, allLayerHoles, &msg ) )
    {
        if( aErrorMessages )
        {
            msg << wxT("\n") <<
                _("Unable to calculate the board outlines.\n"
                  "Therefore use the board boundary box.") << wxT("\n\n");
            aErrorMessages->Report( msg, REPORTER::RPT_WARNING );
        }
    }

    // Build board holes, with no optimization of large holes shape.
    buildBoardThroughHolesPolygonList( allLayerHoles, segcountLowQuality, false );

    // draw graphic items, on technical layers

    static const LAYER_ID teckLayerList[] = {
        B_Adhes,
        F_Adhes,
        B_Paste,
        F_Paste,
        B_SilkS,
        F_SilkS,
        B_Mask,
        F_Mask,
    };

    // User layers are not drawn here, only technical layers
    for( LSEQ seq = LSET::AllTechMask().Seq( teckLayerList, DIM( teckLayerList ) );  seq;  ++seq )
    {
        LAYER_ID layer = *seq;

        if( !is3DLayerEnabled( layer ) )
            continue;

        if( layer == Edge_Cuts && isEnabled( FL_SHOW_BOARD_BODY )  )
            continue;

        if( aActivity )
            aActivity->Report( wxString::Format( _( "Build layer %s" ), LSET::Name( layer ) ) );

        bufferPolys.RemoveAllContours();

        for( BOARD_ITEM* item = pcb->m_Drawings; item; item = item->Next() )
        {
            if( !item->IsOnLayer( layer ) )
                continue;

            switch( item->Type() )
            {
            case PCB_LINE_T:
                ( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon(
                        bufferPolys, 0, segcountforcircle, correctionFactor );
                break;

            case PCB_TEXT_T:
                ( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygonSet(
                        bufferPolys, 0, segcountLowQuality, 1.0 );
                break;

            default:
                break;
            }
        }

        for( MODULE* module = pcb->m_Modules; module; module = module->Next() )
        {
            if( layer == F_SilkS || layer == B_SilkS )
            {
                // On silk screen layers, the pad shape is only the pad outline
                // never a filled shape
                D_PAD*  pad = module->Pads();
                int     linewidth = g_DrawDefaultLineThickness;

                for( ; pad; pad = pad->Next() )
                {
                    if( !pad->IsOnLayer( layer ) )
                        continue;

                    buildPadShapeThickOutlineAsPolygon( pad, bufferPolys,
                            linewidth, segcountforcircle, correctionFactor );
                }
            }
            else
                module->TransformPadsShapesWithClearanceToPolygon( layer,
                        bufferPolys, 0, segcountforcircle, correctionFactor );

            // On tech layers, use a poor circle approximation, only for texts (stroke font)
            module->TransformGraphicShapesWithClearanceToPolygonSet( layer,
                    bufferPolys, 0, segcountforcircle, correctionFactor, segcountInStrokeFont );
        }

        // Draw non copper zones
        if( isEnabled( FL_ZONE ) )
        {
            for( int ii = 0; ii < pcb->GetAreaCount(); ii++ )
            {
                ZONE_CONTAINER* zone = pcb->GetArea( ii );

                if( !zone->IsOnLayer( layer ) )
                    continue;

                zone->TransformSolidAreasShapesToPolygonSet(
                        bufferPolys, segcountLowQuality, correctionFactorLQ );
            }
        }

        // bufferPolys contains polygons to merge. Many overlaps .
        // Calculate merged polygons and remove pads and vias holes
        if( bufferPolys.IsEmpty() )
            continue;

        // Solder mask layers are "negative" layers.
        // Shapes should be removed from the full board area.
        if( layer == B_Mask || layer == F_Mask )
        {
            SHAPE_POLY_SET cuts = bufferPolys;
            bufferPolys = bufferPcbOutlines;

            cuts.Append(allLayerHoles);
            cuts.Simplify();

            bufferPolys.BooleanSubtract( cuts );
        }
        // Remove holes from Solder paste layers and silkscreen
        else if( layer == B_Paste || layer == F_Paste
                 || layer == B_SilkS || layer == F_SilkS  )
        {
            bufferPolys.BooleanSubtract( allLayerHoles );
        }

        int thickness = 0;

        if( layer != B_Mask && layer != F_Mask )
            thickness = GetPrm3DVisu().GetLayerObjectThicknessBIU( layer );

        int zpos = GetPrm3DVisu().GetLayerZcoordBIU( layer );

        if( layer == Edge_Cuts )
        {
            thickness = GetPrm3DVisu().GetLayerZcoordBIU( F_Cu )
                        - GetPrm3DVisu().GetLayerZcoordBIU( B_Cu );
            zpos = GetPrm3DVisu().GetLayerZcoordBIU( B_Cu )
                   + (thickness / 2);
        }
        else
        {
            // for Draw3D_SolidHorizontalPolyPolygons, zpos it the middle between bottom and top
            // sides.
            // However for top layers, zpos should be the bottom layer pos,
            // and for bottom layers, zpos should be the top layer pos.
            if( Get3DLayer_Z_Orientation( layer ) > 0 )
                zpos += thickness/2;
            else
                zpos -= thickness/2 ;
        }


        float zNormal = 1.0f; // When using thickness it will draw first the top and then botton (with z inverted)

        // If we are not using thickness, then the znormal must face the layer direction
        // because it will draw just one plane
        if( !thickness )
            zNormal = Get3DLayer_Z_Orientation( layer );


        setGLTechLayersColor( layer );
        Draw3D_SolidHorizontalPolyPolygons( bufferPolys, zpos,
                thickness, GetPrm3DVisu().m_BiuTo3Dunits, useTextures,
                zNormal );
    }
}
/* Traces the outline of the search block structures
 * The entire block follows the cursor
 */
static void DrawMovingBlockOutlines( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition,
                                     bool aErase )
{
    BASE_SCREEN*            screen = aPanel->GetScreen();
    FOOTPRINT_EDIT_FRAME*   moduleEditFrame = FOOTPRINT_EDIT_FRAME::GetActiveFootprintEditor( aPanel->GetParent() );

    wxASSERT( moduleEditFrame );
    MODULE* currentModule = moduleEditFrame->GetBoard()->m_Modules;

    BLOCK_SELECTOR* block = &screen->m_BlockLocate;
    GRSetDrawMode( aDC, g_XorMode );

    if( aErase )
    {
        block->Draw( aPanel, aDC, block->GetMoveVector(), g_XorMode, block->GetColor() );

        if( currentModule )
        {
            wxPoint     move_offset = -block->GetMoveVector();
            BOARD_ITEM* item = currentModule->GraphicalItems();

            for( ; item != NULL; item = item->Next() )
            {
                if( !item->IsSelected() )
                    continue;

                switch( item->Type() )
                {
                case PCB_MODULE_TEXT_T:
                case PCB_MODULE_EDGE_T:
                    item->Draw( aPanel, aDC, g_XorMode, move_offset );
                    break;

                default:
                    break;
                }
            }

            D_PAD* pad = currentModule->Pads();

            for( ; pad != NULL; pad = pad->Next() )
            {
                if( !pad->IsSelected() )
                    continue;

                pad->Draw( aPanel, aDC, g_XorMode, move_offset );
            }
        }
    }

    // Repaint new view.
    block->SetMoveVector( moduleEditFrame->GetCrossHairPosition() - block->GetLastCursorPosition() );

    block->Draw( aPanel, aDC, block->GetMoveVector(), g_XorMode, block->GetColor() );

    if( currentModule )
    {
        BOARD_ITEM* item = currentModule->GraphicalItems();
        wxPoint     move_offset = - block->GetMoveVector();

        for( ; item != NULL; item = item->Next() )
        {
            if( !item->IsSelected() )
                continue;

            switch( item->Type() )
            {
            case PCB_MODULE_TEXT_T:
            case PCB_MODULE_EDGE_T:
                item->Draw( aPanel, aDC, g_XorMode, move_offset );
                break;

            default:
                break;
            }
        }

        D_PAD* pad = currentModule->Pads();

        for( ; pad != NULL; pad = pad->Next() )
        {
            if( !pad->IsSelected() )
                continue;

            pad->Draw( aPanel, aDC, g_XorMode, move_offset );
        }
    }
}
void PCB_EDIT_FRAME::Show_1_Ratsnest( EDA_ITEM* item, wxDC* DC )
{
    D_PAD*   pt_pad = NULL;
    MODULE*  Module = NULL;

    if( GetBoard()->IsElementVisible(RATSNEST_VISIBLE) )
        return;

    if( ( GetBoard()->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK ) == 0 )
        Compile_Ratsnest( DC, true );

    if( item )
    {
        if( item->Type() == PCB_PAD_T )
        {
            pt_pad = (D_PAD*) item;
            Module = pt_pad->GetParent();
        }

        if( pt_pad ) // Displaying the ratsnest of the corresponding net.
        {
            SetMsgPanel( pt_pad );

            for( unsigned ii = 0; ii < GetBoard()->GetRatsnestsCount(); ii++ )
            {
                RATSNEST_ITEM* net = &GetBoard()->m_FullRatsnest[ii];

                if( net->GetNet() == pt_pad->GetNetCode() )
                {
                    if( ( net->m_Status & CH_VISIBLE ) != 0 )
                        continue;

                    net->m_Status |= CH_VISIBLE;

                    if( ( net->m_Status & CH_ACTIF ) == 0 )
                        continue;

                    net->Draw( m_canvas, DC, GR_XOR, wxPoint( 0, 0 ) );
                }
            }
        }
        else
        {
            if( item->Type() == PCB_MODULE_TEXT_T )
            {
                if( item->GetParent() && ( item->GetParent()->Type() == PCB_MODULE_T ) )
                    Module = static_cast<MODULE*>( item->GetParent() );
            }
            else if( item->Type() == PCB_MODULE_T )
            {
                Module = static_cast<MODULE*>( item );
            }

            if( Module )
            {
                SetMsgPanel( Module );
                pt_pad = Module->Pads();

                for( ; pt_pad != NULL; pt_pad = pt_pad->Next() )
                {
                    for( unsigned ii = 0; ii < GetBoard()->GetRatsnestsCount(); ii++ )
                    {
                        RATSNEST_ITEM* net = &GetBoard()->m_FullRatsnest[ii];

                        if( ( net->m_PadStart == pt_pad ) || ( net->m_PadEnd == pt_pad ) )
                        {
                            if( net->m_Status & CH_VISIBLE )
                                continue;

                            net->m_Status |= CH_VISIBLE;

                            if( (net->m_Status & CH_ACTIF) == 0 )
                                continue;

                            net->Draw( m_canvas, DC, GR_XOR, wxPoint( 0, 0 ) );
                        }
                    }
                }

                pt_pad = NULL;
            }
        }
    }

    // Erase if no pad or module has been selected.
    if( ( pt_pad == NULL ) && ( Module == NULL ) )
    {
        DrawGeneralRatsnest( DC );

        for( unsigned ii = 0; ii < GetBoard()->GetRatsnestsCount(); ii++ )
            GetBoard()->m_FullRatsnest[ii].m_Status &= ~CH_VISIBLE;
    }
}
示例#23
0
/* init board, route traces*/
void PCB_EDIT_FRAME::Autoroute( wxDC* DC, int mode )
{
    int      start, stop;
    MODULE*  Module = NULL;
    D_PAD*   Pad    = NULL;
    int      autoroute_net_code = -1;
    wxString msg;

    if( GetBoard()->GetCopperLayerCount() > 1 )
    {
        g_Route_Layer_TOP    = GetScreen()->m_Route_Layer_TOP;
        g_Route_Layer_BOTTOM = GetScreen()->m_Route_Layer_BOTTOM;
    }
    else
    {
        g_Route_Layer_TOP = g_Route_Layer_BOTTOM = LAYER_N_BACK;
    }

    switch( mode )
    {
    case ROUTE_NET:
        if( GetScreen()->GetCurItem() )
        {
            switch( GetScreen()->GetCurItem()->Type() )
            {
            case PCB_PAD_T:
                Pad = (D_PAD*) GetScreen()->GetCurItem();
                autoroute_net_code = Pad->GetNetCode();
                break;

            default:
                break;
            }
        }
        if( autoroute_net_code <= 0 )
        {
            wxMessageBox( _( "Net not selected" ) ); return;
        }
        break;

    case ROUTE_MODULE:
        Module = (MODULE*) GetScreen()->GetCurItem();
        if( (Module == NULL) || (Module->Type() != PCB_MODULE_T) )
        {
            wxMessageBox( _( "Module not selected" ) );
            return;
        }
        break;

    case ROUTE_PAD:
        Pad = (D_PAD*) GetScreen()->GetCurItem();

        if( (Pad == NULL)  || (Pad->Type() != PCB_PAD_T) )
        {
            wxMessageBox( _( "Pad not selected" ) );
            return;
        }

        break;
    }

    if( (GetBoard()->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK ) == 0 )
        Compile_Ratsnest( DC, true );

    /* Set the flag on the ratsnest to CH_ROUTE_REQ. */
    for( unsigned ii = 0; ii < GetBoard()->GetRatsnestsCount(); ii++ )
    {
        RATSNEST_ITEM* ptmp = &GetBoard()->m_FullRatsnest[ii];
        ptmp->m_Status &= ~CH_ROUTE_REQ;

        switch( mode )
        {
        case ROUTE_ALL:
            ptmp->m_Status |= CH_ROUTE_REQ;
            break;

        case ROUTE_NET:
            if( autoroute_net_code == ptmp->GetNet() )
                ptmp->m_Status |= CH_ROUTE_REQ;
            break;

        case ROUTE_MODULE:
        {
            D_PAD* pt_pad = (D_PAD*) Module->Pads();
            for( ; pt_pad != NULL; pt_pad = pt_pad->Next() )
            {
                if( ptmp->m_PadStart == pt_pad )
                    ptmp->m_Status |= CH_ROUTE_REQ;

                if( ptmp->m_PadEnd == pt_pad )
                    ptmp->m_Status |= CH_ROUTE_REQ;
            }

            break;
        }

        case ROUTE_PAD:
            if( ( ptmp->m_PadStart == Pad ) || ( ptmp->m_PadEnd == Pad ) )
                ptmp->m_Status |= CH_ROUTE_REQ;

            break;
        }
    }

    start = time( NULL );

    /* Calculation of no fixed routing to 5 mils and more. */
    RoutingMatrix.m_GridRouting = (int)GetScreen()->GetGridSize().x;

    if( RoutingMatrix.m_GridRouting < (5*IU_PER_MILS) )
        RoutingMatrix.m_GridRouting = 5*IU_PER_MILS;


    /* Calculated ncol and nrow, matrix size for routing. */
    RoutingMatrix.ComputeMatrixSize( GetBoard() );

    m_messagePanel->EraseMsgBox();

    /* Map the board */
    RoutingMatrix.m_RoutingLayersCount = 1;

    if( g_Route_Layer_TOP != g_Route_Layer_BOTTOM )
        RoutingMatrix.m_RoutingLayersCount = 2;

    if( RoutingMatrix.InitRoutingMatrix() < 0 )
    {
        wxMessageBox( _( "No memory for autorouting" ) );
        RoutingMatrix.UnInitRoutingMatrix();  /* Free memory. */
        return;
    }

    SetStatusText( _( "Place Cells" ) );
    PlaceCells( GetBoard(), -1, FORCE_PADS );

    /* Construction of the track list for router. */
    RoutingMatrix.m_RouteCount = Build_Work( GetBoard() );

    // DisplayRoutingMatrix( m_canvas, DC );

    Solve( DC, RoutingMatrix.m_RoutingLayersCount );

    /* Free memory. */
    FreeQueue();
    InitWork();             /* Free memory for the list of router connections. */
    RoutingMatrix.UnInitRoutingMatrix();
    stop = time( NULL ) - start;
    msg.Printf( wxT( "time = %d second%s" ), stop, ( stop == 1 ) ? wxT( "" ) : wxT( "s" ) );
    SetStatusText( msg );
}
void EXCELLON_WRITER::BuildHolesList( LAYER_PAIR aLayerPair,
                                      bool aGenerateNPTH_list )
{
    HOLE_INFO new_hole;

    m_holeListBuffer.clear();
    m_toolListBuffer.clear();

    wxASSERT(  aLayerPair.first < aLayerPair.second );  // fix the caller

    // build hole list for vias
    if( ! aGenerateNPTH_list )  // vias are always plated !
    {
        for( VIA* via = GetFirstVia( m_pcb->m_Track ); via; via = GetFirstVia( via->Next() ) )
        {
            int hole_sz = via->GetDrillValue();

            if( hole_sz == 0 )   // Should not occur.
                continue;

            new_hole.m_Tool_Reference = -1;         // Flag value for Not initialized
            new_hole.m_Hole_Orient    = 0;
            new_hole.m_Hole_Diameter  = hole_sz;
            new_hole.m_Hole_NotPlated = false;
            new_hole.m_Hole_Size.x = new_hole.m_Hole_Size.y = new_hole.m_Hole_Diameter;

            new_hole.m_Hole_Shape = 0;              // hole shape: round
            new_hole.m_Hole_Pos = via->GetStart();

            via->LayerPair( &new_hole.m_Hole_Top_Layer, &new_hole.m_Hole_Bottom_Layer );

            // LayerPair() returns params with m_Hole_Bottom_Layer > m_Hole_Top_Layer
            // Remember: top layer = 0 and bottom layer = 31 for through hole vias
            // Any captured via should be from aLayerPair.first to aLayerPair.second exactly.
            if( new_hole.m_Hole_Top_Layer    != aLayerPair.first ||
                new_hole.m_Hole_Bottom_Layer != aLayerPair.second )
                continue;

            m_holeListBuffer.push_back( new_hole );
        }
    }

    if( aLayerPair == LAYER_PAIR( F_Cu, B_Cu ) )
    {
        // add holes for thru hole pads
        for( MODULE* module = m_pcb->m_Modules;  module;  module = module->Next() )
        {
            for( D_PAD* pad = module->Pads();  pad;  pad = pad->Next() )
            {
                if( !m_merge_PTH_NPTH )
                {
                    if( !aGenerateNPTH_list && pad->GetAttribute() == PAD_ATTRIB_HOLE_NOT_PLATED )
                        continue;

                    if( aGenerateNPTH_list && pad->GetAttribute() != PAD_ATTRIB_HOLE_NOT_PLATED )
                        continue;
                }

                if( pad->GetDrillSize().x == 0 )
                    continue;

                new_hole.m_Hole_NotPlated = (pad->GetAttribute() == PAD_ATTRIB_HOLE_NOT_PLATED);
                new_hole.m_Tool_Reference = -1;         // Flag is: Not initialized
                new_hole.m_Hole_Orient    = pad->GetOrientation();
                new_hole.m_Hole_Shape     = 0;           // hole shape: round
                new_hole.m_Hole_Diameter  = std::min( pad->GetDrillSize().x, pad->GetDrillSize().y );
                new_hole.m_Hole_Size.x    = new_hole.m_Hole_Size.y = new_hole.m_Hole_Diameter;

                if( pad->GetDrillShape() != PAD_DRILL_SHAPE_CIRCLE )
                    new_hole.m_Hole_Shape = 1; // oval flag set

                new_hole.m_Hole_Size         = pad->GetDrillSize();
                new_hole.m_Hole_Pos          = pad->GetPosition();  // hole position
                new_hole.m_Hole_Bottom_Layer = B_Cu;
                new_hole.m_Hole_Top_Layer    = F_Cu;    // pad holes are through holes
                m_holeListBuffer.push_back( new_hole );
            }
        }
    }

    // Sort holes per increasing diameter value
    sort( m_holeListBuffer.begin(), m_holeListBuffer.end(), CmpHoleSettings );

    // build the tool list
    int last_hole = -1;     // Set to not initialized (this is a value not used
                            // for m_holeListBuffer[ii].m_Hole_Diameter)
    bool last_notplated_opt = false;

    DRILL_TOOL new_tool( 0, false );
    unsigned   jj;

    for( unsigned ii = 0; ii < m_holeListBuffer.size(); ii++ )
    {
        if( m_holeListBuffer[ii].m_Hole_Diameter != last_hole ||
            m_holeListBuffer[ii].m_Hole_NotPlated != last_notplated_opt )
        {
            new_tool.m_Diameter = m_holeListBuffer[ii].m_Hole_Diameter;
            new_tool.m_Hole_NotPlated = m_holeListBuffer[ii].m_Hole_NotPlated;
            m_toolListBuffer.push_back( new_tool );
            last_hole = new_tool.m_Diameter;
            last_notplated_opt = new_tool.m_Hole_NotPlated;
        }

        jj = m_toolListBuffer.size();

        if( jj == 0 )
            continue;                                        // Should not occurs

        m_holeListBuffer[ii].m_Tool_Reference = jj;          // Tool value Initialized (value >= 1)

        m_toolListBuffer.back().m_TotalCount++;

        if( m_holeListBuffer[ii].m_Hole_Shape )
            m_toolListBuffer.back().m_OvalCount++;
    }
}
void DIALOG_GENDRILL::InitDisplayParams()
{
    wxString msg;

    m_Choice_Unit->SetSelection( m_UnitDrillIsInch ? 1 : 0 );
    m_Choice_Zeros_Format->SetSelection( m_ZerosFormat );
    UpdatePrecisionOptions();
    m_Check_Minimal->SetValue( m_MinimalHeader );

    if( m_DrillOriginIsAuxAxis )
        m_Choice_Drill_Offset->SetSelection( 1 );

    m_Check_Mirror->SetValue( m_Mirror );
    m_Check_Merge_PTH_NPTH->SetValue( m_Merge_PTH_NPTH );
    m_Choice_Drill_Map->SetSelection( m_mapFileType );
    m_ViaDrillValue->SetLabel( _( "Use Netclass values" ) );
    m_MicroViaDrillValue->SetLabel( _( "Use Netclass values" ) );

    // See if we have some buried vias or/and microvias, and display
    // microvias drill value if so
    m_throughViasCount = 0;
    m_microViasCount   = 0;
    m_blindOrBuriedViasCount = 0;

    for( TRACK* track = m_parent->GetBoard()->m_Track; track != NULL; track = track->Next() )
    {
        const VIA *via = dynamic_cast<const VIA*>( track );
        if( via )
        {
            switch( via->GetViaType() )
            {
            case VIA_THROUGH:
                m_throughViasCount++;
                break;

            case VIA_MICROVIA:
                m_microViasCount++;
                break;

            case VIA_BLIND_BURIED:
                m_blindOrBuriedViasCount++;
                break;

            default:
                break;
            }
        }
    }

    m_MicroViaDrillValue->Enable( m_microViasCount );

    // Count plated pad holes and not plated pad holes:
    m_platedPadsHoleCount    = 0;
    m_notplatedPadsHoleCount = 0;

    for( MODULE* module = m_parent->GetBoard()->m_Modules;  module;  module = module->Next() )
    {
        for( D_PAD* pad = module->Pads(); pad != NULL; pad = pad->Next() )
        {
            if( pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
            {
                if( pad->GetDrillSize().x != 0 )
                {
                    if( pad->GetAttribute() == PAD_ATTRIB_HOLE_NOT_PLATED )
                        m_notplatedPadsHoleCount++;
                    else
                        m_platedPadsHoleCount++;
                }
            }
            else
            {
                if( pad->GetDrillSize().x != 0 && pad->GetDrillSize().y != 0 )
                {
                    if( pad->GetAttribute() == PAD_ATTRIB_HOLE_NOT_PLATED )
                        m_notplatedPadsHoleCount++;
                    else
                        m_platedPadsHoleCount++;
                }
            }
        }
    }

    // Display hole counts:
    msg = m_PlatedPadsCountInfoMsg->GetLabel();
    msg << wxT( " " ) << m_platedPadsHoleCount;
    m_PlatedPadsCountInfoMsg->SetLabel( msg );

    msg = m_NotPlatedPadsCountInfoMsg->GetLabel();
    msg << wxT( " " ) << m_notplatedPadsHoleCount;
    m_NotPlatedPadsCountInfoMsg->SetLabel( msg );

    msg = m_ThroughViasInfoMsg->GetLabel();
    msg << wxT( " " ) << m_throughViasCount;
    m_ThroughViasInfoMsg->SetLabel( msg );

    msg = m_MicroViasInfoMsg->GetLabel();
    msg << wxT( " " ) << m_microViasCount;
    m_MicroViasInfoMsg->SetLabel( msg );

    msg = m_BuriedViasInfoMsg->GetLabel();
    msg << wxT( " " ) << m_blindOrBuriedViasCount;
    m_BuriedViasInfoMsg->SetLabel( msg );

    // Output directory
    m_outputDirectoryName->SetValue( m_plotOpts.GetOutputDirectory() );
}
void EDA_3D_CANVAS::buildBoardThroughHolesPolygonList( SHAPE_POLY_SET& allBoardHoles,
                                                int aSegCountPerCircle, bool aOptimizeLargeCircles )
{
    // hole diameter value to change seg count by circle:
    int small_hole_limit = Millimeter2iu( 1.0 );
    int copper_thickness = GetPrm3DVisu().GetCopperThicknessBIU();

    BOARD* pcb = GetBoard();

    // Build holes of through vias:
    for( TRACK* track = pcb->m_Track;  track;  track = track->Next() )
    {
        if( track->Type() != PCB_VIA_T )
            continue;

        VIA *via = static_cast<VIA*>( track );

        if( via->GetViaType() != VIA_THROUGH )
            continue;

        int holediameter = via->GetDrillValue();
        int hole_outer_radius = (holediameter + copper_thickness) / 2;

        TransformCircleToPolygon( allBoardHoles,
                                  via->GetStart(), hole_outer_radius,
                                  aSegCountPerCircle );
    }

    // Build holes of through pads:
    for( MODULE* footprint = pcb->m_Modules; footprint; footprint = footprint->Next() )
    {
        for( D_PAD* pad = footprint->Pads(); pad; pad = pad->Next() )
        {
            // Calculate a factor to apply to segcount for large holes ( > 1 mm)
            // (bigger pad drill size -> more segments) because holes in pads can have
            // very different sizes and optimizing this segcount gives a better look
            // Mainly mounting holes have a size bigger than small_hole_limit
            wxSize padHole = pad->GetDrillSize();

            if( ! padHole.x )       // Not drilled pad like SMD pad
                continue;

            // we use the hole diameter to calculate the seg count.
            // for round holes, padHole.x == padHole.y
            // for oblong holes, the diameter is the smaller of (padHole.x, padHole.y)
            int diam = std::min( padHole.x, padHole.y );
            int segcount = aSegCountPerCircle;

            if( diam > small_hole_limit )
            {
                double segFactor = (double)diam / small_hole_limit;
                segcount = (int)(aSegCountPerCircle * segFactor);

                // limit segcount to 48. For a circle this is a very good approx.
                if( segcount > 48 )
                    segcount = 48;
            }

            // The hole in the body is inflated by copper thickness.
            int inflate = copper_thickness;

            // If not plated, no copper.
            if( pad->GetAttribute () == PAD_HOLE_NOT_PLATED )
                inflate = 0;

            pad->BuildPadDrillShapePolygon( allBoardHoles, inflate, segcount );
        }
    }

    allBoardHoles.Simplify();
}
void EXCELLON_WRITER::BuildHolesList( int aFirstLayer,
                                      int aLastLayer,
                                      bool aExcludeThroughHoles,
                                      bool aGenerateNPTH_list,
                                      bool aMerge_PTH_NPTH )
{
    HOLE_INFO new_hole;
    int       hole_value;

    m_holeListBuffer.clear();
    m_toolListBuffer.clear();

    if( (aFirstLayer >= 0) && (aLastLayer >= 0) )
    {
        if( aFirstLayer > aLastLayer )
            std::swap( aFirstLayer, aLastLayer );
    }

    if ( aGenerateNPTH_list && aMerge_PTH_NPTH )
    {
        return;
    }

    // build hole list for vias
    if( ! aGenerateNPTH_list )  // vias are always plated !
    {
        for( VIA* via = GetFirstVia( m_pcb->m_Track ); via; via = GetFirstVia( via->Next() ) )
        {
            hole_value = via->GetDrillValue();

            if( hole_value == 0 )   // Should not occur.
                continue;

            new_hole.m_Tool_Reference = -1;         // Flag value for Not initialized
            new_hole.m_Hole_Orient    = 0;
            new_hole.m_Hole_Diameter  = hole_value;
            new_hole.m_Hole_Size.x = new_hole.m_Hole_Size.y = new_hole.m_Hole_Diameter;

            new_hole.m_Hole_Shape = 0;              // hole shape: round
            new_hole.m_Hole_Pos = via->GetStart();

            via->LayerPair( &new_hole.m_Hole_Top_Layer, &new_hole.m_Hole_Bottom_Layer );

            // LayerPair return params with m_Hole_Bottom_Layer > m_Hole_Top_Layer
            // Remember: top layer = 0 and bottom layer = 31 for through hole vias
            // the via should be at least from aFirstLayer to aLastLayer
            if( (new_hole.m_Hole_Top_Layer > aFirstLayer) && (aFirstLayer >= 0) )
                continue;   // via above the first layer

            if( (new_hole.m_Hole_Bottom_Layer < aLastLayer) && (aLastLayer >= 0) )
                continue;   // via below the last layer

            if( aExcludeThroughHoles && (new_hole.m_Hole_Bottom_Layer == B_Cu)
               && (new_hole.m_Hole_Top_Layer == F_Cu) )
                continue;

            m_holeListBuffer.push_back( new_hole );
        }
    }

    // build hole list for pads (assumed always through holes)
    if( !aExcludeThroughHoles || aGenerateNPTH_list )
    {
        for( MODULE* module = m_pcb->m_Modules;  module;  module = module->Next() )
        {
            // Read and analyse pads
            for( D_PAD* pad = module->Pads();  pad;  pad = pad->Next() )
            {
                if( ! aGenerateNPTH_list &&
                    pad->GetAttribute() == PAD_HOLE_NOT_PLATED &&
                    ! aMerge_PTH_NPTH )
                    continue;

                if( aGenerateNPTH_list && pad->GetAttribute() != PAD_HOLE_NOT_PLATED )
                    continue;

                if( pad->GetDrillSize().x == 0 )
                    continue;

                new_hole.m_Hole_NotPlated = (pad->GetAttribute() == PAD_HOLE_NOT_PLATED);
                new_hole.m_Tool_Reference = -1;         // Flag is: Not initialized
                new_hole.m_Hole_Orient    = pad->GetOrientation();
                new_hole.m_Hole_Shape     = 0;           // hole shape: round
                new_hole.m_Hole_Diameter  = std::min( pad->GetDrillSize().x, pad->GetDrillSize().y );
                new_hole.m_Hole_Size.x    = new_hole.m_Hole_Size.y = new_hole.m_Hole_Diameter;

                if( pad->GetDrillShape() != PAD_DRILL_CIRCLE )
                    new_hole.m_Hole_Shape = 1; // oval flag set

                new_hole.m_Hole_Size         = pad->GetDrillSize();
                new_hole.m_Hole_Pos          = pad->GetPosition();               // hole position
                new_hole.m_Hole_Bottom_Layer = B_Cu;
                new_hole.m_Hole_Top_Layer    = F_Cu;// pad holes are through holes
                m_holeListBuffer.push_back( new_hole );
            }
        }
    }

    // Sort holes per increasing diameter value
    sort( m_holeListBuffer.begin(), m_holeListBuffer.end(), CmpHoleDiameterValue );

    // build the tool list
    int        LastHole = -1; /* Set to not initialized (this is a value not used
                               * for m_holeListBuffer[ii].m_Hole_Diameter) */
    DRILL_TOOL new_tool( 0 );
    unsigned   jj;

    for( unsigned ii = 0; ii < m_holeListBuffer.size(); ii++ )
    {
        if( m_holeListBuffer[ii].m_Hole_Diameter != LastHole )
        {
            new_tool.m_Diameter = ( m_holeListBuffer[ii].m_Hole_Diameter );
            m_toolListBuffer.push_back( new_tool );
            LastHole = new_tool.m_Diameter;
        }

        jj = m_toolListBuffer.size();

        if( jj == 0 )
            continue;                                        // Should not occurs

        m_holeListBuffer[ii].m_Tool_Reference = jj;          // Tool value Initialized (value >= 1)

        m_toolListBuffer.back().m_TotalCount++;

        if( m_holeListBuffer[ii].m_Hole_Shape )
            m_toolListBuffer.back().m_OvalCount++;
    }
}
/*
 * Function GlobalChange_PadSettings
 * Function to change pad caracteristics for the given footprint
 * or alls footprints which look like the given footprint
 * aPad is the pattern. The given footprint is the parent of this pad
 * aSameFootprints: if true, make changes on all identical footprints
 * aPadShapeFilter: if true, make changes only on pads having the same shape as aPad
 * aPadOrientFilter: if true, make changes only on pads having the same orientation as aPad
 * aPadLayerFilter: if true, make changes only on pads having the same layers as aPad
 * aRedraw: if true: redraws the footprint
 * aSaveForUndo: if true: create an entry in the Undo/Redo list
 *        (usually: true in Schematic editor, false in Module editor)
 */
void PCB_BASE_FRAME::GlobalChange_PadSettings( D_PAD* aPad,
                                               bool aSameFootprints,
                                               bool aPadShapeFilter,
                                               bool aPadOrientFilter,
                                               bool aPadLayerFilter,
                                               bool aRedraw, bool aSaveForUndo )
{
    if( aPad == NULL )
        aPad = &GetDesignSettings().m_Pad_Master;

    MODULE* module = aPad->GetParent();

    if( module == NULL )
    {
        DisplayError( this, wxT( "Global_Import_Pad_Settings() Error: NULL module" ) );
        return;
    }

    // Search and copy the name of library reference.
    MODULE* Module_Ref = module;
    double pad_orient = aPad->GetOrientation() - Module_Ref->GetOrientation();

    // Prepare an undo list:
    if( aSaveForUndo )
    {
        PICKED_ITEMS_LIST itemsList;

        for( module = m_Pcb->m_Modules;  module;  module = module->Next() )
        {
            if( !aSameFootprints && (module != Module_Ref) )
                continue;

            if( module->GetFPID() != Module_Ref->GetFPID() )
                continue;

            bool   saveMe = false;

            for( D_PAD* pad = module->Pads();  pad;  pad = pad->Next() )
            {
                // Filters changes prohibited.
                if( aPadShapeFilter && ( pad->GetShape() != aPad->GetShape() ) )
                    continue;

                double currpad_orient = pad->GetOrientation() - module->GetOrientation();

                if( aPadOrientFilter && ( currpad_orient != pad_orient ) )
                    continue;

                if( aPadLayerFilter  &&  pad->GetLayerSet() != aPad->GetLayerSet() )
                    continue;

                saveMe = true;
            }

            if( saveMe )
            {
                ITEM_PICKER itemWrapper( module, UR_CHANGED );

                itemsList.PushItem( itemWrapper );
            }
        }

        SaveCopyInUndoList( itemsList, UR_CHANGED );
    }

    // Update the current module and same others modules if requested.
    for( module = m_Pcb->m_Modules;  module;  module = module->Next() )
    {
        if( !aSameFootprints && (module != Module_Ref) )
            continue;

        if( module->GetFPID() != Module_Ref->GetFPID() )
            continue;

        // Erase module on screen
        if( aRedraw )
        {
            module->SetFlags( DO_NOT_DRAW );
            m_canvas->RefreshDrawingRect( module->GetBoundingBox() );
            module->ClearFlags( DO_NOT_DRAW );
        }

        for( D_PAD* pad = module->Pads();  pad;  pad = pad->Next() )
        {
            // Filters changes prohibited.
            if( aPadShapeFilter && ( pad->GetShape() != aPad->GetShape() ) )
                continue;

            if( aPadOrientFilter &&  (pad->GetOrientation() - module->GetOrientation()) != pad_orient )
                continue;

            if( aPadLayerFilter )
            {
                if( pad->GetLayerSet() != aPad->GetLayerSet() )
                    continue;
                else
                    m_Pcb->m_Status_Pcb &= ~( LISTE_RATSNEST_ITEM_OK | CONNEXION_OK);
            }

            // Change characteristics:
            pad->SetAttribute( aPad->GetAttribute() );
            pad->SetShape( aPad->GetShape() );

            pad->SetLayerSet( aPad->GetLayerSet() );

            pad->SetSize( aPad->GetSize() );
            pad->SetDelta( aPad->GetDelta() );
            pad->SetOffset( aPad->GetOffset() );

            pad->SetDrillSize( aPad->GetDrillSize() );
            pad->SetDrillShape( aPad->GetDrillShape() );

            pad->SetOrientation( pad_orient + module->GetOrientation() );

            // copy also local mask margins, because these parameters usually depend on
            // pad sizes and layers
            pad->SetLocalSolderMaskMargin( aPad->GetLocalSolderMaskMargin() );
            pad->SetLocalSolderPasteMargin( aPad->GetLocalSolderPasteMargin() );
            pad->SetLocalSolderPasteMarginRatio( aPad->GetLocalSolderPasteMarginRatio() );

            if( pad->GetShape() != PAD_TRAPEZOID )
            {
                pad->SetDelta( wxSize( 0, 0 ) );
            }

            if( pad->GetShape() == PAD_CIRCLE )
            {
                // Ensure pad size.y = pad size.x
                int size = pad->GetSize().x;
                pad->SetSize( wxSize( size, size ) );
            }

            switch( pad->GetAttribute() )
            {
            case PAD_SMD:
            case PAD_CONN:
                pad->SetDrillSize( wxSize( 0, 0 ) );
                pad->SetOffset( wxPoint( 0, 0 ) );
                break;

            default:
                break;
            }
        }

        module->CalculateBoundingBox();

        if( aRedraw )
            m_canvas->RefreshDrawingRect( module->GetBoundingBox() );
    }

    OnModify();
}
void ZONE_CONTAINER::buildFeatureHoleList( BOARD* aPcb, SHAPE_POLY_SET& aFeatures )
{
    int segsPerCircle;
    double correctionFactor;

    // Set the number of segments in arc approximations
    if( m_ArcToSegmentsCount == ARC_APPROX_SEGMENTS_COUNT_HIGHT_DEF  )
        segsPerCircle = ARC_APPROX_SEGMENTS_COUNT_HIGHT_DEF;
    else
        segsPerCircle = ARC_APPROX_SEGMENTS_COUNT_LOW_DEF;

    /* calculates the coeff to compensate radius reduction of holes clearance
     * due to the segment approx.
     * For a circle the min radius is radius * cos( 2PI / s_CircleToSegmentsCount / 2)
     * s_Correction is 1 /cos( PI/s_CircleToSegmentsCount  )
     */
    correctionFactor = 1.0 / cos( M_PI / (double) segsPerCircle );

    aFeatures.RemoveAllContours();

    int outline_half_thickness = m_ZoneMinThickness / 2;

    int zone_clearance = std::max( m_ZoneClearance, GetClearance() );
    zone_clearance += outline_half_thickness;

    /* store holes (i.e. tracks and pads areas as polygons outlines)
     * in a polygon list
     */

    /* items ouside the zone bounding box are skipped
     * the bounding box is the zone bounding box + the biggest clearance found in Netclass list
     */
    EDA_RECT item_boundingbox;
    EDA_RECT zone_boundingbox  = GetBoundingBox();
    int      biggest_clearance = aPcb->GetDesignSettings().GetBiggestClearanceValue();
    biggest_clearance = std::max( biggest_clearance, zone_clearance );
    zone_boundingbox.Inflate( biggest_clearance );

    /*
     * First : Add pads. Note: pads having the same net as zone are left in zone.
     * Thermal shapes will be created later if necessary
     */
    int item_clearance;

    /* Use a dummy pad to calculate hole clerance when a pad is not on all copper layers
     * and this pad has a hole
     * This dummy pad has the size and shape of the hole
    * Therefore, this dummy pad is a circle or an oval.
     * A pad must have a parent because some functions expect a non null parent
     * to find the parent board, and some other data
     */
    MODULE dummymodule( aPcb );    // Creates a dummy parent
    D_PAD dummypad( &dummymodule );

    for( MODULE* module = aPcb->m_Modules;  module;  module = module->Next() )
    {
        D_PAD* nextpad;

        for( D_PAD* pad = module->Pads(); pad != NULL; pad = nextpad )
        {
            nextpad = pad->Next();  // pad pointer can be modified by next code, so
                                    // calculate the next pad here

            if( !pad->IsOnLayer( GetLayer() ) )
            {
                /* Test for pads that are on top or bottom only and have a hole.
                 * There are curious pads but they can be used for some components that are
                 * inside the board (in fact inside the hole. Some photo diodes and Leds are
                 * like this)
                 */
                if( pad->GetDrillSize().x == 0 && pad->GetDrillSize().y == 0 )
                    continue;

                // Use a dummy pad to calculate a hole shape that have the same dimension as
                // the pad hole
                dummypad.SetSize( pad->GetDrillSize() );
                dummypad.SetOrientation( pad->GetOrientation() );
                dummypad.SetShape( pad->GetDrillShape() == PAD_DRILL_SHAPE_OBLONG ?
                                   PAD_SHAPE_OVAL : PAD_SHAPE_CIRCLE );
                dummypad.SetPosition( pad->GetPosition() );

                pad = &dummypad;
            }

            // Note: netcode <=0 means not connected item
            if( ( pad->GetNetCode() != GetNetCode() ) || ( pad->GetNetCode() <= 0 ) )
            {
                item_clearance   = pad->GetClearance() + outline_half_thickness;
                item_boundingbox = pad->GetBoundingBox();
                item_boundingbox.Inflate( item_clearance );

                if( item_boundingbox.Intersects( zone_boundingbox ) )
                {
                    int clearance = std::max( zone_clearance, item_clearance );
                    pad->TransformShapeWithClearanceToPolygon( aFeatures,
                                                               clearance,
                                                               segsPerCircle,
                                                               correctionFactor );
                }

                continue;
            }

            // Pads are removed from zone if the setup is PAD_ZONE_CONN_NONE
            if( GetPadConnection( pad ) == PAD_ZONE_CONN_NONE )
            {
                int gap = zone_clearance;
                int thermalGap = GetThermalReliefGap( pad );
                gap = std::max( gap, thermalGap );
                item_boundingbox = pad->GetBoundingBox();
                item_boundingbox.Inflate( gap );

                if( item_boundingbox.Intersects( zone_boundingbox ) )
                {
                    pad->TransformShapeWithClearanceToPolygon( aFeatures,
                                                               gap,
                                                               segsPerCircle,
                                                               correctionFactor );
                }
            }
        }
    }

    /* Add holes (i.e. tracks and vias areas as polygons outlines)
     * in cornerBufferPolysToSubstract
     */
    for( TRACK* track = aPcb->m_Track;  track;  track = track->Next() )
    {
        if( !track->IsOnLayer( GetLayer() ) )
            continue;

        if( track->GetNetCode() == GetNetCode()  && (GetNetCode() != 0) )
            continue;

        item_clearance   = track->GetClearance() + outline_half_thickness;
        item_boundingbox = track->GetBoundingBox();

        if( item_boundingbox.Intersects( zone_boundingbox ) )
        {
            int clearance = std::max( zone_clearance, item_clearance );
            track->TransformShapeWithClearanceToPolygon( aFeatures,
                                                         clearance,
                                                         segsPerCircle,
                                                         correctionFactor );
        }
    }

    /* Add module edge items that are on copper layers
     * Pcbnew allows these items to be on copper layers in microwave applictions
     * This is a bad thing, but must be handled here, until a better way is found
     */
    for( MODULE* module = aPcb->m_Modules;  module;  module = module->Next() )
    {
        for( BOARD_ITEM* item = module->GraphicalItems();  item;  item = item->Next() )
        {
            if( !item->IsOnLayer( GetLayer() ) && !item->IsOnLayer( Edge_Cuts ) )
                continue;

            if( item->Type() != PCB_MODULE_EDGE_T )
                continue;

            item_boundingbox = item->GetBoundingBox();

            if( item_boundingbox.Intersects( zone_boundingbox ) )
            {
                ( (EDGE_MODULE*) item )->TransformShapeWithClearanceToPolygon(
                    aFeatures, zone_clearance,
                    segsPerCircle, correctionFactor );
            }
        }
    }

    // Add graphic items (copper texts) and board edges
    for( BOARD_ITEM* item = aPcb->m_Drawings; item; item = item->Next() )
    {
        if( item->GetLayer() != GetLayer() && item->GetLayer() != Edge_Cuts )
            continue;

        switch( item->Type() )
        {
        case PCB_LINE_T:
            ( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon(
                aFeatures,
                zone_clearance, segsPerCircle, correctionFactor );
            break;

        case PCB_TEXT_T:
            ( (TEXTE_PCB*) item )->TransformBoundingBoxWithClearanceToPolygon(
                aFeatures, zone_clearance );
            break;

        default:
            break;
        }
    }

    // Add zones outlines having an higher priority and keepout
    for( int ii = 0; ii < GetBoard()->GetAreaCount(); ii++ )
    {
        ZONE_CONTAINER* zone = GetBoard()->GetArea( ii );
        if( zone->GetLayer() != GetLayer() )
            continue;

        if( !zone->GetIsKeepout() && zone->GetPriority() <= GetPriority() )
            continue;

        if( zone->GetIsKeepout() && ! zone->GetDoNotAllowCopperPour() )
            continue;

        // A highter priority zone or keepout area is found: remove this area
        item_boundingbox = zone->GetBoundingBox();
        if( !item_boundingbox.Intersects( zone_boundingbox ) )
            continue;

        // Add the zone outline area.
        // However if the zone has the same net as the current zone,
        // do not add any clearance.
        // the zone will be connected to the current zone, but filled areas
        // will use different parameters (clearance, thermal shapes )
        bool same_net = GetNetCode() == zone->GetNetCode();
        bool use_net_clearance = true;
        int min_clearance = zone_clearance;

        // Do not forget to make room to draw the thick outlines
        // of the hole created by the area of the zone to remove
        int holeclearance = zone->GetClearance() + outline_half_thickness;

        // The final clearance is obviously the max value of each zone clearance
        min_clearance = std::max( min_clearance, holeclearance );

        if( zone->GetIsKeepout() || same_net )
        {
            // Just take in account the fact the outline has a thickness, so
            // the actual area to substract is inflated to take in account this fact
            min_clearance = outline_half_thickness;
            use_net_clearance = false;
        }

        zone->TransformOutlinesShapeWithClearanceToPolygon(
                    aFeatures,
                    min_clearance, use_net_clearance );
    }

   // Remove thermal symbols
    for( MODULE* module = aPcb->m_Modules;  module;  module = module->Next() )
    {
        for( D_PAD* pad = module->Pads(); pad != NULL; pad = pad->Next() )
        {
            // Rejects non-standard pads with tht-only thermal reliefs
            if( GetPadConnection( pad ) == PAD_ZONE_CONN_THT_THERMAL
             && pad->GetAttribute() != PAD_ATTRIB_STANDARD )
                continue;

            if( GetPadConnection( pad ) != PAD_ZONE_CONN_THERMAL
             && GetPadConnection( pad ) != PAD_ZONE_CONN_THT_THERMAL )
                continue;

            if( !pad->IsOnLayer( GetLayer() ) )
                continue;

            if( pad->GetNetCode() != GetNetCode() )
                continue;
            item_boundingbox = pad->GetBoundingBox();
            int thermalGap = GetThermalReliefGap( pad );
            item_boundingbox.Inflate( thermalGap, thermalGap );

            if( item_boundingbox.Intersects( zone_boundingbox ) )
            {
                CreateThermalReliefPadPolygon( aFeatures,
                                               *pad, thermalGap,
                                               GetThermalReliefCopperBridge( pad ),
                                               m_ZoneMinThickness,
                                               segsPerCircle,
                                               correctionFactor, s_thermalRot );
            }
        }
    }

}
void GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos )
{
    VECTOR2I origin;

    switch( aItem->Type() )
    {
        case PCB_MODULE_T:
        {
            MODULE* mod = static_cast<MODULE*>( aItem );
            addAnchor( mod->GetPosition(), ORIGIN | SNAPPABLE, mod );

            for( D_PAD* pad = mod->Pads(); pad; pad = pad->Next() )
                addAnchor( pad->GetPosition(), CORNER | SNAPPABLE, pad );

            break;
        }


        case PCB_PAD_T:
        {
            D_PAD* pad = static_cast<D_PAD*>( aItem );
            addAnchor( pad->GetPosition(), CORNER | SNAPPABLE, pad );

            break;
        }

        case PCB_MODULE_EDGE_T:
        case PCB_LINE_T:
        {
            DRAWSEGMENT* dseg = static_cast<DRAWSEGMENT*>( aItem );
            VECTOR2I start = dseg->GetStart();
            VECTOR2I end = dseg->GetEnd();
            //LAYER_ID layer = dseg->GetLayer();

            switch( dseg->GetShape() )
            {
                case S_CIRCLE:
                {
                    int r = ( start - end ).EuclideanNorm();

                    addAnchor( start, ORIGIN | SNAPPABLE, dseg );
                    addAnchor( start + VECTOR2I( -r, 0 ), OUTLINE | SNAPPABLE, dseg );
                    addAnchor( start + VECTOR2I( r, 0 ), OUTLINE | SNAPPABLE, dseg );
                    addAnchor( start + VECTOR2I( 0, -r ), OUTLINE | SNAPPABLE, dseg );
                    addAnchor( start + VECTOR2I( 0, r ), OUTLINE | SNAPPABLE, dseg );
                    break;
                }

                case S_ARC:
                {
                    origin = dseg->GetCenter();
                    addAnchor( dseg->GetArcStart(), CORNER | SNAPPABLE, dseg );
                    addAnchor( dseg->GetArcEnd(), CORNER | SNAPPABLE, dseg );
                    addAnchor( origin, ORIGIN | SNAPPABLE, dseg );
                    break;
                }

                case S_SEGMENT:
                {
                    origin.x = start.x + ( start.x - end.x ) / 2;
                    origin.y = start.y + ( start.y - end.y ) / 2;
                    addAnchor( start, CORNER | SNAPPABLE, dseg );
                    addAnchor( end, CORNER | SNAPPABLE, dseg );
                    addAnchor( origin, ORIGIN, dseg );
                    break;
                }

                default:
                {
                    origin = dseg->GetStart();
                    addAnchor( origin, ORIGIN | SNAPPABLE, dseg );
                    break;
                }
            }
            break;
        }

        case PCB_TRACE_T:
        {
            TRACK* track = static_cast<TRACK*>( aItem );
            VECTOR2I start = track->GetStart();
            VECTOR2I end = track->GetEnd();
            origin.x = start.x + ( start.x - end.x ) / 2;
            origin.y = start.y + ( start.y - end.y ) / 2;
            addAnchor( start, CORNER | SNAPPABLE, track );
            addAnchor( end, CORNER | SNAPPABLE, track );
            addAnchor( origin, ORIGIN, track);
            break;
        }

        case PCB_VIA_T:
            addAnchor( aItem->GetPosition(), CORNER | SNAPPABLE, aItem );
            break;

        case PCB_ZONE_AREA_T:
        {
            const CPolyLine* outline = static_cast<const ZONE_CONTAINER*>( aItem )->Outline();
            int cornersCount = outline->GetCornersCount();

            SHAPE_LINE_CHAIN lc;
            lc.SetClosed( true );

            for( int i = 0; i < cornersCount; ++i )
            {
                const VECTOR2I p ( outline->GetPos( i ) );
                addAnchor( p, CORNER, aItem );
                lc.Append( p );
            }

            addAnchor( lc.NearestPoint( aRefPos ), OUTLINE, aItem );

            break;
        }

        case PCB_MODULE_TEXT_T:
        case PCB_TEXT_T:
            addAnchor( aItem->GetPosition(), ORIGIN, aItem );
        default:

        break;
   }
}