← Back to team overview

kicad-developers team mailing list archive

[PATCH] V2 Rectangular pads with rounded corners

 

Hi everybody,

below is a new version of a patch to add support for rectangular pads
with rounded corners to KiCad. The patch was created against revision
5428.

What has changed:

- optimized Gerber output
- plotting to PDF and Postscript should now produce correct results (as
far as I can check that)
- plotting to SVG should work, but does produce little artifacts in the
rounded corners, I think the SVG plotter does strange things with the
fill mode


BTW, does anybody know what the CERN people are doing? Because properly
supporting roundrect pads in the PNS router needs an extension to the
geometry primitives, something like a convex polygon shape (as a bonus
this would make support for arbitrarily rotated pads possible).

The thought of myself extending the geometry primitives is a bit
scary... ;-)


Enjoy,

MGri


=== modified file 'common/common_plotDXF_functions.cpp'
--- common/common_plotDXF_functions.cpp	2015-02-02 08:06:39 +0000
+++ common/common_plotDXF_functions.cpp	2015-02-17 19:36:08 +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 )
+{
+    // FIXME: MGri - not implemented yet
+}
 
 /**
  * DXF trapezoidal pad: only sketch mode is supported

=== modified file 'common/common_plotGERBER_functions.cpp'
--- common/common_plotGERBER_functions.cpp	2015-02-02 08:06:39 +0000
+++ common/common_plotGERBER_functions.cpp	2015-02-17 19:36:08 +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-17 16:32:47 +0000
+++ common/common_plotHPGL_functions.cpp	2015-02-17 19:36:08 +0000
@@ -629,6 +629,12 @@
     }
 }
 
+void HPGL_PLOTTER::FlashPadRoundRect( const wxPoint& pos, const wxPoint corners[12],
+                                      int cornerRadius, double orient,
+                                      EDA_DRAW_MODE_T trace_mode )
+{
+    // FIXME: MGri - not implemented yet
+}
 
 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-17 19:36:08 +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-17 19:36:08 +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-17 19:36:08 +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	2014-12-23 13:01:59 +0000
+++ include/plot_common.h	2015-02-17 19:36:08 +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-01-15 20:01:53 +0000
+++ pcbnew/board_items_to_polygon_shape_transform.cpp	2015-02-17 19:36:08 +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-01-17 08:01:16 +0000
+++ pcbnew/class_pad.cpp	2015-02-17 19:36:08 +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;
@@ -765,6 +774,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;
@@ -848,6 +881,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-01-17 08:01:16 +0000
+++ pcbnew/class_pad.h	2015-02-17 19:36:08 +0000
@@ -283,6 +283,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
@@ -466,6 +487,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.
      */
@@ -485,7 +518,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-01-10 10:27:49 +0000
+++ pcbnew/class_pad_draw_functions.cpp	2015-02-17 19:36:08 +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-17 19:36:08 +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-01-10 10:27:49 +0000
+++ pcbnew/dialogs/dialog_pad_properties_base.cpp	2015-02-17 19:36:08 +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-01-10 10:27:49 +0000
+++ pcbnew/dialogs/dialog_pad_properties_base.fbp	2015-02-17 19:36:08 +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-17 19:36:08 +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/kicad_plugin.cpp'
--- pcbnew/kicad_plugin.cpp	2015-02-17 18:47:21 +0000
+++ pcbnew/kicad_plugin.cpp	2015-02-17 19:36:08 +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-01-10 10:27:49 +0000
+++ pcbnew/pcb_painter.cpp	2015-02-17 19:36:08 +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-17 18:47:21 +0000
+++ pcbnew/pcb_parser.cpp	2015-02-17 19:36:08 +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-02 08:06:39 +0000
+++ pcbnew/plot_board_layers.cpp	2015-02-17 19:36:08 +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-02 08:06:39 +0000
+++ pcbnew/plot_brditems_plotter.cpp	2015-02-17 19:36:08 +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-17 19:36:08 +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-17 19:36:08 +0000
@@ -477,6 +477,7 @@
         break;
 
     case PAD_RECT:
+    case PAD_ROUNDRECT: // Does Specctra know round rects?
         {
             double  dx  = scale( aPad->GetSize().x ) / 2.0;
             double  dy  = scale( aPad->GetSize().y ) / 2.0;



Follow ups