← Back to team overview

kicad-developers team mailing list archive

[PATCH] new feature: adding rounded rect pads

 

Gentlemen,

Attached a patch which adds rounded rectangle pads to Pcbnew.

I *need testers* especially to test the DRC (but test also print and plot).
In order to support this new shape, the DRC code was widely modified and
cleaned.
Therefore bugs can happen, not only with rounded rect pads, but with
other pads.

Please, use this patch *only for tests*: the .kicad_pcb file format is
not compatible with the current Pcbnew version if Rounded Rect pads are
stored in file, and this new file format to support them is not yet
fully defined.

Thanks to Mathias Grimmberger. His patch helped me to start this work.

Thanks.

-- 
Jean-Pierre CHARRAS
=== modifié fichier common/common_plotDXF_functions.cpp
--- common/common_plotDXF_functions.cpp	2015-12-15 20:21:25 +0000
+++ common/common_plotDXF_functions.cpp	2016-01-15 09:41:03 +0000
@@ -5,7 +5,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2015 KiCad Developers, see CHANGELOG.TXT for contributors.
+ * Copyright (C) 2016 KiCad Developers, see CHANGELOG.TXT for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -617,6 +617,25 @@
     FinishTo( wxPoint( ox, oy ) );
 }

+void DXF_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aSize,
+                                     int aCornerRadius, double aOrient,
+                                     EDA_DRAW_MODE_T aTraceMode )
+{
+    SHAPE_POLY_SET outline;
+    const int segmentToCircleCount = 64;
+    TransformRoundRectToPolygon( outline, aPadPos, aSize, aOrient,
+                                 aCornerRadius, segmentToCircleCount );
+
+    // TransformRoundRectToPolygon creates only one convex polygon
+    SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
+
+    MoveTo( wxPoint( poly.Point( 0 ).x, poly.Point( 0 ).y ) );
+
+    for( int ii = 1; ii < poly.PointCount(); ++ii )
+        LineTo( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) );
+
+    FinishTo( wxPoint( poly.Point( 0 ).x, poly.Point( 0 ).y ) );
+}

 /**
  * DXF trapezoidal pad: only sketch mode is supported

=== modifié fichier common/common_plotGERBER_functions.cpp
--- common/common_plotGERBER_functions.cpp	2015-06-26 13:41:56 +0000
+++ common/common_plotGERBER_functions.cpp	2016-01-15 09:44:51 +0000
@@ -1,8 +1,8 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2014 Jean-Pierre Charras, jp.charras at wanadoo.fr
- * Copyright (C) 2014 KiCad Developers, see CHANGELOG.TXT for contributors.
+ * Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
+ * Copyright (C) 2016 KiCad Developers, see CHANGELOG.TXT for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -36,6 +36,7 @@
 #include <plot_common.h>
 #include <macros.h>
 #include <kicad_string.h>
+#include <convert_basic_shapes_to_polygon.h>

 #include <build_version.h>

@@ -479,8 +480,9 @@

         if( trace_mode == FILLED )
         {
-	    /* XXX to do: use an aperture macro to declare the rotated pad */
-            /* The pad  is reduced to an oval with dy > dx */
+            // TODO: use an aperture macro to declare the rotated pad
+            //
+            // The pad is reduced to an segment with dy > dx
             delta = size.y - size.x;
             x0    = 0;
             y0    = -delta / 2;
@@ -559,12 +561,39 @@
     }
 }

+void GERBER_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aSize,
+                                     int aCornerRadius, double aOrient,
+                                     EDA_DRAW_MODE_T aTraceMode )
+
+{
+    // Currently, a Pad RoundRect is plotted as polygon.
+    // TODO: use Aperture macro and flash it
+    SHAPE_POLY_SET outline;
+    const int segmentToCircleCount = 64;
+    TransformRoundRectToPolygon( outline, aPadPos, aSize, aOrient,
+                                 aCornerRadius, segmentToCircleCount );
+
+    std::vector< wxPoint > cornerList;
+    cornerList.reserve( segmentToCircleCount + 5 );
+    // TransformRoundRectToPolygon creates only one convex polygon
+    SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
+
+    for( int ii = 0; ii < poly.PointCount(); ++ii )
+        cornerList.push_back( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) );
+
+    // Close polygon
+    cornerList.push_back( cornerList[0] );
+
+    PlotPoly( cornerList, ( aTraceMode == FILLED ) ? FILLED_SHAPE : NO_FILL );
+}

 void GERBER_PLOTTER::FlashPadTrapez( const wxPoint& aPadPos,  const wxPoint* aCorners,
                                      double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode )

 {
-    // XXX to do: use an aperture macro to declare the pad
+    // Currently, a Pad Trapezoid is plotted as polygon.
+    // TODO: use Aperture macro and flash it
+
     // polygon corners list
     std::vector< wxPoint > cornerList;


=== modifié fichier common/common_plotHPGL_functions.cpp
--- common/common_plotHPGL_functions.cpp	2015-06-26 13:41:56 +0000
+++ common/common_plotHPGL_functions.cpp	2016-01-15 09:40:29 +0000
@@ -1,8 +1,8 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2014 Jean-Pierre Charras, jp.charras at wanadoo.fr
- * Copyright (C) 2014 KiCad Developers, see CHANGELOG.TXT for contributors.
+ * Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
+ * Copyright (C) 2016 KiCad Developers, see CHANGELOG.TXT for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -197,6 +197,7 @@
 #include <plot_common.h>
 #include <macros.h>
 #include <kicad_string.h>
+#include <convert_basic_shapes_to_polygon.h>

 // HPGL scale factor (1 PLU = 1/40mm = 25 micrometers)
 static const double PLUsPERDECIMIL = 0.102041;
@@ -633,6 +634,34 @@
     }
 }

+void HPGL_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aSize,
+                                        int aCornerRadius, double aOrient,
+                                        EDA_DRAW_MODE_T aTraceMode )
+{
+    SHAPE_POLY_SET outline;
+    const int segmentToCircleCount = 32;
+    TransformRoundRectToPolygon( outline, aPadPos, aSize, aOrient,
+                                 aCornerRadius, segmentToCircleCount );
+
+    std::vector< wxPoint > cornerList;
+    cornerList.reserve( segmentToCircleCount + 4 );
+    // TransformRoundRectToPolygon creates only one convex polygon
+    SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
+
+    if( 0 /*aTrace_Mode == FILLED*/ )
+    {
+        // TODO:
+    }
+    else
+    {
+        MoveTo( wxPoint( poly.Point( 0 ).x, poly.Point( 0 ).y ) );
+
+        for( int ii = 1; ii < poly.PointCount(); ++ii )
+            LineTo( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) );
+
+        FinishTo(wxPoint( poly.Point( 0 ).x, poly.Point( 0 ).y ) );
+    }
+}

 void HPGL_PLOTTER::FlashPadTrapez( const wxPoint& aPadPos, const wxPoint* aCorners,
                                    double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode )

=== modifié fichier common/common_plotPS_functions.cpp
--- common/common_plotPS_functions.cpp	2015-06-26 13:41:56 +0000
+++ common/common_plotPS_functions.cpp	2016-01-15 09:40:54 +0000
@@ -1,8 +1,8 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2014 Jean-Pierre Charras, jp.charras at wanadoo.fr
- * Copyright (C) 2014 KiCad Developers, see CHANGELOG.TXT for contributors.
+ * Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
+ * Copyright (C) 2016 KiCad Developers, see CHANGELOG.TXT for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -35,6 +35,7 @@
 #include <plot_common.h>
 #include <macros.h>
 #include <kicad_string.h>
+#include <convert_basic_shapes_to_polygon.h>

 /* Forward declaration of the font width metrics
    (yes extern! this is the way to forward declare variables */
@@ -188,6 +189,42 @@
               GetCurrentLineWidth() );
 }

+void PSLIKE_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aSize,
+                                        int aCornerRadius, double aOrient,
+                                        EDA_DRAW_MODE_T aTraceMode )
+{
+    wxSize size( aSize );
+
+    if( aTraceMode == FILLED )
+        SetCurrentLineWidth( 0 );
+    else
+    {
+        SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH );
+        size.x -= GetCurrentLineWidth();
+        size.y -= GetCurrentLineWidth();
+        aCornerRadius -= GetCurrentLineWidth()/2;
+    }
+
+
+    SHAPE_POLY_SET outline;
+    const int segmentToCircleCount = 64;
+    TransformRoundRectToPolygon( outline, aPadPos, size, aOrient,
+                                 aCornerRadius, segmentToCircleCount );
+
+    std::vector< wxPoint > cornerList;
+    cornerList.reserve( segmentToCircleCount + 5 );
+    // TransformRoundRectToPolygon creates only one convex polygon
+    SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
+
+    for( int ii = 0; ii < poly.PointCount(); ++ii )
+        cornerList.push_back( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) );
+
+    // Close polygon
+    cornerList.push_back( cornerList[0] );
+
+    PlotPoly( cornerList, ( aTraceMode == FILLED ) ? FILLED_SHAPE : NO_FILL,
+              GetCurrentLineWidth() );
+}

 void PSLIKE_PLOTTER::FlashPadTrapez( const wxPoint& aPadPos, const wxPoint *aCorners,
                                      double aPadOrient, EDA_DRAW_MODE_T aTraceMode )

=== modifié fichier common/convert_basic_shapes_to_polygon.cpp
--- common/convert_basic_shapes_to_polygon.cpp	2015-07-27 19:45:57 +0000
+++ common/convert_basic_shapes_to_polygon.cpp	2016-01-17 16:26:21 +0000
@@ -64,6 +64,71 @@
     }
 }

+/* Returns the centers of the rounded corners of a rect.
+ */
+void GetRoundRectCornerCenters( wxPoint aCenters[4], int aRadius,
+                const wxPoint& aPosition, const wxSize& aSize, double aRotation )
+{
+    wxSize size( aSize/2 );
+
+    size.x -= aRadius;
+    size.y -= aRadius;
+
+    aCenters[0].x = -size.x;
+    aCenters[0].y = size.y;
+
+    aCenters[1].x = size.x;
+    aCenters[1].y = size.y;
+
+    aCenters[2].x = size.x;
+    aCenters[2].y = -size.y;
+
+    aCenters[3].x = -size.x;
+    aCenters[3].y = -size.y;
+
+    // Rotate the polygon
+    if( aRotation )
+    {
+        for( int ii = 0; ii < 4; ii++ )
+            RotatePoint( &aCenters[ii], aRotation );
+    }
+
+    // move the polygon to the position
+    for( int ii = 0; ii < 4; ii++ )
+        aCenters[ii] += aPosition;
+}
+
+/**
+ * Function TransformRoundRectToPolygon
+ * convert a rectangle with rounded corners to a polygon
+ * Convert arcs to multiple straight lines
+ * @param aCornerBuffer = a buffer to store the polygon
+ * @param aPosition = the coordinate of the center of the rectangle
+ * @param aSize = the size of the rectangle
+ * @param aRadius = radius of rounded corners
+ * @param aRotation = rotation in 0.1 degrees of the rectangle
+ * @param aCircleToSegmentsCount = the number of segments to approximate a circle
+ */
+void TransformRoundRectToPolygon( SHAPE_POLY_SET& aCornerBuffer,
+                                  const wxPoint& aPosition, const wxSize& aSize,
+                                  double aRotation, int aCornerRadius,
+                                  int aCircleToSegmentsCount )
+{
+    wxPoint corners[4];
+    GetRoundRectCornerCenters( corners, aCornerRadius, aPosition, aSize, aRotation );
+
+    SHAPE_POLY_SET outline;
+    outline.NewOutline();
+
+    for( int ii = 0; ii < 4; ++ii )
+        outline.Append( corners[ii].x, corners[ii].y );
+
+    outline.Inflate( aCornerRadius, aCircleToSegmentsCount );
+
+    // Add the outline:
+    aCornerBuffer.Append( outline );
+}
+

 /**
  * Function TransformRoundedEndsSegmentToPolygon

=== modifié fichier common/pcb.keywords
--- common/pcb.keywords	2013-09-17 00:52:08 +0000
+++ common/pcb.keywords	2016-01-12 13:19:27 +0000
@@ -142,6 +142,7 @@
 reference
 right
 rotate
+roundrect
 scale
 segment
 segment_width

=== modifié fichier include/convert_basic_shapes_to_polygon.h
--- include/convert_basic_shapes_to_polygon.h	2016-01-12 16:33:33 +0000
+++ include/convert_basic_shapes_to_polygon.h	2016-01-17 16:13:53 +0000
@@ -51,6 +51,34 @@
                                                 int aCircleToSegmentsCount );

 /**
+ * Helper function GetRoundRectCornerCenters
+ * Has meaning only for rounded rect
+ * Returns the centers of the rounded corners.
+ * @param aPosition = position of the round rect
+ * @param aSize = size of the of the round rect.
+ * @param aRotation = rotation of the of the round rect
+ * @param aCenters a buffer to store the 4 coordinates.
+ */
+void GetRoundRectCornerCenters( wxPoint aCenters[4], int aRadius,
+            const wxPoint& aPosition, const wxSize& aSize, double aRotation );
+
+/**
+ * Function TransformRoundRectToPolygon
+ * convert a rectangle with rounded corners to a polygon
+ * Convert arcs to multiple straight lines
+ * @param aCornerBuffer = a buffer to store the polygon
+ * @param aPosition = the coordinate of the center of the rectangle
+ * @param aSize = the size of the rectangle
+ * @param aCornerRadius = radius of rounded corners
+ * @param aRotation = rotation in 0.1 degrees of the rectangle
+ * @param aCircleToSegmentsCount = the number of segments to approximate a circle
+ */
+void TransformRoundRectToPolygon( SHAPE_POLY_SET& aCornerBuffer,
+                                  const wxPoint& aPosition, const wxSize& aSize,
+                                  double aRotation, int aCornerRadius,
+                                  int aCircleToSegmentsCount );
+
+/**
  * Function TransformRoundedEndsSegmentToPolygon
  * convert a segment with rounded ends to a polygon
  * Convert arcs to multiple straight lines

=== modifié fichier include/pad_shapes.h
--- include/pad_shapes.h	2016-01-12 16:33:33 +0000
+++ include/pad_shapes.h	2016-01-13 07:54:46 +0000
@@ -37,7 +37,8 @@
     PAD_SHAPE_OVAL,
     PAD_OVAL = PAD_SHAPE_OVAL,
     PAD_SHAPE_TRAPEZOID,
-    PAD_TRAPEZOID = PAD_SHAPE_TRAPEZOID
+    PAD_TRAPEZOID = PAD_SHAPE_TRAPEZOID,
+    PAD_SHAPE_ROUNDRECT
 };

 /**

=== modifié fichier include/plot_common.h
--- include/plot_common.h	2015-05-21 09:04:47 +0000
+++ include/plot_common.h	2016-01-14 15:08:00 +0000
@@ -280,6 +280,18 @@
     virtual void FlashPadRect( const wxPoint& aPadPos, const wxSize& aSize,
                                double aPadOrient, EDA_DRAW_MODE_T aTraceMode ) = 0;

+    /**
+     * virtual function FlashPadRoundRect
+     * @param aPadPos Position of the shape (center of the rectangle
+     * @param aSize = size of rouded rect
+     * @param cornerRadius Radius of the rounded corners
+     * @param aOrient The rotation of the shape
+     * @param aTraceMode FILLED or SKETCH
+     */
+    virtual void FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aSize,
+                                    int aCornerRadius, double aOrient,
+                                    EDA_DRAW_MODE_T aTraceMode ) = 0;
+
     /** virtual function FlashPadTrapez
      * flash a trapezoidal pad
      * @param aPadPos = the position of the shape
@@ -534,6 +546,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& aPadPos, const wxSize& aSize,
+                                    int aCornerRadius, double aOrient,
+                                    EDA_DRAW_MODE_T aTraceMode );
     virtual void FlashPadTrapez( const wxPoint& aPadPos, const wxPoint *aCorners,
                                  double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode );

@@ -586,6 +601,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& aPadPos, const wxSize& aSize,
+                                    int aCornerRadius, double aOrient,
+                                    EDA_DRAW_MODE_T aTraceMode );
     virtual void FlashPadTrapez( const wxPoint& aPadPos, const wxPoint *aCorners,
                                  double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode );

@@ -942,14 +960,25 @@
                                EDA_DRAW_MODE_T trace_mode );

     /**
-     * Filled rect flashes are handled as aperture in the 90 degree positions only
+     * Filled rect flashes are handled as aperture in the 0 90 180 or 270 degree orientation only
+     * and as polygon for other orientations
+     * TODO: always use flashed shapes (aperture macros)
      */
     virtual void FlashPadRect( const wxPoint& pos, const wxSize& size,
                                double orient, EDA_DRAW_MODE_T trace_mode );

     /**
+     * Roundrect pad at the moment are not handled as aperture, since
+     * they require aperture macros
+     * TODO: always use flashed shapes (aperture macros)
+     */
+    virtual void FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aSize,
+                                    int aCornerRadius, double aOrient,
+                                    EDA_DRAW_MODE_T aTraceMode );
+    /**
      * Trapezoidal pad at the moment are *never* handled as aperture, since
      * they require aperture macros
+     * TODO: always use flashed shapes (aperture macros)
      */
     virtual void FlashPadTrapez( const wxPoint& aPadPos, const wxPoint *aCorners,
                                  double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode );
@@ -1069,6 +1098,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& aPadPos, const wxSize& aSize,
+                                    int aCornerRadius, double aOrient,
+                                    EDA_DRAW_MODE_T aTraceMode );
     virtual void FlashPadTrapez( const wxPoint& aPadPos, const wxPoint *aCorners,
                                  double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode );


=== modifié fichier pcbnew/board_items_to_polygon_shape_transform.cpp
--- pcbnew/board_items_to_polygon_shape_transform.cpp	2015-12-15 20:21:25 +0000
+++ pcbnew/board_items_to_polygon_shape_transform.cpp	2016-01-15 16:12:02 +0000
@@ -1,8 +1,8 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2009-2014 Jean-Pierre Charras, jp.charras at wanadoo.fr
- * Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 2009-2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
+ * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -552,7 +552,7 @@
  * clearance when the circle is approximated by segment bigger or equal
  * to the real clearance value (usually near from 1.0)
  */
-void D_PAD:: TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
+void D_PAD::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
                                                    int             aClearanceValue,
                                                    int             aCircleToSegmentsCount,
                                                    double          aCorrectionFactor ) const
@@ -561,14 +561,14 @@
     int     dx = (m_Size.x / 2) + aClearanceValue;
     int     dy = (m_Size.y / 2) + aClearanceValue;

-    wxPoint PadShapePos = ShapePos();               /* Note: for pad having a shape offset,
+    wxPoint padShapePos = ShapePos();               /* Note: for pad having a shape offset,
                                                      * the pad position is NOT the shape position */

     switch( GetShape() )
     {
     case PAD_SHAPE_CIRCLE:
         dx = KiROUND( dx * aCorrectionFactor );
-        TransformCircleToPolygon( aCornerBuffer, PadShapePos, dx,
+        TransformCircleToPolygon( aCornerBuffer, padShapePos, dx,
                                   aCircleToSegmentsCount );
         break;

@@ -591,8 +591,8 @@
         }

         RotatePoint( &shape_offset, angle );
-        wxPoint start = PadShapePos - shape_offset;
-        wxPoint end = PadShapePos + shape_offset;
+        wxPoint start = padShapePos - shape_offset;
+        wxPoint end = padShapePos + shape_offset;
         TransformRoundedEndsSegmentToPolygon( aCornerBuffer, start, end,
                                               aCircleToSegmentsCount, width );
         }
@@ -605,18 +605,33 @@
         BuildPadPolygon( corners, wxSize( 0, 0 ), angle );

         SHAPE_POLY_SET outline;
-
         outline.NewOutline();

         for( int ii = 0; ii < 4; ii++ )
         {
-            corners[ii] += PadShapePos;
+            corners[ii] += padShapePos;
             outline.Append( corners[ii].x, corners[ii].y );
         }

-        double rounding_radius = aClearanceValue * aCorrectionFactor;
-
-        outline.Inflate( (int) rounding_radius, aCircleToSegmentsCount );
+        int rounding_radius = int( aClearanceValue * aCorrectionFactor );
+        outline.Inflate( rounding_radius, aCircleToSegmentsCount );
+
+        aCornerBuffer.Append( outline );
+    }
+        break;
+
+    case PAD_SHAPE_ROUNDRECT:
+    {
+        SHAPE_POLY_SET outline;
+        int pad_radius = GetRoundRectCornerRadius();
+        int clearance = int( aClearanceValue * aCorrectionFactor );
+        int rounding_radius = pad_radius + clearance;
+        wxSize shapesize( m_Size );
+        shapesize.x += clearance*2;
+        shapesize.y += clearance*2;
+
+        TransformRoundRectToPolygon( outline, padShapePos, shapesize, angle,
+                                     rounding_radius, aCircleToSegmentsCount );

         aCornerBuffer.Append( outline );
     }
@@ -636,12 +651,13 @@
                                   double aCorrectionFactor ) const
 {
     wxPoint corners[4];
-    wxPoint PadShapePos = ShapePos();         /* Note: for pad having a shape offset,
-                                                     * the pad position is NOT the shape position */
+    wxPoint padShapePos = ShapePos();       /* Note: for pad having a shape offset,
+                                             * the pad position is NOT the shape position */
     switch( GetShape() )
     {
     case PAD_SHAPE_CIRCLE:
     case PAD_SHAPE_OVAL:
+    case PAD_SHAPE_ROUNDRECT:
         TransformShapeWithClearanceToPolygon( aCornerBuffer, aInflateValue.x,
                                               aSegmentsPerCircle, aCorrectionFactor );
         break;
@@ -653,7 +669,7 @@
         BuildPadPolygon( corners, aInflateValue, m_Orient );
         for( int ii = 0; ii < 4; ii++ )
         {
-            corners[ii] += PadShapePos;          // Shift origin to position
+            corners[ii] += padShapePos;          // Shift origin to position
             aCornerBuffer.Append( corners[ii].x, corners[ii].y );
         }

@@ -734,7 +750,7 @@
                                        double          aThermalRot )
 {
     wxPoint corner, corner_end;
-    wxPoint PadShapePos = aPad.ShapePos();      // Note: for pad having a shape offset,
+    wxPoint padShapePos = aPad.ShapePos();      // Note: for pad having a shape offset,
                                                 // the pad position is NOT the shape position
     wxSize  copper_thickness;

@@ -836,7 +852,7 @@
                 {
                     corner = corners_buffer[ii];
                     RotatePoint( &corner, th_angle + angle_pad );          // Rotate by segment angle and pad orientation
-                    corner += PadShapePos;
+                    corner += padShapePos;
                     aCornerBuffer.Append( corner.x, corner.y );
                 }

@@ -940,7 +956,7 @@
                 {
                     wxPoint cpos = corners_buffer[ic];
                     RotatePoint( &cpos, angle );
-                    cpos += PadShapePos;
+                    cpos += padShapePos;
                     aCornerBuffer.Append( cpos.x, cpos.y );
                 }

@@ -966,7 +982,7 @@
                 {
                     wxPoint cpos = corners_buffer[ic];
                     RotatePoint( &cpos, angle );
-                    cpos += PadShapePos;
+                    cpos += padShapePos;
                     aCornerBuffer.Append( cpos.x, cpos.y );
                 }

@@ -975,7 +991,8 @@
         }
         break;

-    case PAD_SHAPE_RECT:       // draw 4 Holes
+    case PAD_SHAPE_ROUNDRECT:   // thermal shape is the same for round rect and rect.
+    case PAD_SHAPE_RECT:
         {
             /* we create 4 copper holes and put them in position 1, 2, 3 and 4
              * here is the area of the rectangular pad + its thermal gap
@@ -1039,7 +1056,7 @@
                 {
                     wxPoint cpos = corners_buffer[ic];
                     RotatePoint( &cpos, angle );            // Rotate according to module orientation
-                    cpos += PadShapePos;                    // Shift origin to position
+                    cpos += padShapePos;                    // Shift origin to position
                     aCornerBuffer.Append( cpos.x, cpos.y );
                 }

@@ -1063,7 +1080,7 @@
                 {
                     wxPoint cpos = corners_buffer[ic];
                     RotatePoint( &cpos, angle );
-                    cpos += PadShapePos;
+                    cpos += padShapePos;
                     aCornerBuffer.Append( cpos.x, cpos.y );
                 }

@@ -1110,7 +1127,7 @@
         {
             wxPoint cpos = stubBuffer[ii];
             RotatePoint( &cpos, aPad.GetOrientation() );
-            cpos += PadShapePos;
+            cpos += padShapePos;
             stub.Append( cpos.x, cpos.y );
         }

@@ -1132,7 +1149,7 @@
         {
             wxPoint cpos = stubBuffer[ii];
             RotatePoint( &cpos, aPad.GetOrientation() );
-            cpos += PadShapePos;
+            cpos += padShapePos;
             stub.Append( cpos.x, cpos.y );
         }


=== modifié fichier pcbnew/class_pad.cpp
--- pcbnew/class_pad.cpp	2015-12-27 15:51:13 +0000
+++ pcbnew/class_pad.cpp	2016-01-17 15:36:38 +0000
@@ -48,6 +48,7 @@
 #include <polygon_test_point_inside.h>
 #include <convert_from_iu.h>
 #include <boost/foreach.hpp>
+#include <convert_basic_shapes_to_polygon.h>


 int D_PAD::m_PadSketchModePenSize = 0;      // Pen size used to draw pads in sketch mode
@@ -74,6 +75,10 @@
     m_LocalSolderMaskMargin  = 0;
     m_LocalSolderPasteMargin = 0;
     m_LocalSolderPasteMarginRatio = 0.0;
+    // Parameters for round rect only:
+    m_padRoundRectRadiusScale = 0.25;                   // from  IPC-7351C standard
+    m_padRoundRectRadiusMax = Millimeter2iu( 0.25 );    // from  IPC-7351C standard
+
     m_ZoneConnection      = PAD_ZONE_CONN_INHERITED; // Use parent setting by default
     m_ThermalWidth        = 0;                  // Use parent setting by default
     m_ThermalGap          = 0;                  // Use parent setting by default
@@ -110,8 +115,6 @@

 LSET D_PAD::UnplatedHoleMask()
 {
-    // was #define PAD_ATTRIB_HOLE_NOT_PLATED_DEFAULT_LAYERS ALL_CU_LAYERS |
-    // SILKSCREEN_LAYER_FRONT | SOLDERMASK_LAYER_BACK | SOLDERMASK_LAYER_FRONT
     static LSET saved = LSET::AllCuMask() | LSET( 3, F_SilkS, B_Mask, F_Mask );
     return saved;
 }
@@ -142,6 +145,13 @@
         radius = 1 + KiROUND( hypot( x, y ) / 2 );
         break;

+    case PAD_SHAPE_ROUNDRECT:
+        radius = GetRoundRectCornerRadius();
+        x = m_Size.x >> 1;
+        y = m_Size.y >> 1;
+        radius += 1 + KiROUND( EuclideanNorm( wxSize( x - radius, y - radius )));
+        break;
+
     default:
         radius = 0;
     }
@@ -150,6 +160,23 @@
 }


+int D_PAD::GetRoundRectCornerRadius( const wxSize& aSize ) const
+{
+    // radius of rounded corners, usually 25% of shorter pad edge for now
+    int r = aSize.x > aSize.y ? aSize.y : aSize.x;
+    r = int( r * m_padRoundRectRadiusScale );
+
+    // but not more than usually 0.25 mm
+
+    if ( r > m_padRoundRectRadiusMax )
+    {
+        r = m_padRoundRectRadiusMax;
+    }
+
+    return r;
+}
+
+
 const EDA_RECT D_PAD::GetBoundingBox() const
 {
     EDA_RECT area;
@@ -180,6 +207,7 @@
         break;

     case PAD_SHAPE_RECT:
+    case PAD_SHAPE_ROUNDRECT:
         //Use two corners and track their rotation
         // (utilise symmetry to avoid four points)
         quadrant1.x =  m_Size.x/2;
@@ -768,6 +796,19 @@
             return true;

         break;
+
+    case PAD_SHAPE_ROUNDRECT:
+    {
+        // Check for hit in polygon
+        SHAPE_POLY_SET outline;
+        const int segmentToCircleCount = 32;
+        TransformRoundRectToPolygon( outline, wxPoint(0,0), GetSize(), m_Orient,
+                                 GetRoundRectCornerRadius(), segmentToCircleCount );
+
+        SHAPE_LINE_CHAIN &poly = outline.Outline( 0 );
+        return TestPointInsidePolygon( (wxPoint*)&poly.Point(0), poly.PointCount(), delta );
+    }
+        break;
     }

     return false;
@@ -854,6 +895,9 @@
     case PAD_SHAPE_TRAPEZOID:
         return _( "Trap" );

+    case PAD_SHAPE_ROUNDRECT:
+        return _( "Roundrect" );
+
     default:
         return wxT( "???" );
     }

=== modifié fichier pcbnew/class_pad.h
--- pcbnew/class_pad.h	2015-11-13 11:32:42 +0000
+++ pcbnew/class_pad.h	2016-01-20 17:03:51 +0000
@@ -1,8 +1,8 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@xxxxxxxxxxxxxxxxxx
- * Copyright (C) 1992-2011 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 2016 Jean-Pierre Charras, jaen-pierre.charras@xxxxxxxxxxxxxxxxxx
+ * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -324,6 +324,27 @@
     void BuildPadPolygon( wxPoint aCoord[4], wxSize aInflateValue, double aRotation ) const;

     /**
+     * Function GetRoundRectCornerRadius
+     * Has meaning only for rounded rect pads
+     * @return The radius of the rounded corners for this pad.
+     */
+    int GetRoundRectCornerRadius() const
+    {
+        return GetRoundRectCornerRadius( m_Size );
+    }
+
+    /**
+     * Helper function GetRoundRectCornerRadius
+     * Has meaning only for rounded rect pads
+     * Returns the radius of the rounded corners of a rectangle
+     * size aSize, using others setting of the pad
+     * @param aSize = size of the of the round rect. Usually the pad size
+     * but can be the size of the pad on solder mask or solder paste
+     * @return The radius of the rounded corners for this pad size.
+     */
+    int GetRoundRectCornerRadius( const wxSize& aSize ) const;
+
+    /**
      * Function BuildPadShapePolygon
      * Build the Corner list of the polygonal shape,
      * depending on shape, extra size (clearance ...) pad and orientation
@@ -340,7 +361,7 @@
      * @param aSegmentsPerCircle = number of segments to approximate a circle
      *              (used for round and oblong shapes only (16 to 32 is a good value)
      * @param aCorrectionFactor = the correction to apply to circles radius to keep
-     *        the pad size when the circle is approximated by segments
+     *        the pad size/clearance when the arcs are approximated by segments
      */
     void BuildPadShapePolygon( SHAPE_POLY_SET& aCornerBuffer,
                                wxSize aInflateValue, int aSegmentsPerCircle,
@@ -531,7 +552,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
@@ -545,6 +566,10 @@

     PAD_DRILL_SHAPE_T m_drillShape; ///< PAD_DRILL_SHAPE_CIRCLE, PAD_DRILL_SHAPE_OBLONG

+    double      m_padRoundRectRadiusScale;  ///< scaling factor from smallest m_Size coord
+                                            ///< to corner radius, default 0.25
+    int         m_padRoundRectRadiusMax;    ///< max corner radius
+

     /**
      * m_Offset is useful only for oblong pads (it can be used for other

=== modifié fichier pcbnew/class_pad_draw_functions.cpp
--- pcbnew/class_pad_draw_functions.cpp	2016-01-17 15:59:24 +0000
+++ pcbnew/class_pad_draw_functions.cpp	2016-01-20 17:03:36 +0000
@@ -1,10 +1,10 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@xxxxxxxxxxxxxxx
+ * Copyright (C) 2016 Jean-Pierre Charras, jean-pierre.charras@xxxxxxxxxxxxxxx
  * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@xxxxxxxxxxx>
  * Copyright (C) 2012 Wayne Stambaugh <stambaughw@xxxxxxxxxxx>
- * Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -40,6 +40,8 @@
 #include <pcbnew_id.h>             // ID_TRACK_BUTT
 #include <pcbnew.h>
 #include <class_board.h>
+#include <convert_basic_shapes_to_polygon.h>
+


 /* uncomment this line to show this pad with its specfic size and color
@@ -315,7 +317,7 @@

 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;

@@ -392,12 +394,67 @@

         if( aDrawInfo.m_PadClearance )
         {
-            BuildPadPolygon( coord, wxSize( aDrawInfo.m_PadClearance,
-                                            aDrawInfo.m_PadClearance ), angle );
-            for( int ii = 0; ii < 4; ii++ )
-                coord[ii] += shape_pos;
-
-            GRClosedPoly( aClipBox, aDC, 4, coord, 0, aDrawInfo.m_Color, aDrawInfo.m_Color );
+            #define SEGCOUNT 32     // number of segments to approximate a circle
+            SHAPE_POLY_SET outline;
+            TransformShapeWithClearanceToPolygon( outline, aDrawInfo.m_PadClearance, SEGCOUNT, 1.0 );
+
+            // Draw the polygon: Inflate creates only one convex polygon
+            SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
+
+            GRClosedPoly( aClipBox, aDC, poly.PointCount(),
+                          (wxPoint*)&poly.Point( 0 ), false, 0,
+                          aDrawInfo.m_Color, aDrawInfo.m_Color );
+        }
+        break;
+
+    case PAD_SHAPE_ROUNDRECT:
+        {
+        // Use solder[Paste/Mask]size or pad size to build pad shape to draw
+        wxSize size( GetSize() );
+        size += aDrawInfo.m_Mask_margin * 2;
+        int corner_radius = GetRoundRectCornerRadius( size );
+
+        // Draw the polygon: Inflate creates only one convex polygon
+        SHAPE_POLY_SET outline;
+        bool filled = aDrawInfo.m_ShowPadFilled;
+
+        if( filled )
+        {
+            wxPoint centers[4];
+            GetRoundRectCornerCenters( centers, corner_radius, shape_pos,
+                                       size, GetOrientation() );
+            GRClosedPoly( aClipBox, aDC, 4, centers, true, corner_radius*2,
+                          aDrawInfo.m_Color, aDrawInfo.m_Color );
+        }
+        else
+        {
+            TransformRoundRectToPolygon( outline, shape_pos, size, GetOrientation(),
+                                         corner_radius, 64 );
+
+            SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
+
+            GRClosedPoly( aClipBox, aDC, poly.PointCount(),
+                          (wxPoint*)&poly.Point( 0 ), false, 0,
+                          aDrawInfo.m_Color, aDrawInfo.m_Color );
+        }
+        if( aDrawInfo.m_PadClearance )
+        {
+            outline.RemoveAllContours();
+            size = GetSize();
+            size.x += aDrawInfo.m_PadClearance * 2;
+            size.y += aDrawInfo.m_PadClearance * 2;
+            corner_radius = GetRoundRectCornerRadius() + aDrawInfo.m_PadClearance;
+
+            TransformRoundRectToPolygon( outline, shape_pos, size, GetOrientation(),
+                                     corner_radius, 32 );
+
+            // Draw the polygon: Inflate creates only one convex polygon
+            SHAPE_LINE_CHAIN& clearance_poly = outline.Outline( 0 );
+
+            GRClosedPoly( aClipBox, aDC, clearance_poly.PointCount(),
+                          (wxPoint*)&clearance_poly.Point( 0 ), false, 0,
+                          aDrawInfo.m_Color, aDrawInfo.m_Color );
+        }
         }
         break;


=== modifié fichier pcbnew/dialogs/dialog_pad_properties.cpp
--- pcbnew/dialogs/dialog_pad_properties.cpp	2015-12-27 15:51:13 +0000
+++ pcbnew/dialogs/dialog_pad_properties.cpp	2016-01-12 13:19:27 +0000
@@ -55,7 +55,8 @@
     PAD_SHAPE_CIRCLE,
     PAD_SHAPE_OVAL,
     PAD_SHAPE_RECT,
-    PAD_SHAPE_TRAPEZOID
+    PAD_SHAPE_TRAPEZOID,
+    PAD_SHAPE_ROUNDRECT
 };


@@ -510,6 +511,10 @@
     case PAD_SHAPE_TRAPEZOID:
         m_PadShape->SetSelection( 3 );
         break;
+
+    case PAD_SHAPE_ROUNDRECT:
+        m_PadShape->SetSelection( 4 );
+        break;
     }

     msg.Printf( wxT( "%g" ), angle );
@@ -590,6 +595,14 @@
         m_ShapeOffset_X_Ctrl->Enable( true );
         m_ShapeOffset_Y_Ctrl->Enable( true );
         break;
+
+    case 4:     // PAD_SHAPE_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 );
@@ -1136,6 +1149,10 @@
     case PAD_SHAPE_TRAPEZOID:
         break;

+    case PAD_SHAPE_ROUNDRECT:
+        aPad->SetDelta( wxSize( 0, 0 ) );
+        break;
+
     default:
         ;
     }

=== modifié fichier pcbnew/dialogs/dialog_pad_properties_base.cpp
--- pcbnew/dialogs/dialog_pad_properties_base.cpp	2015-09-11 23:13:54 +0000
+++ pcbnew/dialogs/dialog_pad_properties_base.cpp	2016-01-12 13:35:15 +0000
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Jun  5 2014)
+// C++ code generated with wxFormBuilder (version Jan  1 2016)
 // http://www.wxformbuilder.org/
 //
 // PLEASE DO "NOT" EDIT THIS FILE!
@@ -40,7 +40,6 @@
 	fgSizerPadType->Add( m_PadNumText, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );

 	m_PadNumCtrl = new wxTextCtrl( m_panelGeneral, wxID_PADNUMCTRL, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
-	m_PadNumCtrl->SetMaxLength( 0 );
 	fgSizerPadType->Add( m_PadNumCtrl, 0, wxEXPAND|wxLEFT|wxRIGHT|wxTOP, 5 );

 	m_PadNameText = new wxStaticText( m_panelGeneral, wxID_ANY, _("Net name:"), wxDefaultPosition, wxDefaultSize, 0 );
@@ -48,7 +47,6 @@
 	fgSizerPadType->Add( m_PadNameText, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP, 5 );

 	m_PadNetNameCtrl = new wxTextCtrl( m_panelGeneral, wxID_PADNETNAMECTRL, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
-	m_PadNetNameCtrl->SetMaxLength( 0 );
 	fgSizerPadType->Add( m_PadNetNameCtrl, 0, wxEXPAND|wxLEFT|wxRIGHT|wxTOP, 5 );

 	m_staticText44 = new wxStaticText( m_panelGeneral, wxID_ANY, _("Pad type:"), wxDefaultPosition, wxDefaultSize, 0 );
@@ -65,7 +63,7 @@
 	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 );
@@ -85,7 +83,6 @@
 	fgSizerShapeType->Add( m_staticText4, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );

 	m_PadPosition_X_Ctrl = new wxTextCtrl( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
-	m_PadPosition_X_Ctrl->SetMaxLength( 0 );
 	fgSizerShapeType->Add( m_PadPosition_X_Ctrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );

 	m_PadPosX_Unit = new wxStaticText( m_panelGeneral, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
@@ -97,7 +94,6 @@
 	fgSizerShapeType->Add( m_staticText41, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );

 	m_PadPosition_Y_Ctrl = new wxTextCtrl( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
-	m_PadPosition_Y_Ctrl->SetMaxLength( 0 );
 	fgSizerShapeType->Add( m_PadPosition_Y_Ctrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );

 	m_PadPosY_Unit = new wxStaticText( m_panelGeneral, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
@@ -109,7 +105,6 @@
 	fgSizerShapeType->Add( m_staticText12, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );

 	m_ShapeSize_X_Ctrl = new wxTextCtrl( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
-	m_ShapeSize_X_Ctrl->SetMaxLength( 0 );
 	fgSizerShapeType->Add( m_ShapeSize_X_Ctrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );

 	m_PadShapeSizeX_Unit = new wxStaticText( m_panelGeneral, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
@@ -121,7 +116,6 @@
 	fgSizerShapeType->Add( m_staticText15, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );

 	m_ShapeSize_Y_Ctrl = new wxTextCtrl( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
-	m_ShapeSize_Y_Ctrl->SetMaxLength( 0 );
 	fgSizerShapeType->Add( m_ShapeSize_Y_Ctrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );

 	m_PadShapeSizeY_Unit = new wxStaticText( m_panelGeneral, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
@@ -147,7 +141,6 @@
 	fgSizerShapeType->Add( m_PadOrientText, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );

 	m_PadOrientCtrl = new wxTextCtrl( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
-	m_PadOrientCtrl->SetMaxLength( 0 );
 	fgSizerShapeType->Add( m_PadOrientCtrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );

 	m_customOrientUnits = new wxStaticText( m_panelGeneral, wxID_ANY, _("0.1 deg"), wxDefaultPosition, wxDefaultSize, 0 );
@@ -159,7 +152,6 @@
 	fgSizerShapeType->Add( m_staticText17, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );

 	m_ShapeOffset_X_Ctrl = new wxTextCtrl( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
-	m_ShapeOffset_X_Ctrl->SetMaxLength( 0 );
 	fgSizerShapeType->Add( m_ShapeOffset_X_Ctrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );

 	m_PadShapeOffsetX_Unit = new wxStaticText( m_panelGeneral, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
@@ -171,7 +163,6 @@
 	fgSizerShapeType->Add( m_staticText19, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );

 	m_ShapeOffset_Y_Ctrl = new wxTextCtrl( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
-	m_ShapeOffset_Y_Ctrl->SetMaxLength( 0 );
 	fgSizerShapeType->Add( m_ShapeOffset_Y_Ctrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );

 	m_PadShapeOffsetY_Unit = new wxStaticText( m_panelGeneral, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
@@ -185,7 +176,6 @@
 	fgSizerShapeType->Add( m_staticText38, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );

 	m_LengthPadToDieCtrl = new wxTextCtrl( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
-	m_LengthPadToDieCtrl->SetMaxLength( 0 );
 	fgSizerShapeType->Add( m_LengthPadToDieCtrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );

 	m_PadLengthDie_Unit = new wxStaticText( m_panelGeneral, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
@@ -197,7 +187,6 @@
 	fgSizerShapeType->Add( m_staticText21, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT, 5 );

 	m_ShapeDelta_Ctrl = new wxTextCtrl( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
-	m_ShapeDelta_Ctrl->SetMaxLength( 0 );
 	fgSizerShapeType->Add( m_ShapeDelta_Ctrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );

 	m_PadShapeDelta_Unit = new wxStaticText( m_panelGeneral, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
@@ -230,19 +219,19 @@
 	fgSizer4->SetFlexibleDirection( wxBOTH );
 	fgSizer4->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );

-	m_staticTitleModuleRot = new wxStaticText( m_panelGeneral, wxID_ANY, _("Rotation:"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_staticTitleModuleRot = new wxStaticText( sbSizeModuleInfo->GetStaticBox(), wxID_ANY, _("Rotation:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_staticTitleModuleRot->Wrap( -1 );
 	fgSizer4->Add( m_staticTitleModuleRot, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );

-	m_staticModuleRotValue = new wxStaticText( m_panelGeneral, wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_staticModuleRotValue = new wxStaticText( sbSizeModuleInfo->GetStaticBox(), wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_staticModuleRotValue->Wrap( -1 );
 	fgSizer4->Add( m_staticModuleRotValue, 0, wxEXPAND|wxLEFT|wxRIGHT|wxTOP, 5 );

-	m_staticTitleModuleSide = new wxStaticText( m_panelGeneral, wxID_ANY, _("Board side:"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_staticTitleModuleSide = new wxStaticText( sbSizeModuleInfo->GetStaticBox(), wxID_ANY, _("Board side:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_staticTitleModuleSide->Wrap( -1 );
 	fgSizer4->Add( m_staticTitleModuleSide, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxTOP, 5 );

-	m_staticModuleSideValue = new wxStaticText( m_panelGeneral, wxID_ANY, _("Front side"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_staticModuleSideValue = new wxStaticText( sbSizeModuleInfo->GetStaticBox(), wxID_ANY, _("Front side"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_staticModuleSideValue->Wrap( -1 );
 	fgSizer4->Add( m_staticModuleSideValue, 0, wxALL|wxEXPAND, 5 );

@@ -267,41 +256,39 @@
 	fgSizerGeometry->SetFlexibleDirection( wxBOTH );
 	fgSizerGeometry->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );

-	m_staticText47 = new wxStaticText( m_panelGeneral, wxID_ANY, _("Shape:"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_staticText47 = new wxStaticText( sbSizer2->GetStaticBox(), wxID_ANY, _("Shape:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_staticText47->Wrap( -1 );
 	fgSizerGeometry->Add( m_staticText47, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );

 	wxString m_DrillShapeCtrlChoices[] = { _("Circular hole"), _("Oval hole") };
 	int m_DrillShapeCtrlNChoices = sizeof( m_DrillShapeCtrlChoices ) / sizeof( wxString );
-	m_DrillShapeCtrl = new wxChoice( m_panelGeneral, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_DrillShapeCtrlNChoices, m_DrillShapeCtrlChoices, 0 );
+	m_DrillShapeCtrl = new wxChoice( sbSizer2->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_DrillShapeCtrlNChoices, m_DrillShapeCtrlChoices, 0 );
 	m_DrillShapeCtrl->SetSelection( 0 );
 	fgSizerGeometry->Add( m_DrillShapeCtrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );

-	m_staticText51 = new wxStaticText( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
+	m_staticText51 = new wxStaticText( sbSizer2->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
 	m_staticText51->Wrap( -1 );
 	fgSizerGeometry->Add( m_staticText51, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP, 5 );

-	m_textPadDrillX = new wxStaticText( m_panelGeneral, wxID_ANY, _("Size X:"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_textPadDrillX = new wxStaticText( sbSizer2->GetStaticBox(), wxID_ANY, _("Size X:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_textPadDrillX->Wrap( -1 );
 	fgSizerGeometry->Add( m_textPadDrillX, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );

-	m_PadDrill_X_Ctrl = new wxTextCtrl( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
-	m_PadDrill_X_Ctrl->SetMaxLength( 0 );
+	m_PadDrill_X_Ctrl = new wxTextCtrl( sbSizer2->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
 	fgSizerGeometry->Add( m_PadDrill_X_Ctrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );

-	m_PadDrill_X_Unit = new wxStaticText( m_panelGeneral, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_PadDrill_X_Unit = new wxStaticText( sbSizer2->GetStaticBox(), wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_PadDrill_X_Unit->Wrap( -1 );
 	fgSizerGeometry->Add( m_PadDrill_X_Unit, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP, 5 );

-	m_textPadDrillY = new wxStaticText( m_panelGeneral, wxID_ANY, _("Size Y:"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_textPadDrillY = new wxStaticText( sbSizer2->GetStaticBox(), wxID_ANY, _("Size Y:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_textPadDrillY->Wrap( -1 );
 	fgSizerGeometry->Add( m_textPadDrillY, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxTOP, 5 );

-	m_PadDrill_Y_Ctrl = new wxTextCtrl( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
-	m_PadDrill_Y_Ctrl->SetMaxLength( 0 );
+	m_PadDrill_Y_Ctrl = new wxTextCtrl( sbSizer2->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
 	fgSizerGeometry->Add( m_PadDrill_Y_Ctrl, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxTOP, 5 );

-	m_PadDrill_Y_Unit = new wxStaticText( m_panelGeneral, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_PadDrill_Y_Unit = new wxStaticText( sbSizer2->GetStaticBox(), wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_PadDrill_Y_Unit->Wrap( -1 );
 	fgSizerGeometry->Add( m_PadDrill_Y_Unit, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );

@@ -317,13 +304,13 @@
 	wxBoxSizer* bSizer11;
 	bSizer11 = new wxBoxSizer( wxHORIZONTAL );

-	m_staticText511 = new wxStaticText( m_panelGeneral, wxID_ANY, _("Copper:"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_staticText511 = new wxStaticText( m_LayersSizer->GetStaticBox(), wxID_ANY, _("Copper:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_staticText511->Wrap( -1 );
 	bSizer11->Add( m_staticText511, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );

 	wxString m_rbCopperLayersSelChoices[] = { _("Front layer"), _("Back layer"), _("All copper layers"), _("None") };
 	int m_rbCopperLayersSelNChoices = sizeof( m_rbCopperLayersSelChoices ) / sizeof( wxString );
-	m_rbCopperLayersSel = new wxChoice( m_panelGeneral, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_rbCopperLayersSelNChoices, m_rbCopperLayersSelChoices, 0 );
+	m_rbCopperLayersSel = new wxChoice( m_LayersSizer->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_rbCopperLayersSelNChoices, m_rbCopperLayersSelChoices, 0 );
 	m_rbCopperLayersSel->SetSelection( 0 );
 	bSizer11->Add( m_rbCopperLayersSel, 1, wxALL|wxEXPAND, 5 );

@@ -331,39 +318,39 @@
 	m_LayersSizer->Add( bSizer11, 0, wxEXPAND, 5 );

 	wxStaticBoxSizer* sbSizerTechlayers;
-	sbSizerTechlayers = new wxStaticBoxSizer( new wxStaticBox( m_panelGeneral, wxID_ANY, _("Technical Layers") ), wxVERTICAL );
+	sbSizerTechlayers = new wxStaticBoxSizer( new wxStaticBox( m_LayersSizer->GetStaticBox(), wxID_ANY, _("Technical Layers") ), wxVERTICAL );

-	m_PadLayerAdhCmp = new wxCheckBox( m_panelGeneral, wxID_ANY, _("Front adhesive"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_PadLayerAdhCmp = new wxCheckBox( sbSizerTechlayers->GetStaticBox(), wxID_ANY, _("Front adhesive"), wxDefaultPosition, wxDefaultSize, 0 );
 	sbSizerTechlayers->Add( m_PadLayerAdhCmp, 0, wxTOP|wxRIGHT|wxLEFT, 5 );

-	m_PadLayerAdhCu = new wxCheckBox( m_panelGeneral, wxID_ANY, _("Back adhesive"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_PadLayerAdhCu = new wxCheckBox( sbSizerTechlayers->GetStaticBox(), wxID_ANY, _("Back adhesive"), wxDefaultPosition, wxDefaultSize, 0 );
 	sbSizerTechlayers->Add( m_PadLayerAdhCu, 0, wxTOP|wxRIGHT|wxLEFT, 5 );

-	m_PadLayerPateCmp = new wxCheckBox( m_panelGeneral, wxID_ANY, _("Front solder paste"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_PadLayerPateCmp = new wxCheckBox( sbSizerTechlayers->GetStaticBox(), wxID_ANY, _("Front solder paste"), wxDefaultPosition, wxDefaultSize, 0 );
 	sbSizerTechlayers->Add( m_PadLayerPateCmp, 0, wxTOP|wxRIGHT|wxLEFT, 5 );

-	m_PadLayerPateCu = new wxCheckBox( m_panelGeneral, wxID_ANY, _("Back solder paste"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_PadLayerPateCu = new wxCheckBox( sbSizerTechlayers->GetStaticBox(), wxID_ANY, _("Back solder paste"), wxDefaultPosition, wxDefaultSize, 0 );
 	sbSizerTechlayers->Add( m_PadLayerPateCu, 0, wxTOP|wxRIGHT|wxLEFT, 5 );

-	m_PadLayerSilkCmp = new wxCheckBox( m_panelGeneral, wxID_ANY, _("Front silk screen"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_PadLayerSilkCmp = new wxCheckBox( sbSizerTechlayers->GetStaticBox(), wxID_ANY, _("Front silk screen"), wxDefaultPosition, wxDefaultSize, 0 );
 	sbSizerTechlayers->Add( m_PadLayerSilkCmp, 0, wxTOP|wxRIGHT|wxLEFT, 5 );

-	m_PadLayerSilkCu = new wxCheckBox( m_panelGeneral, wxID_ANY, _("Back silk screen"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_PadLayerSilkCu = new wxCheckBox( sbSizerTechlayers->GetStaticBox(), wxID_ANY, _("Back silk screen"), wxDefaultPosition, wxDefaultSize, 0 );
 	sbSizerTechlayers->Add( m_PadLayerSilkCu, 0, wxTOP|wxRIGHT|wxLEFT, 5 );

-	m_PadLayerMaskCmp = new wxCheckBox( m_panelGeneral, wxID_ANY, _("Front solder mask"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_PadLayerMaskCmp = new wxCheckBox( sbSizerTechlayers->GetStaticBox(), wxID_ANY, _("Front solder mask"), wxDefaultPosition, wxDefaultSize, 0 );
 	sbSizerTechlayers->Add( m_PadLayerMaskCmp, 0, wxTOP|wxRIGHT|wxLEFT, 5 );

-	m_PadLayerMaskCu = new wxCheckBox( m_panelGeneral, wxID_ANY, _("Back solder mask"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_PadLayerMaskCu = new wxCheckBox( sbSizerTechlayers->GetStaticBox(), wxID_ANY, _("Back solder mask"), wxDefaultPosition, wxDefaultSize, 0 );
 	sbSizerTechlayers->Add( m_PadLayerMaskCu, 0, wxTOP|wxRIGHT|wxLEFT, 5 );

-	m_PadLayerDraft = new wxCheckBox( m_panelGeneral, wxID_ANY, _("Drafting notes"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_PadLayerDraft = new wxCheckBox( sbSizerTechlayers->GetStaticBox(), wxID_ANY, _("Drafting notes"), wxDefaultPosition, wxDefaultSize, 0 );
 	sbSizerTechlayers->Add( m_PadLayerDraft, 0, wxTOP|wxRIGHT|wxLEFT, 5 );

-	m_PadLayerECO1 = new wxCheckBox( m_panelGeneral, wxID_ANY, _("E.C.O.1"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_PadLayerECO1 = new wxCheckBox( sbSizerTechlayers->GetStaticBox(), wxID_ANY, _("E.C.O.1"), wxDefaultPosition, wxDefaultSize, 0 );
 	sbSizerTechlayers->Add( m_PadLayerECO1, 0, wxTOP|wxRIGHT|wxLEFT, 5 );

-	m_PadLayerECO2 = new wxCheckBox( m_panelGeneral, wxID_ANY, _("E.C.O.2"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_PadLayerECO2 = new wxCheckBox( sbSizerTechlayers->GetStaticBox(), wxID_ANY, _("E.C.O.2"), wxDefaultPosition, wxDefaultSize, 0 );
 	sbSizerTechlayers->Add( m_PadLayerECO2, 0, wxALL, 5 );


@@ -396,59 +383,55 @@
 	fgClearancesGridSizer->SetFlexibleDirection( wxBOTH );
 	fgClearancesGridSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );

-	m_staticTextNetClearance = new wxStaticText( m_localSettingsPanel, wxID_ANY, _("Net pad clearance:"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_staticTextNetClearance = new wxStaticText( sbClearancesSizer->GetStaticBox(), wxID_ANY, _("Net pad clearance:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_staticTextNetClearance->Wrap( -1 );
 	m_staticTextNetClearance->SetToolTip( _("This is the local net clearance for  pad.\nIf 0, the footprint local value or the Netclass value is used") );

 	fgClearancesGridSizer->Add( m_staticTextNetClearance, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );

-	m_NetClearanceValueCtrl = new wxTextCtrl( m_localSettingsPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
-	m_NetClearanceValueCtrl->SetMaxLength( 0 );
+	m_NetClearanceValueCtrl = new wxTextCtrl( sbClearancesSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
 	fgClearancesGridSizer->Add( m_NetClearanceValueCtrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );

-	m_NetClearanceUnits = new wxStaticText( m_localSettingsPanel, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_NetClearanceUnits = new wxStaticText( sbClearancesSizer->GetStaticBox(), wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_NetClearanceUnits->Wrap( -1 );
 	fgClearancesGridSizer->Add( m_NetClearanceUnits, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP, 5 );

-	m_MaskClearanceTitle = new wxStaticText( m_localSettingsPanel, wxID_ANY, _("Solder mask clearance:"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_MaskClearanceTitle = new wxStaticText( sbClearancesSizer->GetStaticBox(), wxID_ANY, _("Solder mask clearance:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_MaskClearanceTitle->Wrap( -1 );
 	m_MaskClearanceTitle->SetToolTip( _("This is the local clearance between this  pad and the solder mask\nIf 0, the footprint local value or the global value is used") );

 	fgClearancesGridSizer->Add( m_MaskClearanceTitle, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );

-	m_SolderMaskMarginCtrl = new wxTextCtrl( m_localSettingsPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
-	m_SolderMaskMarginCtrl->SetMaxLength( 0 );
+	m_SolderMaskMarginCtrl = new wxTextCtrl( sbClearancesSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
 	fgClearancesGridSizer->Add( m_SolderMaskMarginCtrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );

-	m_SolderMaskMarginUnits = new wxStaticText( m_localSettingsPanel, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_SolderMaskMarginUnits = new wxStaticText( sbClearancesSizer->GetStaticBox(), wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_SolderMaskMarginUnits->Wrap( -1 );
 	fgClearancesGridSizer->Add( m_SolderMaskMarginUnits, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP, 5 );

-	m_staticTextSolderPaste = new wxStaticText( m_localSettingsPanel, wxID_ANY, _("Solder paste clearance:"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_staticTextSolderPaste = new wxStaticText( sbClearancesSizer->GetStaticBox(), wxID_ANY, _("Solder paste clearance:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_staticTextSolderPaste->Wrap( -1 );
 	m_staticTextSolderPaste->SetToolTip( _("This is the local clearance between this pad and the solder paste.\nIf 0 the footprint value or the global value is used..\nThe final clearance value is the sum of this value and the clearance value ratio\nA negative value means a smaller mask size than pad size") );

 	fgClearancesGridSizer->Add( m_staticTextSolderPaste, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );

-	m_SolderPasteMarginCtrl = new wxTextCtrl( m_localSettingsPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
-	m_SolderPasteMarginCtrl->SetMaxLength( 0 );
+	m_SolderPasteMarginCtrl = new wxTextCtrl( sbClearancesSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
 	fgClearancesGridSizer->Add( m_SolderPasteMarginCtrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );

-	m_SolderPasteMarginUnits = new wxStaticText( m_localSettingsPanel, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_SolderPasteMarginUnits = new wxStaticText( sbClearancesSizer->GetStaticBox(), wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_SolderPasteMarginUnits->Wrap( -1 );
 	fgClearancesGridSizer->Add( m_SolderPasteMarginUnits, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP, 5 );

-	m_staticTextRatio = new wxStaticText( m_localSettingsPanel, wxID_ANY, _("Solder paste ratio clearance:"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_staticTextRatio = new wxStaticText( sbClearancesSizer->GetStaticBox(), wxID_ANY, _("Solder paste ratio clearance:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_staticTextRatio->Wrap( -1 );
 	m_staticTextRatio->SetToolTip( _("This is the local clearance ratio in per cent between this pad and the solder paste.\nA value of 10 means the clearance value is 10 per cent of the pad size\nIf 0 the footprint value or the global value is used..\nThe final clearance value is the sum of this value and the clearance value\nA negative value means a smaller mask size than pad size.") );

 	fgClearancesGridSizer->Add( m_staticTextRatio, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxTOP, 5 );

-	m_SolderPasteMarginRatioCtrl = new wxTextCtrl( m_localSettingsPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
-	m_SolderPasteMarginRatioCtrl->SetMaxLength( 0 );
+	m_SolderPasteMarginRatioCtrl = new wxTextCtrl( sbClearancesSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
 	fgClearancesGridSizer->Add( m_SolderPasteMarginRatioCtrl, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxTOP, 5 );

-	m_SolderPasteRatioMarginUnits = new wxStaticText( m_localSettingsPanel, wxID_ANY, _("%"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_SolderPasteRatioMarginUnits = new wxStaticText( sbClearancesSizer->GetStaticBox(), wxID_ANY, _("%"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_SolderPasteRatioMarginUnits->Wrap( -1 );
 	fgClearancesGridSizer->Add( m_SolderPasteRatioMarginUnits, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );

@@ -467,41 +450,39 @@
 	fgSizer41->SetFlexibleDirection( wxBOTH );
 	fgSizer41->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );

-	m_staticText40 = new wxStaticText( m_localSettingsPanel, wxID_ANY, _("Pad connection:"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_staticText40 = new wxStaticText( sbSizerZonesSettings->GetStaticBox(), wxID_ANY, _("Pad connection:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_staticText40->Wrap( -1 );
 	fgSizer41->Add( m_staticText40, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );

 	wxString m_ZoneConnectionChoiceChoices[] = { _("From parent footprint"), _("Solid"), _("Thermal relief"), _("None") };
 	int m_ZoneConnectionChoiceNChoices = sizeof( m_ZoneConnectionChoiceChoices ) / sizeof( wxString );
-	m_ZoneConnectionChoice = new wxChoice( m_localSettingsPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_ZoneConnectionChoiceNChoices, m_ZoneConnectionChoiceChoices, 0 );
+	m_ZoneConnectionChoice = new wxChoice( sbSizerZonesSettings->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_ZoneConnectionChoiceNChoices, m_ZoneConnectionChoiceChoices, 0 );
 	m_ZoneConnectionChoice->SetSelection( 0 );
 	fgSizer41->Add( m_ZoneConnectionChoice, 0, wxLEFT|wxTOP|wxEXPAND, 5 );

-	m_staticText53 = new wxStaticText( m_localSettingsPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
+	m_staticText53 = new wxStaticText( sbSizerZonesSettings->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
 	m_staticText53->Wrap( -1 );
 	fgSizer41->Add( m_staticText53, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP, 5 );

-	m_staticText49 = new wxStaticText( m_localSettingsPanel, wxID_ANY, _("Thermal relief width:"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_staticText49 = new wxStaticText( sbSizerZonesSettings->GetStaticBox(), wxID_ANY, _("Thermal relief width:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_staticText49->Wrap( -1 );
 	fgSizer41->Add( m_staticText49, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );

-	m_ThermalWidthCtrl = new wxTextCtrl( m_localSettingsPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
-	m_ThermalWidthCtrl->SetMaxLength( 0 );
+	m_ThermalWidthCtrl = new wxTextCtrl( sbSizerZonesSettings->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
 	fgSizer41->Add( m_ThermalWidthCtrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );

-	m_ThermalWidthUnits = new wxStaticText( m_localSettingsPanel, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_ThermalWidthUnits = new wxStaticText( sbSizerZonesSettings->GetStaticBox(), wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_ThermalWidthUnits->Wrap( -1 );
 	fgSizer41->Add( m_ThermalWidthUnits, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP, 5 );

-	m_staticText52 = new wxStaticText( m_localSettingsPanel, wxID_ANY, _("Thermal relief gap:"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_staticText52 = new wxStaticText( sbSizerZonesSettings->GetStaticBox(), wxID_ANY, _("Thermal relief gap:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_staticText52->Wrap( -1 );
 	fgSizer41->Add( m_staticText52, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxTOP, 5 );

-	m_ThermalGapCtrl = new wxTextCtrl( m_localSettingsPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
-	m_ThermalGapCtrl->SetMaxLength( 0 );
+	m_ThermalGapCtrl = new wxTextCtrl( sbSizerZonesSettings->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
 	fgSizer41->Add( m_ThermalGapCtrl, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxTOP, 5 );

-	m_ThermalGapUnits = new wxStaticText( m_localSettingsPanel, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_ThermalGapUnits = new wxStaticText( sbSizerZonesSettings->GetStaticBox(), wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_ThermalGapUnits->Wrap( -1 );
 	fgSizer41->Add( m_ThermalGapUnits, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );


=== modifié fichier pcbnew/dialogs/dialog_pad_properties_base.fbp
--- pcbnew/dialogs/dialog_pad_properties_base.fbp	2015-09-11 23:13:54 +0000
+++ pcbnew/dialogs/dialog_pad_properties_base.fbp	2016-01-12 13:19:27 +0000
@@ -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>

=== modifié fichier pcbnew/dialogs/dialog_pad_properties_base.h
--- pcbnew/dialogs/dialog_pad_properties_base.h	2015-09-11 23:13:54 +0000
+++ pcbnew/dialogs/dialog_pad_properties_base.h	2016-01-12 13:35:15 +0000
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Jun  5 2014)
+// C++ code generated with wxFormBuilder (version Jan  1 2016)
 // http://www.wxformbuilder.org/
 //
 // PLEASE DO "NOT" EDIT THIS FILE!

=== modifié fichier pcbnew/drc_clearance_test_functions.cpp
--- pcbnew/drc_clearance_test_functions.cpp	2016-01-09 21:07:52 +0000
+++ pcbnew/drc_clearance_test_functions.cpp	2016-01-20 16:37:18 +0000
@@ -45,41 +45,37 @@
 #include <class_marker_pcb.h>
 #include <math_for_graphics.h>
 #include <polygon_test_point_inside.h>
-
-
-/* compare 2 trapezoids (can be rectangle) and return true if distance > aDist
+#include <convert_basic_shapes_to_polygon.h>
+
+
+/* compare 2 convex polygons and return true if distance > aDist
  * i.e if for each edge of the first polygon distance from each edge of the other polygon
  * is >= aDist
  */
-bool trapezoid2trapezoidDRC( wxPoint aTref[4], wxPoint aTcompare[4], int aDist )
+bool convex2convexDRC( wxPoint* aTref, int aTrefCount,
+                       wxPoint* aTcompare, int aTcompareCount, int aDist )
 {
     /* Test if one polygon is contained in the other and thus the polygon overlap.
      * This case is not covered by the following check if one polygond is
      * completely contained in the other (because edges don't intersect)!
      */
-    if( TestPointInsidePolygon( aTref, 4, aTcompare[0] ) )
-        return false;
-
-    if( TestPointInsidePolygon( aTcompare, 4, aTref[0] ) )
-        return false;
-
-    int ii, jj, kk, ll;
-
-    for( ii = 0, jj = 3; ii<4; jj = ii, ii++ )          // for all edges in aTref
-    {
-        for( kk = 0, ll = 3; kk < 4; ll = kk, kk++ )    // for all edges in aTcompare
-        {
+    if( TestPointInsidePolygon( aTref, aTrefCount, aTcompare[0] ) )
+        return false;
+
+    if( TestPointInsidePolygon( aTcompare, aTcompareCount, aTref[0] ) )
+        return false;
+
+    for( int ii = 0, jj = aTrefCount - 1; ii < aTrefCount; jj = ii, ii++ )
+    {   // for all edges in aTref
+        for( int kk = 0, ll = aTcompareCount - 1; kk < aTcompareCount; ll = kk, kk++ )
+        {   // for all edges in aTcompare
             double d;
-            int    intersect = TestForIntersectionOfStraightLineSegments( aTref[ii].x,
-                                                                          aTref[ii].y,
-                                                                          aTref[jj].x,
-                                                                          aTref[jj].y,
-                                                                          aTcompare[kk].x,
-                                                                          aTcompare[kk].y,
-                                                                          aTcompare[ll].x,
-                                                                          aTcompare[ll].y,
-                                                                          NULL, NULL, &d );
-            if( intersect || (d< aDist) )
+            int    intersect = TestForIntersectionOfStraightLineSegments(
+                                aTref[ii].x, aTref[ii].y, aTref[jj].x, aTref[jj].y,
+                                aTcompare[kk].x, aTcompare[kk].y, aTcompare[ll].x, aTcompare[ll].y,
+                                NULL, NULL, &d );
+
+            if( intersect || ( d< aDist ) )
                 return false;
         }
     }
@@ -87,7 +83,6 @@
     return true;
 }

-
 /* compare a trapezoids (can be rectangle) and a segment and return true if distance > aDist
  */
 bool trapezoid2segmentDRC( wxPoint aTref[4], wxPoint aSegStart, wxPoint aSegEnd, int aDist )
@@ -99,46 +94,39 @@
     if( TestPointInsidePolygon( aTref, 4, aSegStart ) )
         return false;

-    int ii, jj;
-
-    for( ii = 0, jj = 3; ii < 4; jj = ii, ii++ )  // for all edges in aTref
+    for( int ii = 0, jj = 3; ii < 4; jj = ii, ii++ )  // for all edges in aTref
     {
         double d;
-        int    intersect = TestForIntersectionOfStraightLineSegments( aTref[ii].x,
-                                                                      aTref[ii].y,
-                                                                      aTref[jj].x,
-                                                                      aTref[jj].y,
-                                                                      aSegStart.x,
-                                                                      aSegStart.y,
-                                                                      aSegEnd.x,
-                                                                      aSegEnd.y,
-                                                                      NULL, NULL, &d );
-        if( intersect || (d< aDist) )
+        int    intersect = TestForIntersectionOfStraightLineSegments(
+                                aTref[ii].x, aTref[ii].y, aTref[jj].x, aTref[jj].y,
+                                aSegStart.x, aSegStart.y, aSegEnd.x, aSegEnd.y,
+                                NULL, NULL, &d );
+
+        if( intersect || ( d < aDist) )
             return false;
     }

     return true;
 }

-
-/* compare a trapezoid to a point and return true if distance > aDist
+/* compare a polygon to a point and return true if distance > aDist
  * do not use this function for horizontal or vertical rectangles
  * because there is a faster an easier way to compare the distance
  */
-bool trapezoid2pointDRC( wxPoint aTref[4], wxPoint aPcompare, int aDist )
+bool convex2pointDRC( wxPoint* aTref, int aTrefCount, wxPoint aPcompare, int aDist )
 {
     /* Test if aPcompare point is contained in the polygon.
      * This case is not covered by the following check if this point is inside the polygon
      */
-    if( TestPointInsidePolygon( aTref, 4, aPcompare ) )
+    if( TestPointInsidePolygon( aTref, aTrefCount, aPcompare ) )
     {
         return false;
     }

     // Test distance between aPcompare and each segment of the polygon:
-    for( int ii = 0, jj = 3; ii < 4; jj = ii, ii++ )  // for all edge in polygon
+    for( int ii = 0, jj = aTrefCount - 1; ii < aTrefCount; jj = ii, ii++ )  // for all edge in polygon
     {
-        if( TestSegmentHit( aTref[ii], aTref[jj], aPcompare, aDist ) )
+        if( TestSegmentHit( aPcompare, aTref[ii], aTref[jj], aDist ) )
             return false;
     }

@@ -577,12 +565,13 @@


 /* test DRC between 2 pads.
- * this function can be also used to test DRC between a pas and a hole,
- * because a hole is like a round pad.
+ * this function can be also used to test DRC between a pad and a hole,
+ * because a hole is like a round or oval pad.
  */
 bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
 {
     int     dist;
+    double pad_angle;

     // Get the clearance between the 2 pads. this is the min distance between aRefPad and aPad
     int     dist_min = aRefPad->GetClearance( aPad );
@@ -607,10 +596,12 @@
     swap_pads = false;

     // swap pads to make comparisons easier
-    // priority is aRefPad = ROUND then OVAL then RECT then other
+    // Note also a ROUNDRECT pad with a corner radius = r can be considered as
+    // a smaller RECT (size - 2*r) with a clearance increased by r
+    // priority is aRefPad = ROUND then OVAL then RECT/ROUNDRECT then other
     if( aRefPad->GetShape() != aPad->GetShape() && aRefPad->GetShape() != PAD_SHAPE_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_SHAPE_CIRCLE:
@@ -622,6 +613,7 @@
                 break;

             case PAD_SHAPE_RECT:
+            case PAD_SHAPE_ROUNDRECT:
                 if( aRefPad->GetShape() != PAD_SHAPE_OVAL )
                     swap_pads = true;
                 break;
@@ -637,10 +629,15 @@
         relativePadPos = -relativePadPos;
     }

+    // corners of aRefPad (used only for rect/roundrect/trap pad)
+    wxPoint polyref[4];
+    // corners of aPad (used only for rect/roundrect/trap pad)
+    wxPoint polycompare[4];
+
     /* Because pad exchange, aRefPad shape is PAD_SHAPE_CIRCLE or PAD_SHAPE_OVAL,
      * if one of the 2 pads was a PAD_SHAPE_CIRCLE or PAD_SHAPE_OVAL.
-     * Therefore, if aRefPad is a PAD_SHAPE_SHAPE_RECT or a PAD_SHAPE_TRAPEZOID,
-     * aPad is also a PAD_SHAPE_RECT or a PAD_SHAPE_TRAPEZOID
+     * Therefore, if aRefPad is a PAD_SHAPE_RECT, PAD_SHAPE_ROUNDRECT or a PAD_SHAPE_TRAPEZOID,
+     * aPad is also a PAD_SHAPE_RECT, PAD_SHAPE_ROUNDRECT or a PAD_SHAPE_TRAPEZOID
      */
     bool diag = true;

@@ -660,6 +657,55 @@
         diag = checkClearanceSegmToPad( aPad, aRefPad->GetSize().x, dist_min );
         break;

+    case PAD_SHAPE_TRAPEZOID:
+    case PAD_SHAPE_ROUNDRECT:
+    case PAD_SHAPE_RECT:
+        // pad_angle = pad orient relative to the aRefPad orient
+        pad_angle = aRefPad->GetOrientation() + aPad->GetOrientation();
+        NORMALIZE_ANGLE_POS( pad_angle );
+
+        if( aRefPad->GetShape() == PAD_SHAPE_ROUNDRECT )
+        {
+            int padRadius = aRefPad->GetRoundRectCornerRadius();
+            dist_min += padRadius;
+            GetRoundRectCornerCenters( polyref, padRadius, wxPoint( 0, 0 ),
+                                aRefPad->GetSize(), aRefPad->GetOrientation() );
+        }
+        else
+            aRefPad->BuildPadPolygon( polyref, wxSize( 0, 0 ), aRefPad->GetOrientation() );
+
+        switch( aPad->GetShape() )
+        {
+        case PAD_SHAPE_ROUNDRECT:
+        case PAD_SHAPE_RECT:
+        case PAD_SHAPE_TRAPEZOID:
+            if( aPad->GetShape() == PAD_SHAPE_ROUNDRECT )
+            {
+                int padRadius = aPad->GetRoundRectCornerRadius();
+                dist_min += padRadius;
+                GetRoundRectCornerCenters( polycompare, padRadius, wxPoint( 0, 0 ),
+                                    aPad->GetSize(), aPad->GetOrientation() );
+            }
+            else
+            {
+                aPad->BuildPadPolygon( polycompare, wxSize( 0, 0 ), aPad->GetOrientation() );
+
+                // Move aPad shape to relativePadPos
+                for( int ii = 0; ii < 4; ii++ )
+                    polycompare[ii] += relativePadPos;
+
+                // And now test polygons:
+                if( !convex2convexDRC( polyref, 4, polycompare, 4, dist_min ) )
+                    diag = false;
+            }
+            break;
+
+        default:
+            wxLogDebug( wxT( "DRC::checkClearancePadToPad: unexpected pad shape %d" ), aPad->GetShape() );
+            break;
+        }
+        break;
+
     case PAD_SHAPE_OVAL:     /* an oval pad is like a track segment */
     {
         /* Create a track segment with same dimensions as the oval aRefPad
@@ -702,26 +748,8 @@
         break;
     }

-    case PAD_SHAPE_TRAPEZOID:
-    case PAD_SHAPE_RECT:
-        {
-            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() );
-
-            // Move aPad shape to relativePadPos
-            for( int ii = 0; ii < 4; ii++ )
-                polycompare[ii] += relativePadPos;
-
-            // And now test polygons:
-            if( !trapezoid2trapezoidDRC( polyref, polycompare, dist_min ) )
-                diag = false;
-        }
-        break;
-
     default:
-        wxLogDebug( wxT( "DRC::checkClearancePadToPad: unexpected pad shape" ) );
+        wxLogDebug( wxT( "DRC::checkClearancePadToPad: unknown pad shape" ) );
         break;
     }

@@ -738,6 +766,7 @@
 {
     wxSize  padHalfsize;            // half dimension of the pad
     wxPoint startPoint, endPoint;
+    int     r;

     int segmHalfWidth = aSegmentWidth / 2;
     int distToLine = segmHalfWidth + aMinDist;
@@ -849,6 +878,13 @@
     }
         break;

+    case PAD_SHAPE_ROUNDRECT:
+        // a round rect is a smaller rect, with a clearance augmented by the corners radius
+        r = aPad->GetRoundRectCornerRadius();
+        padHalfsize.x -= r;
+        padHalfsize.y -= r;
+        distToLine += r;
+        // Fall through
     case PAD_SHAPE_RECT:
         // the area to test is a rounded rectangle.
         // this can be done by testing 2 rectangles and 4 circles (the corners)

=== modifié fichier pcbnew/exporters/gen_modules_placefile.cpp
--- pcbnew/exporters/gen_modules_placefile.cpp	2015-11-17 16:18:00 +0000
+++ pcbnew/exporters/gen_modules_placefile.cpp	2016-01-12 13:19:27 +0000
@@ -723,7 +723,7 @@
                          (pad->GetOrientation() - Module->GetOrientation()) / 10.0 );
                 fputs( line, rptfile );

-                static const char* shape_name[6] = { "???", "Circ", "Rect", "Oval", "Trap", "Spec" };
+                static const char* shape_name[6] = { "Circ", "Rect", "Oval", "Trap", "Rrec", "Spec" };

                 sprintf( line, "Shape  %s\n", shape_name[pad->GetShape()] );
                 fputs( line, rptfile );

=== modifié fichier pcbnew/kicad_plugin.cpp
--- pcbnew/kicad_plugin.cpp	2016-01-17 17:31:00 +0000
+++ pcbnew/kicad_plugin.cpp	2016-01-18 08:31:58 +0000
@@ -1229,6 +1229,7 @@
     case PAD_SHAPE_RECT:      shape = "rect";         break;
     case PAD_SHAPE_OVAL:      shape = "oval";         break;
     case PAD_SHAPE_TRAPEZOID: shape = "trapezoid";    break;
+    case PAD_SHAPE_ROUNDRECT: shape = "roundrect";    break;

     default:
         THROW_IO_ERROR( wxString::Format( _( "unknown pad type: %d"), aPad->GetShape() ) );

=== modifié fichier pcbnew/pcb_painter.cpp
--- pcbnew/pcb_painter.cpp	2016-01-20 14:19:26 +0000
+++ pcbnew/pcb_painter.cpp	2016-01-20 17:12:09 +0000
@@ -38,6 +38,7 @@

 #include <pcb_painter.h>
 #include <gal/graphics_abstraction_layer.h>
+#include <convert_basic_shapes_to_polygon.h>

 using namespace KIGFX;

@@ -653,6 +654,37 @@
         m_gal->DrawRectangle( VECTOR2D( -size.x, -size.y ), VECTOR2D( size.x, size.y ) );
         break;

+    case PAD_SHAPE_ROUNDRECT:
+    {
+        std::deque<VECTOR2D> pointList;
+
+        // Use solder[Paste/Mask]size or pad size to build pad shape
+        SHAPE_POLY_SET outline;
+        wxSize prsize( size.x*2, size.y*2 );
+        const int segmentToCircleCount = 64;
+        int corner_radius = aPad->GetRoundRectCornerRadius( prsize );
+        TransformRoundRectToPolygon( outline, wxPoint( 0, 0 ), prsize,
+                                    0.0 , corner_radius, segmentToCircleCount );
+
+        // Draw the polygon: Inflate creates only one convex polygon
+        SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
+
+        for( int ii = 0; ii < poly.PointCount(); ii++ )
+            pointList.push_back( poly.Point( ii ) );
+
+        if( m_pcbSettings.m_sketchMode[PADS_VISIBLE] )
+        {
+            // Add the beginning point to close the outline
+            pointList.push_back( pointList.front() );
+            m_gal->DrawPolyline( pointList );
+        }
+        else
+        {
+            m_gal->DrawPolygon( pointList );
+        }
+        break;
+    }
+
     case PAD_SHAPE_TRAPEZOID:
     {
         std::deque<VECTOR2D> pointList;

=== modifié fichier pcbnew/pcb_parser.cpp
--- pcbnew/pcb_parser.cpp	2015-11-17 16:18:00 +0000
+++ pcbnew/pcb_parser.cpp	2016-01-12 13:19:27 +0000
@@ -2197,8 +2197,12 @@
         pad->SetShape( PAD_SHAPE_TRAPEZOID );
         break;

+    case T_roundrect:
+        pad->SetShape( PAD_SHAPE_ROUNDRECT );
+        break;
+
     default:
-        Expecting( "circle, rectangle, oval, or trapezoid" );
+        Expecting( "circle, rectangle, roundrect, oval, or trapezoid" );
     }

     for( token = NextTok();  token != T_RIGHT;  token = NextTok() )

=== modifié fichier pcbnew/plot_board_layers.cpp
--- pcbnew/plot_board_layers.cpp	2015-12-15 20:21:25 +0000
+++ pcbnew/plot_board_layers.cpp	2016-01-12 13:19:27 +0000
@@ -380,6 +380,7 @@
                 // Fall through:
             case PAD_SHAPE_TRAPEZOID:
             case PAD_SHAPE_RECT:
+            case PAD_SHAPE_ROUNDRECT:
             default:
                 itemplotter.PlotPad( pad, color, plotMode );
                 break;

=== modifié fichier pcbnew/plot_brditems_plotter.cpp
--- pcbnew/plot_brditems_plotter.cpp	2015-08-23 19:40:33 +0000
+++ pcbnew/plot_brditems_plotter.cpp	2016-01-14 16:01:51 +0000
@@ -91,6 +91,11 @@
         }
         break;

+    case PAD_SHAPE_ROUNDRECT:
+            m_plotter->FlashPadRoundRect( shape_pos, aPad->GetSize(), aPad->GetRoundRectCornerRadius(),
+                                          aPad->GetOrientation(), aPlotMode );
+        break;
+
     case PAD_SHAPE_RECT:
     default:
         m_plotter->FlashPadRect( shape_pos, aPad->GetSize(),

=== modifié fichier pcbnew/router/pns_router.cpp
--- pcbnew/router/pns_router.cpp	2015-11-18 14:35:17 +0000
+++ pcbnew/router/pns_router.cpp	2016-01-20 17:45:38 +0000
@@ -267,6 +267,31 @@
                 break;
             }

+            case PAD_SHAPE_ROUNDRECT:
+            {
+                SHAPE_POLY_SET outline;
+                const int segmentToCircleCount = 64;
+                // FIXME: Perhaps not optimal because we are using a polygonal
+                // shape with segmentToCircleCount+4 corners,
+                // but perhaps using 2 rect and 4 circles could be better
+                // (better shape, although for more than 32 segm per circle
+                // the shape is good) and faster
+                aPad->BuildPadShapePolygon( outline, wxSize( 0, 0 ),
+                                            segmentToCircleCount, 1.0 );
+
+                // TransformRoundRectToPolygon creates only one convex polygon
+                SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
+                SHAPE_CONVEX* shape = new SHAPE_CONVEX();
+
+                for( int ii = 0; ii < poly.PointCount(); ++ii )
+                {
+                    shape->Append( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) );
+                }
+
+                solid->SetShape( shape );
+            }
+                break;
+
             default:
                 TRACEn( 0, "unsupported pad shape" );
                 delete solid;
@@ -344,6 +369,26 @@
                 break;
             }

+            case PAD_SHAPE_ROUNDRECT:
+            {
+                SHAPE_POLY_SET outline;
+                const int segmentToCircleCount = 32;
+                aPad->BuildPadShapePolygon( outline, wxSize( 0, 0 ),
+                                            segmentToCircleCount, 1.0 );
+
+                // TransformRoundRectToPolygon creates only one convex polygon
+                SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
+                SHAPE_CONVEX* shape = new SHAPE_CONVEX();
+
+                for( int ii = 0; ii < poly.PointCount(); ++ii )
+                {
+                    shape->Append( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) );
+                }
+
+                solid->SetShape( shape );
+            }
+                break;
+
             default:
                 TRACEn( 0, "unsupported pad shape" );
                 delete solid;


Follow ups

References