void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer )
{
    PAD_SHAPE_T shape;
    double m, n;
    double orientation = aPad->GetOrientation();

    // Draw description layer
    if( IsNetnameLayer( aLayer ) )
    {
        VECTOR2D position( aPad->ShapePos() );

        // Is anything that we can display enabled?
        if( m_pcbSettings.m_netNamesOnPads || m_pcbSettings.m_padNumbers )
        {
            bool displayNetname = ( m_pcbSettings.m_netNamesOnPads && !aPad->GetNetname().empty() );
            VECTOR2D padsize = VECTOR2D( aPad->GetSize() );
            double maxSize = PCB_RENDER_SETTINGS::MAX_FONT_SIZE;
            double size = padsize.y;

            // Keep the size ratio for the font, but make it smaller
            if( padsize.x < padsize.y )
            {
                orientation += 900.0;
                size = padsize.x;
                std::swap( padsize.x, padsize.y );
            }
            else if( padsize.x == padsize.y )
            {
                // If the text is displayed on a symmetrical pad, do not rotate it
                orientation = 0.0;
            }

            // Font size limits
            if( size > maxSize )
                size = maxSize;

            m_gal->Save();
            m_gal->Translate( position );

            // do not display descriptions upside down
            NORMALIZE_ANGLE_90( orientation );
            m_gal->Rotate( DECIDEG2RAD( -orientation ) );

            // Default font settings
            m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
            m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
            m_gal->SetFontBold( false );
            m_gal->SetFontItalic( false );
            m_gal->SetTextMirrored( false );
            m_gal->SetStrokeColor( m_pcbSettings.GetColor( NULL, aLayer ) );
            m_gal->SetIsStroke( true );
            m_gal->SetIsFill( false );

            // Set the text position to the pad shape position (the pad position is not the best place)
            VECTOR2D textpos( 0.0, 0.0 );

            // Divide the space, to display both pad numbers and netnames
            // and set the Y text position to display 2 lines
            if( displayNetname && m_pcbSettings.m_padNumbers )
            {
                size = size / 2.0;
                textpos.y = size / 2.0;
            }

            if( displayNetname )
            {
                wxString netname = UnescapeString( aPad->GetShortNetname() );
                // calculate the size of net name text:
                double tsize = 1.5 * padsize.x / netname.Length();
                tsize = std::min( tsize, size );
                // Use a smaller text size to handle interline, pen size..
                tsize *= 0.7;
                VECTOR2D namesize( tsize, tsize );

                m_gal->SetGlyphSize( namesize );
                m_gal->SetLineWidth( namesize.x / 12.0 );
                m_gal->BitmapText( netname, textpos, 0.0 );
            }

            if( m_pcbSettings.m_padNumbers )
            {
                const wxString& padName = aPad->GetName();
                textpos.y = -textpos.y;
                double tsize = 1.5 * padsize.x / padName.Length();
                tsize = std::min( tsize, size );
                // Use a smaller text size to handle interline, pen size..
                tsize *= 0.7;
                tsize = std::min( tsize, size );
                VECTOR2D numsize( tsize, tsize );

                m_gal->SetGlyphSize( numsize );
                m_gal->SetLineWidth( numsize.x / 12.0 );
                m_gal->BitmapText( padName, textpos, 0.0 );
            }

            m_gal->Restore();
        }
        return;
    }

    // Pad drawing
    COLOR4D color;

    // Pad holes color is type specific
    if( aLayer == LAYER_PADS_PLATEDHOLES || aLayer == LAYER_NON_PLATEDHOLES )
    {
        // Hole color is the background color for plated holes, but a specific color
        // for not plated holes (LAYER_NON_PLATEDHOLES color layer )
        if( aPad->GetAttribute() == PAD_ATTRIB_HOLE_NOT_PLATED )
            color = m_pcbSettings.GetColor( nullptr, LAYER_NON_PLATEDHOLES );
        // Don't let pads that *should* be NPTH get lost
        else if( aPad->PadShouldBeNPTH() )
            color = m_pcbSettings.GetColor( aPad, aLayer );
        else
            color = m_pcbSettings.GetBackgroundColor();
    }
    else
    {
        color = m_pcbSettings.GetColor( aPad, aLayer );
    }

    VECTOR2D size;

    if( m_pcbSettings.m_sketchMode[LAYER_PADS_TH] )
    {
        // Outline mode
        m_gal->SetIsFill( false );
        m_gal->SetIsStroke( true );
        m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth );
        m_gal->SetStrokeColor( color );
    }
    else
    {
        // Filled mode
        m_gal->SetIsFill( true );
        m_gal->SetIsStroke( false );
        m_gal->SetFillColor( color );
    }

    m_gal->Save();
    m_gal->Translate( VECTOR2D( aPad->GetPosition() ) );
    m_gal->Rotate( -aPad->GetOrientationRadians() );

    int custom_margin = 0;     // a clearance/margin for custom shape, for solder paste/mask

    // Choose drawing settings depending on if we are drawing a pad itself or a hole
    if( aLayer == LAYER_PADS_PLATEDHOLES || aLayer == LAYER_NON_PLATEDHOLES )
    {
        // Drawing hole: has same shape as PAD_CIRCLE or PAD_OVAL
        size  = getDrillSize( aPad ) / 2.0;
        shape = getDrillShape( aPad ) == PAD_DRILL_SHAPE_OBLONG ? PAD_SHAPE_OVAL : PAD_SHAPE_CIRCLE;
    }
    else if( aLayer == F_Mask || aLayer == B_Mask )
    {
        // Drawing soldermask
        int soldermaskMargin = aPad->GetSolderMaskMargin();
        custom_margin = soldermaskMargin;

        m_gal->Translate( VECTOR2D( aPad->GetOffset() ) );
        size  = VECTOR2D( aPad->GetSize().x / 2.0 + soldermaskMargin,
                          aPad->GetSize().y / 2.0 + soldermaskMargin );
        shape = aPad->GetShape();
    }
    else if( aLayer == F_Paste || aLayer == B_Paste )
    {
        // Drawing solderpaste
        wxSize solderpasteMargin = aPad->GetSolderPasteMargin();
        // try to find a clearance which can be used for custom shapes
        custom_margin = solderpasteMargin.x;

        m_gal->Translate( VECTOR2D( aPad->GetOffset() ) );
        size  = VECTOR2D( aPad->GetSize().x / 2.0 + solderpasteMargin.x,
                          aPad->GetSize().y / 2.0 + solderpasteMargin.y );
        shape = aPad->GetShape();
    }
    else
    {
        // Drawing every kind of pad
        m_gal->Translate( VECTOR2D( aPad->GetOffset() ) );
        size  = VECTOR2D( aPad->GetSize() ) / 2.0;
        shape = aPad->GetShape();
    }

    switch( shape )
    {
    case PAD_SHAPE_OVAL:
        if( size.y >= size.x )
        {
            m = ( size.y - size.x );
            n = size.x;

            m_gal->DrawArc( VECTOR2D( 0, -m ), n, -M_PI, 0 );
            m_gal->DrawArc( VECTOR2D( 0, m ),  n, M_PI, 0 );

            if( m_pcbSettings.m_sketchMode[LAYER_PADS_TH] )
            {
                m_gal->DrawLine( VECTOR2D( -n, -m ), VECTOR2D( -n, m ) );
                m_gal->DrawLine( VECTOR2D( n, -m ),  VECTOR2D( n, m ) );
            }
            else
            {
                m_gal->DrawRectangle( VECTOR2D( -n, -m ), VECTOR2D( n, m ) );
            }
        }
        else
        {
            m = ( size.x - size.y );
            n = size.y;
            m_gal->DrawArc( VECTOR2D( -m, 0 ), n, M_PI / 2, 3 * M_PI / 2 );
            m_gal->DrawArc( VECTOR2D( m, 0 ),  n, M_PI / 2, -M_PI / 2 );

            if( m_pcbSettings.m_sketchMode[LAYER_PADS_TH] )
            {
                m_gal->DrawLine( VECTOR2D( -m, -n ), VECTOR2D( m, -n ) );
                m_gal->DrawLine( VECTOR2D( -m, n ),  VECTOR2D( m, n ) );
            }
            else
            {
                m_gal->DrawRectangle( VECTOR2D( -m, -n ), VECTOR2D( m, n ) );
            }
        }
        break;

    case PAD_SHAPE_RECT:
        m_gal->DrawRectangle( VECTOR2D( -size.x, -size.y ), VECTOR2D( size.x, size.y ) );
        break;

    case PAD_SHAPE_ROUNDRECT:
    case PAD_SHAPE_CHAMFERED_RECT:
    {
        SHAPE_POLY_SET polySet;
        wxSize prsize( size.x * 2, size.y * 2 );    // size is the half pad area size)
        const int corner_radius = aPad->GetRoundRectCornerRadius( prsize );
        bool doChamfer = shape == PAD_SHAPE_CHAMFERED_RECT;
        auto board = aPad->GetBoard();
        int maxError = ARC_HIGH_DEF;

        if( board )
            maxError = board->GetDesignSettings().m_MaxError;

        TransformRoundChamferedRectToPolygon( polySet, wxPoint( 0, 0 ), prsize,
                0.0, corner_radius, aPad->GetChamferRectRatio(),
                doChamfer ? aPad->GetChamferPositions() : 0, maxError );
        m_gal->DrawPolygon( polySet );
        break;
    }

    case PAD_SHAPE_CUSTOM:
    {   // Draw the complex custom shape

        // Use solder[Paste/Mask]size or pad size to build pad shape
        // however, solder[Paste/Mask] size has no actual meaning for a
        // custom shape, because it is a set of basic shapes
        // We use the custom_margin (good for solder mask, but approximative
        // for solder paste).
        if( custom_margin )
        {
            auto board = aPad->GetBoard();
            int maxError = ARC_HIGH_DEF;

            if( board )
                maxError = board->GetDesignSettings().m_MaxError;

            SHAPE_POLY_SET outline;
            outline.Append( aPad->GetCustomShapeAsPolygon() );
            // outline polygon can have holes linked to the main outline.
            // So use InflateWithLinkedHoles(), not Inflate() that can create
            // bad shapes if custom_margin is < 0
            int numSegs = std::max( GetArcToSegmentCount( custom_margin, maxError, 360.0 ), 6 );
            outline.InflateWithLinkedHoles( custom_margin, numSegs, SHAPE_POLY_SET::PM_FAST );
            m_gal->DrawPolygon( outline );
        }
        else
        {
            // Draw the polygon: only one polygon is expected
            // However we provide a multi polygon shape drawing
            // ( for the future or  to show even an incorrect shape
            m_gal->DrawPolygon( aPad->GetCustomShapeAsPolygon() );
        }
    }
        break;

    case PAD_SHAPE_TRAPEZOID:
    {
        std::deque<VECTOR2D> pointList;
        wxPoint corners[4];

        VECTOR2D padSize = VECTOR2D( aPad->GetSize().x, aPad->GetSize().y ) / 2;
        VECTOR2D deltaPadSize = size - padSize; // = solder[Paste/Mask]Margin or 0

        aPad->BuildPadPolygon( corners, wxSize( deltaPadSize.x, deltaPadSize.y ), 0.0 );
        SHAPE_POLY_SET polySet;
        polySet.NewOutline();
        polySet.Append( VECTOR2I( corners[0] ) );
        polySet.Append( VECTOR2I( corners[1] ) );
        polySet.Append( VECTOR2I( corners[2] ) );
        polySet.Append( VECTOR2I( corners[3] ) );

        m_gal->DrawPolygon( polySet );
    }
    break;

    case PAD_SHAPE_CIRCLE:
        m_gal->DrawCircle( VECTOR2D( 0.0, 0.0 ), size.x );
        break;
    }

    m_gal->Restore();

    // Clearance lines
    // It has to be called after GAL::Restore() as TransformShapeWithClearanceToPolygon()
    // returns already transformed coordinates
    constexpr int clearanceFlags = /*PCB_RENDER_SETTINGS::CL_EXISTING |*/ PCB_RENDER_SETTINGS::CL_PADS;

    if( ( m_pcbSettings.m_clearance & clearanceFlags ) == clearanceFlags
            && ( aLayer == LAYER_PAD_FR
                || aLayer == LAYER_PAD_BK
                || aLayer == LAYER_PADS_TH ) )
    {
        SHAPE_POLY_SET polySet;
        aPad->TransformShapeWithClearanceToPolygon( polySet, aPad->GetClearance() );
        m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth );
        m_gal->SetIsStroke( true );
        m_gal->SetIsFill( false );
        m_gal->SetStrokeColor( color );
        m_gal->DrawPolygon( polySet );
    }
}