← Back to team overview

kicad-developers team mailing list archive

[PATCH] V3 Rectangular pads with rounded corners

 

Hi everybody,

below is the third version of a patch to add support for rectangular
pads with rounded corners to KiCad. The patch was generated against
revision 5444.

What is new:

- plotting to HPGL works

- plotting to DXF works. Actually that worked from the beginning because
DXF is plotted differently than the other formats. Imagine my surprise
when discovering that...

- I looked at the footprint report. But because I couldn't figure out
who actually defined the format (is it KiCad specific, can I simply add
a pad shape?) and because there seems to be something fishy with the
existing code (see below) I left it alone

- IPC D-356 doesn't seem to need any change because it doesn't seem to
have pad shape info in it

- GenCAD handles PAD_ROUNDRECT like PAD_TRAPEZOID (i.e chickens out ;-),
I have no idea how I could check GenCAD files anyway

- VRML for now errors out when encountering PAD_ROUNDRECT, that code
frightened me ;-)

- IDFv3, nothing changed as it seems there is no pad shape info in it

What I think is fishy about the code generating the footprint report: in
PCB_EDIT_FRAME::DoGenFootprintsReport, assumptions are made about
PAD_SHAPE_T which IMHO do not hold. The code seems to assume PAD_SHAPE_T
has 6 distinct enumeration constants when in fact PAD_CIRCLE and
PAD_ROUND both have the value 0. Also seems to assume value 0 doesn't
occur. Because I don't know the history behind that I left it as is.


Enjoy,

MGri


=== modified file 'common/common_plotDXF_functions.cpp'
--- common/common_plotDXF_functions.cpp	2015-02-18 19:27:00 +0000
+++ common/common_plotDXF_functions.cpp	2015-02-22 16:52:36 +0000
@@ -601,6 +601,12 @@
     FinishTo( wxPoint( ox, oy ) );
 }
 
+void DXF_PLOTTER::FlashPadRoundRect( const wxPoint& pos, const wxPoint corners[12],
+                                     int cornerRadius, double orient,
+                                     EDA_DRAW_MODE_T trace_mode )
+{
+    // Not actually needed, because for DXF copper is plotted entirely as polygons
+}
 
 /**
  * DXF trapezoidal pad: only sketch mode is supported

=== modified file 'common/common_plotGERBER_functions.cpp'
--- common/common_plotGERBER_functions.cpp	2015-02-18 19:27:00 +0000
+++ common/common_plotGERBER_functions.cpp	2015-02-22 16:52:36 +0000
@@ -559,6 +559,120 @@
 }
 
 
+void GERBER_PLOTTER::FlashPadRoundRect( const wxPoint& pos, const wxPoint corners[12],
+                                        int cornerRadius, double orient,
+                                        EDA_DRAW_MODE_T trace_mode )
+
+{
+    wxASSERT( outputFile );
+
+    // XXX to do: use an aperture macro to declare the pad if possible
+
+    if( ( orient == 0 || orient == 900 || orient == 1800 || orient == 2700 )
+        && trace_mode == FILLED )
+    {
+        wxSize size;
+        DPOINT pos_dev;
+
+        // flash the large rectangle of the center polygon
+        pos_dev = userToDeviceCoordinates( pos );
+        if( orient == 0 || orient == 1800 )
+        {
+            size = wxSize( corners[4].x - corners[11].x,
+                           corners[4].y - corners[5].y );
+        }
+        else 
+        {
+            size = wxSize( corners[1].y - corners[8].y,
+                           corners[3].x - corners[0].x );
+        }
+        selectAperture( size, APERTURE::Rect );
+        emitDcode( pos_dev, 3 );
+        // flash the top small rectangle of the center polygon
+        if( orient == 0 || orient == 1800 )
+        {	
+            pos_dev = userToDeviceCoordinates( pos + wxPoint( 0, corners[0].y + cornerRadius / 2 ));
+            size = wxSize( corners[3].x - corners[0].x,
+                           corners[1].y - corners[0].y );
+        }
+        else
+        {
+            pos_dev = userToDeviceCoordinates( pos + wxPoint( 0, corners[3].x + cornerRadius / 2 ));
+            size = wxSize( corners[3].y - corners[6].y,
+                           corners[4].x - corners[3].x );
+        }
+        selectAperture( size, APERTURE::Rect );
+        emitDcode( pos_dev, 3 );
+        // flash the bottom small rectangle of the center polygon
+        if( orient == 0 || orient == 1800 )
+        {	
+            pos_dev = userToDeviceCoordinates( pos - wxPoint( 0, corners[0].y + cornerRadius / 2 ));
+        }
+        else
+        {
+            pos_dev = userToDeviceCoordinates( pos - wxPoint( 0, corners[3].x + cornerRadius / 2 ));
+        }
+        selectAperture( size, APERTURE::Rect );
+        emitDcode( pos_dev, 3 );
+        // Flash the 4 corner circles
+        size = wxSize( cornerRadius << 1, cornerRadius << 1 );
+        selectAperture( size, APERTURE::Circle );
+        if( orient == 0 || orient == 1800 )
+        {
+            pos_dev = userToDeviceCoordinates( corners[0] + pos );
+            emitDcode( pos_dev, 3 );
+            pos_dev = userToDeviceCoordinates( corners[3] + pos );
+            emitDcode( pos_dev, 3 );
+            pos_dev = userToDeviceCoordinates( corners[6] + pos );
+            emitDcode( pos_dev, 3 );
+            pos_dev = userToDeviceCoordinates( corners[9] + pos );
+            emitDcode( pos_dev, 3 );
+        }
+        else
+        {
+            pos_dev = userToDeviceCoordinates(
+                wxPoint( corners[0].y, -corners[0].x ) + pos );
+            emitDcode( pos_dev, 3 );
+            pos_dev = userToDeviceCoordinates(
+                wxPoint( corners[3].y, -corners[3].x ) + pos );
+            emitDcode( pos_dev, 3 );
+            pos_dev = userToDeviceCoordinates(
+                wxPoint( corners[6].y, -corners[6].x ) + pos );
+            emitDcode( pos_dev, 3 );
+            pos_dev = userToDeviceCoordinates(
+                wxPoint( corners[9].y, -corners[9].x ) + pos );
+            emitDcode( pos_dev, 3 );
+        }
+    }
+    else
+    {
+        std::vector< wxPoint > cornerList;
+
+        // construct the rotated polygons corner list
+        for( int i = 2; i < 12; i += 3 )
+        {
+            wxPoint p( corners[i] );
+            RotatePoint( &p, orient );
+            p += pos;
+            cornerList.push_back( p );
+            wxPoint center( corners[(i + 1) % 12] );
+            RotatePoint( &center, orient );
+            for( int rot = 100; rot < 900; rot += 100 )
+            {
+                wxPoint pr( corners[i] );
+                RotatePoint( &pr, orient );
+                RotatePoint( &pr, center, rot );
+                pr += pos;
+                cornerList.push_back( pr );
+            }
+        }
+        // plot it
+        SetCurrentLineWidth( -1 );
+        PlotPoly( cornerList, trace_mode == SKETCH ? NO_FILL : FILLED_SHAPE );
+    }
+}
+
+
 void GERBER_PLOTTER::FlashPadTrapez( const wxPoint& aPadPos,  const wxPoint* aCorners,
                                      double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode )
 

=== modified file 'common/common_plotHPGL_functions.cpp'
--- common/common_plotHPGL_functions.cpp	2015-02-18 19:27:00 +0000
+++ common/common_plotHPGL_functions.cpp	2015-02-22 16:52:36 +0000
@@ -249,14 +249,21 @@
 
 
 /**
- * HPGL rectangle: fill not supported
+ * HPGL rectangle
  */
 void HPGL_PLOTTER::Rect( const wxPoint& p1, const wxPoint& p2, FILL_T fill, int width )
 {
     wxASSERT( outputFile );
     DPOINT p2dev = userToDeviceCoordinates( p2 );
     MoveTo( p1 );
-    fprintf( outputFile, "EA %.0f,%.0f;\n", p2dev.x, p2dev.y );
+    if( fill == NO_FILL ) 
+    {
+	fprintf( outputFile, "EA %.0f,%.0f;\n", p2dev.x, p2dev.y );
+    }
+    else
+    {
+	fprintf( outputFile, "RA %.0f,%.0f;\n", p2dev.x, p2dev.y );
+    }
     PenFinish();
 }
 
@@ -629,6 +636,115 @@
     }
 }
 
+void HPGL_PLOTTER::FlashPadRoundRect( const wxPoint& pos, const wxPoint corners[12],
+                                      int cornerRadius, double orient,
+                                      EDA_DRAW_MODE_T trace_mode )
+{
+    std::vector< wxPoint > cornerList;
+
+    wxASSERT( outputFile );
+
+    for( int ii = 0; ii < 12; ii++ )
+        cornerList.push_back( corners[ii] );
+
+    int w = KiROUND( penDiameter );
+    int hw = w / 2;
+
+    if( trace_mode != FILLED ) 
+    {
+        cornerList[0].x += hw;
+        cornerList[0].y -= hw;
+        cornerList[1].x += hw;
+        cornerList[1].y -= hw;
+        cornerList[2].x -= hw;
+        cornerList[2].y -= hw;
+        cornerList[3].x -= hw;
+        cornerList[3].y -= hw;
+        cornerList[4].x -= hw;
+        cornerList[4].y -= hw;
+        cornerList[5].x -= hw;
+        cornerList[5].y += hw;
+        cornerList[6].x -= hw;
+        cornerList[6].y += hw;
+        cornerList[7].x -= hw;
+        cornerList[7].y += hw;
+        cornerList[8].x += hw;
+        cornerList[8].y += hw;
+        cornerList[9].x += hw;
+        cornerList[9].y += hw;
+        cornerList[10].x += hw;
+        cornerList[10].y += hw;
+        cornerList[11].x += hw;
+        cornerList[11].y -= hw;
+    }
+
+    for( unsigned ii = 0; ii < cornerList.size(); ii++ )
+    {
+        RotatePoint( &cornerList[ii], orient );
+        cornerList[ii] += pos;
+    }
+
+    if( trace_mode == FILLED )
+    {
+        wxPoint cpos;
+        
+        if( orient == 0 || orient == 900 || orient == 1800 || orient == 2700 )
+        {            
+            Rect( cornerList[10], cornerList[4], FILLED_SHAPE, w );
+            Rect( cornerList[0], cornerList[2], FILLED_SHAPE, w );
+            Rect( cornerList[8], cornerList[6], FILLED_SHAPE, w );
+        }
+        else
+        {
+            // (ab)use FlashPadRect() as a generalized Rect()
+            wxPoint s( corners[4] - corners[10] );
+            FlashPadRect( pos, wxSize( s.x, s.y ), orient, FILLED );
+            // small top reactangle
+            cpos = wxPoint( 0, corners[1].y - cornerRadius / 2 );
+            RotatePoint( &cpos, orient );
+            s = corners[2] - corners[0];
+            FlashPadRect( pos + cpos, wxSize( s.x, s.y ), orient, FILLED );
+            // small bottom rectangle
+            cpos = wxPoint( 0, corners[8].y + cornerRadius / 2 );
+            RotatePoint( &cpos, orient );            
+            s = corners[6] - corners[8];
+            FlashPadRect( pos + cpos, wxSize( s.x, s.y ), orient, FILLED );
+        }        
+        // (ab)use FlashPadCircle for filled circle
+        cpos = corners[0];
+        RotatePoint( &cpos, orient );
+        FlashPadCircle( pos + cpos, cornerRadius * 2, FILLED );
+        cpos = corners[3];
+        RotatePoint( &cpos, orient );
+        FlashPadCircle( pos + cpos, cornerRadius * 2, FILLED );
+        cpos = corners[6];
+        RotatePoint( &cpos, orient );
+        FlashPadCircle( pos + cpos, cornerRadius * 2, FILLED );
+        cpos = corners[9];
+        RotatePoint( &cpos, orient );
+        FlashPadCircle( pos + cpos, cornerRadius * 2, FILLED );
+    }
+    else
+    {
+        MoveTo( cornerList[1] );
+        LineTo( cornerList[2] );
+        MoveTo( cornerList[4] );
+        LineTo( cornerList[5] );
+        MoveTo( cornerList[7] );
+        LineTo( cornerList[8] );
+        MoveTo( cornerList[10] );
+        FinishTo( cornerList[11] );
+
+        Arc(cornerList[0], orient + 1800, orient + 2700, cornerRadius,
+            NO_FILL, w );
+        Arc(cornerList[3], orient + 2700, orient + 3600, cornerRadius,
+            NO_FILL, w );
+        Arc(cornerList[6], orient, orient + 900, cornerRadius,
+            NO_FILL, w );
+        Arc(cornerList[9], orient + 900, orient + 1800, cornerRadius,
+            NO_FILL, w );
+    }    
+}
 
 void HPGL_PLOTTER::FlashPadTrapez( const wxPoint& aPadPos, const wxPoint* aCorners,
                                    double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode )

=== modified file 'common/common_plotPS_functions.cpp'
--- common/common_plotPS_functions.cpp	2014-10-19 20:20:16 +0000
+++ common/common_plotPS_functions.cpp	2015-02-22 16:52:36 +0000
@@ -181,6 +181,82 @@
     PlotPoly( cornerList, ( trace_mode == FILLED ) ? FILLED_SHAPE : NO_FILL );
 }
 
+void PSLIKE_PLOTTER::FlashPadRoundRect( const wxPoint& pos, const wxPoint corners[12],
+                                        int cornerRadius, double orient,
+                                        EDA_DRAW_MODE_T trace_mode )
+{
+    static std::vector< wxPoint > cornerList;
+    cornerList.clear();
+
+    for( int ii = 0; ii < 12; ii++ )
+        cornerList.push_back( corners[ii] );
+
+    // As far as I understand it line and pen width are the same thing???
+    
+    SetCurrentLineWidth( -1 );
+    int w = GetCurrentLineWidth();
+    int hw = w / 2;
+
+    cornerList[0].x += hw;
+    cornerList[0].y -= hw;
+    cornerList[1].x += hw;
+    cornerList[1].y -= hw;
+    cornerList[2].x -= hw;
+    cornerList[2].y -= hw;
+    cornerList[3].x -= hw;
+    cornerList[3].y -= hw;
+    cornerList[4].x -= hw;
+    cornerList[4].y -= hw;
+    cornerList[5].x -= hw;
+    cornerList[5].y += hw;
+    cornerList[6].x -= hw;
+    cornerList[6].y += hw;
+    cornerList[7].x -= hw;
+    cornerList[7].y += hw;
+    cornerList[8].x += hw;
+    cornerList[8].y += hw;
+    cornerList[9].x += hw;
+    cornerList[9].y += hw;
+    cornerList[10].x += hw;
+    cornerList[10].y += hw;
+    cornerList[11].x += hw;
+    cornerList[11].y -= hw;
+
+    for( unsigned ii = 0; ii < cornerList.size(); ii++ )
+    {
+        RotatePoint( &cornerList[ii], orient );
+        cornerList[ii] += pos;
+    }
+
+    cornerList.push_back( cornerList[0] );
+
+    if( trace_mode == FILLED ) 
+    {
+        PlotPoly( cornerList, FILLED_SHAPE );
+    }
+    else 
+    {
+        for( unsigned ii = 1; ii < 12; ii += 3 )
+        {
+            MoveTo( cornerList[ii] );
+            FinishTo( cornerList[ii + 1] );
+        }
+    }
+
+    if ( w > 2 * cornerRadius )
+        w = 2 * cornerRadius;
+
+    Arc(cornerList[0], orient + 1800, orient + 2700, cornerRadius,
+        ( trace_mode == FILLED ) ? FILLED_SHAPE : NO_FILL, w );
+    Arc(cornerList[3], orient + 2700, orient + 3600, cornerRadius,
+        ( trace_mode == FILLED ) ? FILLED_SHAPE : NO_FILL, w );
+    Arc(cornerList[6], orient, orient + 900, cornerRadius,
+        ( trace_mode == FILLED ) ? FILLED_SHAPE : NO_FILL, w );
+    Arc(cornerList[9], orient + 900, orient + 1800, cornerRadius,
+        ( trace_mode == FILLED ) ? FILLED_SHAPE : NO_FILL, w );
+    
+    SetCurrentLineWidth( -1 );
+}
 
 void PSLIKE_PLOTTER::FlashPadTrapez( const wxPoint& aPadPos, const wxPoint *aCorners,
                                      double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode )

=== modified file 'common/pcb.keywords'
--- common/pcb.keywords	2013-09-17 00:52:08 +0000
+++ common/pcb.keywords	2015-02-22 16:52:36 +0000
@@ -142,6 +142,7 @@
 reference
 right
 rotate
+roundrect
 scale
 segment
 segment_width

=== modified file 'include/pad_shapes.h'
--- include/pad_shapes.h	2014-01-28 09:43:55 +0000
+++ include/pad_shapes.h	2015-02-22 16:52:36 +0000
@@ -15,7 +15,8 @@
     PAD_ROUND = PAD_CIRCLE,
     PAD_RECT,
     PAD_OVAL,
-    PAD_TRAPEZOID
+    PAD_TRAPEZOID,
+    PAD_ROUNDRECT
 };
 
 /**

=== modified file 'include/plot_common.h'
--- include/plot_common.h	2015-02-18 19:27:00 +0000
+++ include/plot_common.h	2015-02-22 16:52:36 +0000
@@ -257,6 +257,18 @@
     virtual void FlashPadRect( const wxPoint& pos, const wxSize& size,
                                double orient, EDA_DRAW_MODE_T trace_mode ) = 0;
 
+    /**
+     * @param pos Position of the shape
+     * @param corners List of the 12 corners of the inner polygon, the arcs
+     *          for the corners are centered on corner 0, 3, 6 and 9
+     * @param cornerRadius Radius of the rounded corners
+     * @param orient The rotattion of the shape
+     * @param trace_mode FILLED or SKETCH
+     */
+    virtual void FlashPadRoundRect( const wxPoint& pos, const wxPoint corners[12],
+                                    int cornerRadius, double orient,
+                                    EDA_DRAW_MODE_T trace_mode ) = 0;
+
     /** virtual function FlashPadTrapez
      * flash a trapezoidal pad
      * @param aPadPos = the position of the shape
@@ -509,6 +521,9 @@
                                EDA_DRAW_MODE_T trace_mode );
     virtual void FlashPadRect( const wxPoint& pos, const wxSize& size,
                                double orient, EDA_DRAW_MODE_T trace_mode );
+    virtual void FlashPadRoundRect( const wxPoint& pos, const wxPoint corners[12],
+                                    int cornerRadius, double orient,
+                                    EDA_DRAW_MODE_T trace_mode );
     virtual void FlashPadTrapez( const wxPoint& aPadPos, const wxPoint *aCorners,
                                  double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode );
 
@@ -561,6 +576,9 @@
                                EDA_DRAW_MODE_T trace_mode );
     virtual void FlashPadRect( const wxPoint& pos, const wxSize& size,
                                double orient, EDA_DRAW_MODE_T trace_mode );
+    virtual void FlashPadRoundRect( const wxPoint& pos, const wxPoint corners[12],
+                                    int cornerRadius, double orient,
+                                    EDA_DRAW_MODE_T trace_mode );
     virtual void FlashPadTrapez( const wxPoint& aPadPos, const wxPoint *aCorners,
                                  double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode );
 
@@ -919,6 +937,13 @@
                                double orient, EDA_DRAW_MODE_T trace_mode );
 
     /**
+     * Roundrect pad at the moment are *never* handled as aperture, since
+     * they require aperture macros
+     */
+    virtual void FlashPadRoundRect( const wxPoint& pos, const wxPoint corners[12],
+                                    int cornerRadius, double orient,
+                                    EDA_DRAW_MODE_T trace_mode );
+    /**
      * Trapezoidal pad at the moment are *never* handled as aperture, since
      * they require aperture macros
      */
@@ -1045,6 +1070,9 @@
                                EDA_DRAW_MODE_T trace_mode );
     virtual void FlashPadRect( const wxPoint& pos, const wxSize& size,
                                double orient, EDA_DRAW_MODE_T trace_mode );
+    virtual void FlashPadRoundRect( const wxPoint& pos, const wxPoint corners[12],
+                                    int cornerRadius, double orient,
+                                    EDA_DRAW_MODE_T trace_mode );
     virtual void FlashPadTrapez( const wxPoint& aPadPos, const wxPoint *aCorners,
                                  double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode );
 

=== modified file 'pcbnew/board_items_to_polygon_shape_transform.cpp'
--- pcbnew/board_items_to_polygon_shape_transform.cpp	2015-02-18 19:27:00 +0000
+++ pcbnew/board_items_to_polygon_shape_transform.cpp	2015-02-22 16:52:36 +0000
@@ -605,6 +605,44 @@
         aCornerBuffer.ImportFrom( shapeWithClearance );
     }
         break;
+
+    case PAD_ROUNDRECT:
+    {
+        wxPoint corners[12];
+        int r = BuildPadPolygonRoundRect( corners, wxSize( 0, 0 ), angle );
+
+        // We are using ClipperLib to inflate the polygon shape, using
+        // arcs to connect moved segments.
+        ClipperLib::Path outline;
+        ClipperLib::Paths shapeWithClearance;
+
+        for( int ii = 0; ii < 12; ii += 3 )
+        {
+            corners[ii] += PadShapePos;
+            outline << ClipperLib::IntPoint( corners[ii].x, corners[ii].y );
+        }
+
+        ClipperLib::ClipperOffset offset_engine;
+        // Prepare an offset (inflate) transform, with edges connected by arcs
+        offset_engine.AddPath( outline, ClipperLib::jtRound, ClipperLib::etClosedPolygon );
+
+        // Clipper approximates arcs by segments
+        // It uses a value called ArcTolerance which is the max error between the arc
+        // and segments created to approximate this arc
+        // the number of segm per circle is:
+        // n = PI / acos(1 - arc_tolerance / (arc radius))
+        // the arc radius is aClearanceValue
+        // because arc_tolerance is << aClearanceValue and aClearanceValue >= 0
+        // n = PI / (arc_tolerance / aClearanceValue )
+        offset_engine.ArcTolerance = ((double)aClearanceValue + r) / 3.14 / aCircleToSegmentsCount;
+
+        double rounding_radius = (aClearanceValue + r) * aCorrectionFactor;
+        offset_engine.Execute( shapeWithClearance, rounding_radius );
+
+        // get new outline (only one polygon is expected)
+        aCornerBuffer.ImportFrom( shapeWithClearance );
+    }
+        break;
     }
 }
 
@@ -626,6 +664,7 @@
     {
     case PAD_CIRCLE:
     case PAD_OVAL:
+    case PAD_ROUNDRECT:
         TransformShapeWithClearanceToPolygon( aCornerBuffer, aInflateValue.x,
                                               aSegmentsPerCircle, aCorrectionFactor );
         break;
@@ -1052,6 +1091,79 @@
         }
         break;
 
+    case PAD_ROUNDRECT:
+        {
+            std::vector <wxPoint> corners_buffer;          // Polygon buffer as vector
+
+            int dx = (aPad.GetSize().x / 2) + aThermalGap;
+            int dy = (aPad.GetSize().y / 2) + aThermalGap;
+
+            // The first point of polygon buffer is left lower corner, second the crosspoint of
+            // thermal spoke sides, the third is upper right corner and the rest are rounding
+            // vertices going anticlockwise. Note the inveted Y-axis in CG.
+            corners_buffer.push_back( wxPoint( -dx, -(aThermalGap / 4 + copper_thickness.y / 2) ) );    // Adds small miters to zone
+            corners_buffer.push_back( wxPoint( -(dx - aThermalGap / 4), -copper_thickness.y / 2 ) );    // fill and spoke corner
+            corners_buffer.push_back( wxPoint( -copper_thickness.x / 2, -copper_thickness.y / 2 ) );
+            corners_buffer.push_back( wxPoint( -copper_thickness.x / 2, -(dy - aThermalGap / 4) ) );
+            corners_buffer.push_back( wxPoint( -(aThermalGap / 4 + copper_thickness.x / 2), -dy ) );
+
+            int r = aPad.GetRoundRectCornerRadius();
+            // the center around which the round part of the thermal gap is drawn
+            wxPoint center = wxPoint( -(aPad.GetSize().x / 2 - r), -(aPad.GetSize().y / 2 - r) );
+
+            corners_buffer.push_back( wxPoint( center.x, -dy ));
+            
+            for( int i = 1; i < aCircleToSegmentsCount / 4 + 1; i++ )
+            {
+                wxPoint corner_position = wxPoint( center.x, -dy );
+
+                double angle_pg = i * delta;
+                RotatePoint( &corner_position, center, angle_pg );
+
+                corners_buffer.push_back( wxPoint( corner_position.x, corner_position.y ) );
+            }
+
+            double angle = aPad.GetOrientation();
+            
+            for( int irect = 0; irect < 2; irect++ )
+            {
+                for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
+                {
+                    wxPoint cpos = corners_buffer[ic];
+                    RotatePoint( &cpos, angle );            // Rotate according to module orientation
+                    cpos += PadShapePos;                    // Shift origin to position
+                    aCornerBuffer.Append( CPolyPt( cpos.x, cpos.y ) );
+                }
+
+                aCornerBuffer.CloseLastContour();
+                angle = AddAngles( angle, 1800 );       // this is calculate hole 3
+            }
+
+            // Create holes, that are the mirrored from the previous holes
+            for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
+            {
+                wxPoint swap = corners_buffer[ic];
+                swap.x = -swap.x;
+                corners_buffer[ic] = swap;
+            }
+
+            // Now add corner 4 and 2 (2 is the corner 4 rotated by 180 deg
+            for( int irect = 0; irect < 2; irect++ )
+            {
+                for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
+                {
+                    wxPoint cpos = corners_buffer[ic];
+                    RotatePoint( &cpos, angle );
+                    cpos += PadShapePos;
+                    aCornerBuffer.Append( CPolyPt( cpos.x, cpos.y ) );
+                }
+
+                aCornerBuffer.CloseLastContour();
+                angle = AddAngles( angle, 1800 );
+            }
+        }
+        break;
+        
     case PAD_TRAPEZOID:
         {
         CPOLYGONS_LIST cbuffer;

=== modified file 'pcbnew/class_pad.cpp'
--- pcbnew/class_pad.cpp	2015-02-18 19:27:00 +0000
+++ pcbnew/class_pad.cpp	2015-02-22 16:52:36 +0000
@@ -141,6 +141,14 @@
         radius = 1 + KiROUND( hypot( x, y ) / 2 );
         break;
 
+    case PAD_ROUNDRECT:
+	radius = GetRoundRectCornerRadius( m_Size );
+	x = m_Size.x >> 1;
+	y = m_Size.y >> 1;
+	radius = 1 + KiROUND( EuclideanNorm( wxSize( x - radius, y - radius )))
+	    + radius;
+        break;
+
     default:
         radius = 0;
     }
@@ -180,6 +188,7 @@
         break;
 
     case PAD_RECT:
+    case PAD_ROUNDRECT:
         //Use two corners and track their rotation
         // (utilise symmetry to avoid four points)
         quadrant1.x =  m_Size.x/2;
@@ -774,6 +783,30 @@
             return true;
 
         break;
+
+    case PAD_ROUNDRECT:
+    {
+        // First check for hit in polygon
+        wxPoint poly[12];
+        int r = BuildPadPolygonRoundRect( poly, wxSize(0,0), 0 );
+        RotatePoint( &delta, -m_Orient );
+        if( TestPointInsidePolygon( poly, 12, delta ))
+            return true;
+        // Then check the rounded corners
+        delta = aPosition - shape_pos - poly[0];
+        if( KiROUND( EuclideanNorm( delta ) ) <= r )
+            return true;
+        delta = aPosition - shape_pos - poly[3];
+        if( KiROUND( EuclideanNorm( delta ) ) <= r )
+            return true;
+        delta = aPosition - shape_pos - poly[6];
+        if( KiROUND( EuclideanNorm( delta ) ) <= r )
+            return true;
+        delta = aPosition - shape_pos - poly[9];
+        if( KiROUND( EuclideanNorm( delta ) ) <= r )
+            return true;
+    }
+        break;
     }
 
     return false;
@@ -857,6 +890,9 @@
     case PAD_TRAPEZOID:
         return _( "Trap" );
 
+    case PAD_ROUNDRECT:
+        return _( "Roundrect" );
+
     default:
         return wxT( "???" );
     }

=== modified file 'pcbnew/class_pad.h'
--- pcbnew/class_pad.h	2015-02-18 19:27:00 +0000
+++ pcbnew/class_pad.h	2015-02-22 16:52:36 +0000
@@ -292,6 +292,27 @@
     void BuildPadPolygon( wxPoint aCoord[4], wxSize aInflateValue, double aRotation ) const;
 
     /**
+     * Function BuildPadPolygonRoundRect
+     * Has meaning only for rounded rect pads
+     * Build the Corner list of the polygonal center shape,
+     * depending on shape, extra size (clearance ...) and orientation
+     * @param aCoord = a buffer to fill (12 corners).
+     * @param aInflateValue = wxSize: the clearance or margin value. value > 0:
+     *                        inflate, < 0 deflate
+     * @param aRotation = full rotation of the polygon
+     * @return Radius of the rounded corner arcs
+     */
+    int BuildPadPolygonRoundRect( wxPoint aCoord[12], wxSize aInflateValue, double aRotation ) const;
+
+    /**
+     * Function GetRoundRectCornerRadius
+     * Has meaning only for rounded rect pads
+     * Returns the radius of the rounded corners for this pad.
+     * @return The radius of the rounded corners for this pad.
+     */
+    int GetRoundRectCornerRadius() const;
+
+    /**
      * Function BuildPadShapePolygon
      * Build the Corner list of the polygonal shape,
      * depending on shape, extra size (clearance ...) pad and orientation
@@ -475,6 +496,18 @@
 
 private:
     /**
+     * Private helper function BuildPadPolygonRoundRect
+     * Has meaning only for rounded rect pads
+     * Build the Corner list of the non-rotated polygonal center shape
+     * @param aCoord = a buffer to fill (12 corners).
+     * @param size Size of shape to build
+     * @return Radius of the rounded corner arcs
+     */
+    int BuildPadPolygonRoundRect( wxPoint aCoord[12], wxSize size ) const;
+
+    int GetRoundRectCornerRadius( wxSize size ) const;
+    
+    /**
      * Function boundingRadius
      * returns a calculated radius of a bounding circle for this pad.
      */
@@ -494,7 +527,7 @@
 
     wxPoint     m_Pos;              ///< pad Position on board
 
-    PAD_SHAPE_T m_padShape;         ///< Shape: PAD_CIRCLE, PAD_RECT, PAD_OVAL, PAD_TRAPEZOID
+    PAD_SHAPE_T m_padShape;         ///< Shape: PAD_CIRCLE, PAD_RECT, PAD_OVAL, PAD_TRAPEZOID, PAD_ROUNDRECT
 
 
     int         m_SubRatsnest;      ///< variable used in rats nest computations

=== modified file 'pcbnew/class_pad_draw_functions.cpp'
--- pcbnew/class_pad_draw_functions.cpp	2015-02-22 09:39:58 +0000
+++ pcbnew/class_pad_draw_functions.cpp	2015-02-22 16:52:36 +0000
@@ -311,9 +311,10 @@
 
 void D_PAD::DrawShape( EDA_RECT* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
 {
-    wxPoint coord[4];
+    wxPoint coord[12];
     double  angle = m_Orient;
     int     seg_width;
+    int     r;
 
     GRSetDrawMode( aDC, aDrawInfo.m_DrawMode );
 
@@ -397,6 +398,86 @@
         }
         break;
 
+    case PAD_ROUNDRECT:
+        r = BuildPadPolygonRoundRect( coord, aDrawInfo.m_Mask_margin, angle );
+
+        for( int ii = 0; ii < 12; ii++ )
+            coord[ii] += shape_pos;
+
+        if( aDrawInfo.m_ShowPadFilled ) 
+        {
+            GRClosedPoly( aClipBox, aDC, 12, coord, true, 0,
+                          aDrawInfo.m_Color, aDrawInfo.m_Color );
+        }
+        else 
+        {
+            for( int ii = 1; ii < 12; ii += 3 )
+            {
+                GRLine( aClipBox, aDC, coord[ii].x, coord[ii].y,
+                        coord[ii + 1].x, coord[ii + 1].y, 0,
+                        aDrawInfo.m_Color );
+            }
+        }
+        if( aDrawInfo.m_ShowPadFilled ) 
+        {
+            GRFilledArc( aClipBox, aDC, coord[0].x, coord[0].y,
+                         900.0 - angle, 1800.0 - angle, r,
+                         aDrawInfo.m_Color, aDrawInfo.m_Color );
+            GRFilledArc( aClipBox, aDC, coord[3].x, coord[3].y,
+                         0.0 - angle, 900.0 - angle, r,
+                         aDrawInfo.m_Color, aDrawInfo.m_Color );
+            GRFilledArc( aClipBox, aDC, coord[6].x, coord[6].y,
+                         2700.0 - angle, 0.0 - angle, r,
+                         aDrawInfo.m_Color, aDrawInfo.m_Color );
+            GRFilledArc( aClipBox, aDC, coord[9].x, coord[9].y,
+                         1800.0 - angle, 2700.0 - angle, r,
+                         aDrawInfo.m_Color, aDrawInfo.m_Color );
+        }
+        else 
+        {
+            GRArc( aClipBox, aDC, coord[0].x, coord[0].y,
+                   900.0 - angle, 1800.0 - angle, r,
+                   m_PadSketchModePenSize, aDrawInfo.m_Color );
+            GRArc( aClipBox, aDC, coord[3].x, coord[3].y,
+                   0.0 - angle, 900.0 - angle, r,
+                   m_PadSketchModePenSize, aDrawInfo.m_Color );
+            GRArc( aClipBox, aDC, coord[6].x, coord[6].y,
+                   2700.0 - angle, 0.0 - angle, r,
+                   m_PadSketchModePenSize, aDrawInfo.m_Color );
+            GRArc( aClipBox, aDC, coord[9].x, coord[9].y,
+                   1800.0 - angle, 2700.0 - angle, r,
+                   m_PadSketchModePenSize, aDrawInfo.m_Color );
+        }
+
+        if( aDrawInfo.m_PadClearance )
+        {
+            r = BuildPadPolygonRoundRect( coord, wxSize( aDrawInfo.m_PadClearance,
+							 aDrawInfo.m_PadClearance ),
+                                   angle );
+            for( int ii = 0; ii < 12; ii++ )
+                coord[ii] += shape_pos;
+
+            for( int ii = 1; ii < 12; ii += 3 )
+            {
+                GRLine( aClipBox, aDC, coord[ii].x, coord[ii].y,
+                        coord[ii + 1].x, coord[ii + 1].y, 0,
+                        aDrawInfo.m_Color );
+            }
+            GRArc( aClipBox, aDC, coord[0].x, coord[0].y,
+                   900.0 - angle, 1800.0 - angle, r,
+                   0, aDrawInfo.m_Color );
+            GRArc( aClipBox, aDC, coord[3].x, coord[3].y,
+                   0.0 - angle, 900.0 - angle, r,
+                   0, aDrawInfo.m_Color );
+            GRArc( aClipBox, aDC, coord[6].x, coord[6].y,
+                   2700.0 - angle, 0.0 - angle, r,
+                   0, aDrawInfo.m_Color );
+            GRArc( aClipBox, aDC, coord[9].x, coord[9].y,
+                   1800.0 - angle, 2700.0 - angle, r,
+                   0, aDrawInfo.m_Color );
+        }
+        break;
+
     default:
         break;
     }
@@ -759,3 +840,140 @@
             RotatePoint( &aCoord[ii], aRotation );
     }
 }
+
+int D_PAD::BuildPadPolygonRoundRect( wxPoint aCoord[12], wxSize aInflateValue,
+				     double aRotation ) const
+{
+    int r;
+
+    /*
+     * There are three cases here:
+     *
+     * 1. aInflateValue.x == ainflateValue.y == 0
+     *
+     * This means the actual pad polygon is build.
+     *
+     * 2. aInflateValue.x == ainflateValue.y and both > 0
+     *
+     * This means the clearance polygon is build.
+     *
+     * 3. aInflateValue.x < 0 && ainflateValue.y < 0 but *.x and *.y may differ
+     *
+     * This means the paste polygon is build.
+     *
+     * Other cases are not supported (and can't happen as far as I see).
+     */
+
+    if( aInflateValue.x == 0 ) // case 1
+    {
+	r = BuildPadPolygonRoundRect( aCoord, m_Size );
+    }
+    else if( aInflateValue.x > 0 ) // case 2
+    {
+	r = BuildPadPolygonRoundRect( aCoord, m_Size );
+
+	// inflate the polygon and correct the corner radius
+	// this makes sure the distance between pad and clearance polygons
+	// is the same everywhere
+	aCoord[1].y += aInflateValue.y;
+	aCoord[2].y += aInflateValue.y;
+	aCoord[4].x += aInflateValue.x;
+	aCoord[5].x += aInflateValue.x;
+	aCoord[7].y -= aInflateValue.y;
+	aCoord[8].y -= aInflateValue.y;
+	aCoord[10].x -= aInflateValue.x;
+	aCoord[11].x -= aInflateValue.x;
+	r += aInflateValue.x;
+    }
+    else // case 3
+    {
+	// because inflation (actually shrinkage) may be asymmetrical here
+	// equal distance between pad and solder paste can't be done
+	// looks good enough anyway
+	r = BuildPadPolygonRoundRect( aCoord, m_Size + aInflateValue );
+    }
+    
+    // Finally rotate the polygon
+    
+    if( aRotation )
+    {
+        for( int ii = 0; ii < 12; ii++ )
+            RotatePoint( &aCoord[ii], aRotation );
+    }
+
+    return r;
+}
+
+int D_PAD::BuildPadPolygonRoundRect( wxPoint aCoord[12], wxSize size ) const
+{
+    wxSize halfsize;
+    int r;
+
+    halfsize.x = size.x >> 1;
+    halfsize.y = size.y >> 1;
+
+    r = GetRoundRectCornerRadius( size );
+
+    /*
+     * The unrotated pad polygon for PAD_ROUNDRECT looks like this:
+     *
+     *      1    2
+     *      +----+
+     *     0|    |3
+     * 11+--+    +--+4
+     *   |          |
+     *   |          |
+     * 10+--+    +--+5
+     *     9|    |6
+     *      +----+
+     *      8    7
+     *
+     * The centers of the rounded corner arcs are at 0, 3, 6 and 9
+     * DO NOT CHANGE THAT, callers depend on it
+     *
+     */
+    aCoord[0].x = -halfsize.x + r;
+    aCoord[0].y = +halfsize.y - r;
+    aCoord[1].x = -halfsize.x + r;
+    aCoord[1].y = +halfsize.y;
+    aCoord[2].x = +halfsize.x - r;
+    aCoord[2].y = +halfsize.y;
+    aCoord[3].x = +halfsize.x - r;
+    aCoord[3].y = +halfsize.y - r;
+    aCoord[4].x = +halfsize.x;
+    aCoord[4].y = +halfsize.y - r;
+    aCoord[5].x = +halfsize.x;
+    aCoord[5].y = -halfsize.y + r;
+    aCoord[6].x = +halfsize.x - r;
+    aCoord[6].y = -halfsize.y + r;
+    aCoord[7].x = +halfsize.x - r;
+    aCoord[7].y = -halfsize.y;
+    aCoord[8].x = -halfsize.x + r;
+    aCoord[8].y = -halfsize.y;
+    aCoord[9].x = -halfsize.x + r;
+    aCoord[9].y = -halfsize.y + r;
+    aCoord[10].x = -halfsize.x;
+    aCoord[10].y = -halfsize.y + r;
+    aCoord[11].x = -halfsize.x;
+    aCoord[11].y = +halfsize.y - r;
+
+    return r;
+}
+
+int D_PAD::GetRoundRectCornerRadius( wxSize size ) const
+{
+    // radius of rounded corners, fixed 25% of shorter pad edge for now
+    int r = size.x > size.y ? (size.y >> 2) : (size.x >> 2);
+    // but not more than 0.25 mm
+    if ( r > 250000 )
+    {
+        r = 250000;
+    }
+
+    return r;
+}
+
+int D_PAD::GetRoundRectCornerRadius() const
+{
+    return GetRoundRectCornerRadius( m_Size );
+}

=== modified file 'pcbnew/dialogs/dialog_pad_properties.cpp'
--- pcbnew/dialogs/dialog_pad_properties.cpp	2014-11-19 18:39:02 +0000
+++ pcbnew/dialogs/dialog_pad_properties.cpp	2015-02-22 16:52:36 +0000
@@ -55,7 +55,8 @@
     PAD_CIRCLE,
     PAD_OVAL,
     PAD_RECT,
-    PAD_TRAPEZOID
+    PAD_TRAPEZOID,
+    PAD_ROUNDRECT
 };
 
 
@@ -512,6 +513,10 @@
     case PAD_TRAPEZOID:
         m_PadShape->SetSelection( 3 );
         break;
+
+    case PAD_ROUNDRECT:
+        m_PadShape->SetSelection( 4 );
+        break;	    
     }
 
     msg.Printf( wxT( "%g" ), angle );
@@ -592,6 +597,14 @@
         m_ShapeOffset_X_Ctrl->Enable( true );
         m_ShapeOffset_Y_Ctrl->Enable( true );
         break;
+
+    case 4:     // PAD_ROUNDRECT:
+        m_ShapeDelta_Ctrl->Enable( false );
+        m_trapDeltaDirChoice->Enable( false );
+        m_ShapeSize_Y_Ctrl->Enable( true );
+        m_ShapeOffset_X_Ctrl->Enable( true );
+        m_ShapeOffset_Y_Ctrl->Enable( true );
+        break;
     }
 
     transferDataToPad( m_dummyPad );
@@ -1126,6 +1139,10 @@
     case PAD_TRAPEZOID:
         break;
 
+    case PAD_ROUNDRECT:
+        aPad->SetDelta( wxSize( 0, 0 ) );
+        break;
+
     default:
         ;
     }

=== modified file 'pcbnew/dialogs/dialog_pad_properties_base.cpp'
--- pcbnew/dialogs/dialog_pad_properties_base.cpp	2015-02-18 19:27:00 +0000
+++ pcbnew/dialogs/dialog_pad_properties_base.cpp	2015-02-22 16:52:36 +0000
@@ -65,10 +65,10 @@
 	m_staticText45->Wrap( -1 );
 	fgSizerPadType->Add( m_staticText45, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxTOP, 5 );
 	
-	wxString m_PadShapeChoices[] = { _("Circular"), _("Oval"), _("Rectangular"), _("Trapezoidal") };
+	wxString m_PadShapeChoices[] = { _("Circular"), _("Oval"), _("Rectangular"), _("Trapezoidal"), _("Rounded Rectangle") };
 	int m_PadShapeNChoices = sizeof( m_PadShapeChoices ) / sizeof( wxString );
 	m_PadShape = new wxChoice( m_panelGeneral, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_PadShapeNChoices, m_PadShapeChoices, 0 );
-	m_PadShape->SetSelection( 0 );
+	m_PadShape->SetSelection( 4 );
 	fgSizerPadType->Add( m_PadShape, 0, wxALIGN_CENTER_VERTICAL|wxALL|wxEXPAND, 5 );
 	
 	

=== modified file 'pcbnew/dialogs/dialog_pad_properties_base.fbp'
--- pcbnew/dialogs/dialog_pad_properties_base.fbp	2015-02-18 19:27:00 +0000
+++ pcbnew/dialogs/dialog_pad_properties_base.fbp	2015-02-22 16:52:36 +0000
@@ -271,16 +271,16 @@
                                                 <property name="border">5</property>
                                                 <property name="flag">wxALL|wxEXPAND</property>
                                                 <property name="proportion">3</property>
-                                                <object class="wxBoxSizer" expanded="0">
+                                                <object class="wxBoxSizer" expanded="1">
                                                     <property name="minimum_size"></property>
                                                     <property name="name">m_LeftBoxSizer</property>
                                                     <property name="orient">wxVERTICAL</property>
                                                     <property name="permission">none</property>
-                                                    <object class="sizeritem" expanded="0">
+                                                    <object class="sizeritem" expanded="1">
                                                         <property name="border">5</property>
                                                         <property name="flag">wxEXPAND|wxTOP|wxRIGHT|wxLEFT</property>
                                                         <property name="proportion">0</property>
-                                                        <object class="wxFlexGridSizer" expanded="0">
+                                                        <object class="wxFlexGridSizer" expanded="1">
                                                             <property name="cols">2</property>
                                                             <property name="flexible_direction">wxBOTH</property>
                                                             <property name="growablecols">1</property>
@@ -912,7 +912,7 @@
                                                                     <property name="caption"></property>
                                                                     <property name="caption_visible">1</property>
                                                                     <property name="center_pane">0</property>
-                                                                    <property name="choices">&quot;Circular&quot; &quot;Oval&quot; &quot;Rectangular&quot; &quot;Trapezoidal&quot;</property>
+                                                                    <property name="choices">&quot;Circular&quot; &quot;Oval&quot; &quot;Rectangular&quot; &quot;Trapezoidal&quot; &quot;Rounded Rectangle&quot;</property>
                                                                     <property name="close_button">1</property>
                                                                     <property name="context_help"></property>
                                                                     <property name="context_menu">1</property>
@@ -942,7 +942,7 @@
                                                                     <property name="pin_button">1</property>
                                                                     <property name="pos"></property>
                                                                     <property name="resize">Resizable</property>
-                                                                    <property name="selection">0</property>
+                                                                    <property name="selection">4</property>
                                                                     <property name="show">1</property>
                                                                     <property name="size"></property>
                                                                     <property name="style"></property>

=== modified file 'pcbnew/drc_clearance_test_functions.cpp'
--- pcbnew/drc_clearance_test_functions.cpp	2014-06-25 17:01:50 +0000
+++ pcbnew/drc_clearance_test_functions.cpp	2015-02-22 16:52:36 +0000
@@ -595,6 +595,11 @@
 
     double  pad_angle;
 
+    /*
+     * FIXME: MGri - for now treat PAD_ROUNDRECT like PAD_RECT
+     * This is suboptimal, around the corners clearance will be too large
+     */
+    
     // Get the clerance between the 2 pads. this is the min distance between aRefPad and aPad
     int     dist_min = aRefPad->GetClearance( aPad );
 
@@ -621,7 +626,7 @@
     // priority is aRefPad = ROUND then OVAL then RECT then other
     if( aRefPad->GetShape() != aPad->GetShape() && aRefPad->GetShape() != PAD_CIRCLE )
     {
-        // pad ref shape is here oval, rect or trapezoid
+        // pad ref shape is here oval, rect, roundrect or trapezoid
         switch( aPad->GetShape() )
         {
             case PAD_CIRCLE:
@@ -633,6 +638,7 @@
                 break;
 
             case PAD_RECT:
+            case PAD_ROUNDRECT: // FIXME: MGri - is this correct?
                 if( aRefPad->GetShape() != PAD_OVAL )
                     swap_pads = true;
                 break;
@@ -672,11 +678,12 @@
         break;
 
     case PAD_RECT:
+    case PAD_ROUNDRECT: // FIXME: MGri - not optimal, could go closer to round corners
         // pad_angle = pad orient relative to the aRefPad orient
         pad_angle = aRefPad->GetOrientation() + aPad->GetOrientation();
         NORMALIZE_ANGLE_POS( pad_angle );
 
-        if( aPad->GetShape() == PAD_RECT )
+        if( aPad->GetShape() == PAD_RECT || aPad->GetShape() == PAD_ROUNDRECT )
         {
             wxSize size = aPad->GetSize();
 
@@ -708,8 +715,15 @@
             {   // Use the trapezoid2trapezoidDRC which also compare 2 rectangles with any orientation
                 wxPoint polyref[4];         // Shape of aRefPad
                 wxPoint polycompare[4];     // Shape of aPad
-                aRefPad->BuildPadPolygon( polyref, wxSize( 0, 0 ), aRefPad->GetOrientation() );
-                aPad->BuildPadPolygon( polycompare, wxSize( 0, 0 ), aPad->GetOrientation() );
+
+                // FIXME: MGri - Nasty hack here...
+                D_PAD p(*aPad);
+                p.SetShape( PAD_RECT );
+                D_PAD rp(*aRefPad);
+                rp.SetShape( PAD_RECT );
+
+                rp.BuildPadPolygon( polyref, wxSize( 0, 0 ), rp.GetOrientation() );
+                p.BuildPadPolygon( polycompare, wxSize( 0, 0 ), p.GetOrientation() );
 
                 // Move aPad shape to relativePadPos
                 for( int ii = 0; ii < 4; ii++ )
@@ -828,6 +842,7 @@
     wxPoint startPoint, endPoint;
     int     seuil;
     int     deltay;
+    int     r;
 
     int     segmHalfWidth = aSegmentWidth / 2;
 
@@ -992,6 +1007,66 @@
 
         break;
 
+    case PAD_ROUNDRECT:
+        /* Test du rectangle dimx + seuil, dimy */
+        m_xcliplo = m_padToTestPos.x - padHalfsize.x - seuil;
+        m_ycliplo = m_padToTestPos.y - padHalfsize.y;
+        m_xcliphi = m_padToTestPos.x + padHalfsize.x + seuil;
+        m_ycliphi = m_padToTestPos.y + padHalfsize.y;
+
+        if( !checkLine( startPoint, endPoint ) )
+            return false;
+
+        /* Test du rectangle dimx , dimy + seuil */
+        m_xcliplo = m_padToTestPos.x - padHalfsize.x;
+        m_ycliplo = m_padToTestPos.y - padHalfsize.y - seuil;
+        m_xcliphi = m_padToTestPos.x + padHalfsize.x;
+        m_ycliphi = m_padToTestPos.y + padHalfsize.y + seuil;
+
+        if( !checkLine( startPoint, endPoint ) )
+            return false;
+
+	r = aPad->GetRoundRectCornerRadius();
+	
+        /* test des 4 cercles ( surface d'solation autour des sommets */
+        /* test du coin sup. gauche du pad */
+        startPoint.x = m_padToTestPos.x - padHalfsize.x + r;
+        startPoint.y = m_padToTestPos.y - padHalfsize.y + r;
+        RotatePoint( &startPoint, m_padToTestPos, orient );
+        RotatePoint( &startPoint, m_segmAngle );
+
+        if( !checkMarginToCircle( startPoint, seuil + r, m_segmLength ) )
+            return false;
+
+        /* test du coin sup. droit du pad */
+        startPoint.x = m_padToTestPos.x + padHalfsize.x - r;
+        startPoint.y = m_padToTestPos.y - padHalfsize.y + r;
+        RotatePoint( &startPoint, m_padToTestPos, orient );
+        RotatePoint( &startPoint, m_segmAngle );
+
+        if( !checkMarginToCircle( startPoint, seuil + r, m_segmLength ) )
+            return false;
+
+        /* test du coin inf. gauche du pad */
+        startPoint.x = m_padToTestPos.x - padHalfsize.x + r;
+        startPoint.y = m_padToTestPos.y + padHalfsize.y - r;
+        RotatePoint( &startPoint, m_padToTestPos, orient );
+        RotatePoint( &startPoint, m_segmAngle );
+
+        if( !checkMarginToCircle( startPoint, seuil + r, m_segmLength ) )
+            return false;
+
+        /* test du coin inf. droit du pad */
+        startPoint.x = m_padToTestPos.x + padHalfsize.x - r;
+        startPoint.y = m_padToTestPos.y + padHalfsize.y - r;
+        RotatePoint( &startPoint, m_padToTestPos, orient );
+        RotatePoint( &startPoint, m_segmAngle );
+
+        if( !checkMarginToCircle( startPoint, seuil + r, m_segmLength ) )
+            return false;
+
+        break;
+
     case PAD_TRAPEZOID:
     {
         wxPoint poly[4];

=== modified file 'pcbnew/exporters/export_gencad.cpp'
--- pcbnew/exporters/export_gencad.cpp	2015-02-22 14:43:44 +0000
+++ pcbnew/exporters/export_gencad.cpp	2015-02-22 16:52:36 +0000
@@ -553,6 +553,13 @@
 
             // XXX TO BE IMPLEMENTED! and I don't know if it could be actually imported by something
             break;
+
+        case PAD_ROUNDRECT:
+            fprintf( aFile, " POLYGON %g\n",
+                     pad->GetDrillSize().x / SCALE_FACTOR );
+
+            // XXX TO BE IMPLEMENTED! But how to test it?
+            break;
         }
     }
 

=== modified file 'pcbnew/exporters/export_vrml.cpp'
--- pcbnew/exporters/export_vrml.cpp	2015-02-18 19:27:00 +0000
+++ pcbnew/exporters/export_vrml.cpp	2015-02-22 16:52:36 +0000
@@ -1095,6 +1095,10 @@
         break;
     }
 
+    case PAD_ROUNDRECT:
+        throw( std::runtime_error( "Exporting roundrect pads to VRML not yet implemented." ) );
+        break;
+    
     default:
         break;
     }

=== modified file 'pcbnew/kicad_plugin.cpp'
--- pcbnew/kicad_plugin.cpp	2015-02-18 19:27:00 +0000
+++ pcbnew/kicad_plugin.cpp	2015-02-22 16:52:36 +0000
@@ -1275,6 +1275,7 @@
     case PAD_RECT:      shape = "rect";         break;
     case PAD_OVAL:      shape = "oval";         break;
     case PAD_TRAPEZOID: shape = "trapezoid";    break;
+    case PAD_ROUNDRECT: shape = "roundrect";    break;
 
     default:
         THROW_IO_ERROR( wxString::Format( _( "unknown pad type: %d"), aPad->GetShape() ) );

=== modified file 'pcbnew/pcb_painter.cpp'
--- pcbnew/pcb_painter.cpp	2015-02-18 19:27:00 +0000
+++ pcbnew/pcb_painter.cpp	2015-02-22 16:52:36 +0000
@@ -650,6 +650,44 @@
         m_gal->DrawRectangle( VECTOR2D( -size.x, -size.y ), VECTOR2D( size.x, size.y ) );
         break;
 
+    case PAD_ROUNDRECT:
+    {
+        std::deque<VECTOR2D> pointList;
+        wxPoint corners[12];
+
+        VECTOR2D padSize = VECTOR2D( aPad->GetSize().x, aPad->GetSize().y ) / 2;
+        VECTOR2D deltaPadSize = size - padSize; // = solder[Paste/Mask]Margin or 0
+
+        int r = aPad->BuildPadPolygonRoundRect( corners, wxSize( deltaPadSize.x, deltaPadSize.y ), 0.0 );
+
+        if( m_pcbSettings.m_sketchMode[ITEM_GAL_LAYER( PADS_VISIBLE )] )
+        {
+            // Outline mode
+            m_gal->DrawLine( VECTOR2D( corners[1] ), VECTOR2D( corners[2] ) );
+            m_gal->DrawLine( VECTOR2D( corners[4] ), VECTOR2D( corners[5] ) );
+            m_gal->DrawLine( VECTOR2D( corners[7] ), VECTOR2D( corners[8] ) );
+            m_gal->DrawLine( VECTOR2D( corners[10] ), VECTOR2D( corners[11] ) );
+            m_gal->DrawArc( VECTOR2D( corners[0] ), r, M_PI / 2, M_PI );
+            m_gal->DrawArc( VECTOR2D( corners[3] ), r, 0, M_PI / 2 );
+            m_gal->DrawArc( VECTOR2D( corners[6] ), r, 3 * M_PI / 2, 2 * M_PI );
+            m_gal->DrawArc( VECTOR2D( corners[9] ), r, M_PI, 3 * M_PI / 2 );
+        }
+        else
+        {
+            // Filled mode
+            for( int ii = 0; ii < 12; ii++ )
+            {
+                pointList.push_back( VECTOR2D( corners[ii] ) );
+            }
+            m_gal->DrawPolygon( pointList );
+            m_gal->DrawArc( VECTOR2D( corners[0] ), r, M_PI / 2, M_PI );
+            m_gal->DrawArc( VECTOR2D( corners[3] ), r, 0, M_PI / 2 );
+            m_gal->DrawArc( VECTOR2D( corners[6] ), r, 3 * M_PI / 2, 2 * M_PI );
+            m_gal->DrawArc( VECTOR2D( corners[9] ), r, M_PI, 3 * M_PI / 2 );
+         }
+        break;
+    }
+        
     case PAD_TRAPEZOID:
     {
         std::deque<VECTOR2D> pointList;

=== modified file 'pcbnew/pcb_parser.cpp'
--- pcbnew/pcb_parser.cpp	2015-02-21 00:41:10 +0000
+++ pcbnew/pcb_parser.cpp	2015-02-22 16:52:36 +0000
@@ -2213,8 +2213,12 @@
         pad->SetShape( PAD_TRAPEZOID );
         break;
 
+    case T_roundrect:
+        pad->SetShape( PAD_ROUNDRECT );
+        break;
+
     default:
-        Expecting( "circle, rectangle, oval, or trapezoid" );
+        Expecting( "circle, rectangle, roundrect, oval, or trapezoid" );
     }
 
     for( token = NextTok();  token != T_RIGHT;  token = NextTok() )

=== modified file 'pcbnew/plot_board_layers.cpp'
--- pcbnew/plot_board_layers.cpp	2015-02-18 19:27:00 +0000
+++ pcbnew/plot_board_layers.cpp	2015-02-22 16:52:36 +0000
@@ -380,6 +380,7 @@
                 // Fall through:
             case PAD_TRAPEZOID:
             case PAD_RECT:
+            case PAD_ROUNDRECT:
             default:
                 itemplotter.PlotPad( pad, color, plotMode );
                 break;

=== modified file 'pcbnew/plot_brditems_plotter.cpp'
--- pcbnew/plot_brditems_plotter.cpp	2015-02-18 19:27:00 +0000
+++ pcbnew/plot_brditems_plotter.cpp	2015-02-22 16:52:36 +0000
@@ -91,6 +91,15 @@
         }
         break;
 
+    case PAD_ROUNDRECT:
+        {
+            wxPoint coord[12];
+            int r = aPad->BuildPadPolygonRoundRect( coord, wxSize(0,0), 0 );
+            m_plotter->FlashPadRoundRect( shape_pos, coord, r,
+                                          aPad->GetOrientation(), aPlotMode );
+        }
+        break;
+	    
     case PAD_RECT:
     default:
         m_plotter->FlashPadRect( shape_pos, aPad->GetSize(),

=== modified file 'pcbnew/router/pns_router.cpp'
--- pcbnew/router/pns_router.cpp	2014-11-27 10:51:16 +0000
+++ pcbnew/router/pns_router.cpp	2015-02-22 16:52:36 +0000
@@ -205,6 +205,11 @@
             solid->SetShape( new SHAPE_RECT( c - sz / 2, sz.x, sz.y ) );
             break;
 
+        case PAD_ROUNDRECT:
+            // FIXME: not optimal and the optical effect is confusing
+            solid->SetShape( new SHAPE_RECT( c - sz / 2, sz.x, sz.y ) );
+            break;
+
         default:
             TRACEn( 0, "unsupported pad shape" );
             delete solid;

=== modified file 'pcbnew/specctra_export.cpp'
--- pcbnew/specctra_export.cpp	2015-02-17 18:47:21 +0000
+++ pcbnew/specctra_export.cpp	2015-02-22 16:52:36 +0000
@@ -477,6 +477,7 @@
         break;
 
     case PAD_RECT:
+    case PAD_ROUNDRECT: // For now handle roundrects as rects
         {
             double  dx  = scale( aPad->GetSize().x ) / 2.0;
             double  dy  = scale( aPad->GetSize().y ) / 2.0;