← Back to team overview

kicad-developers team mailing list archive

Re: [PATCH] V4 Rectangular pads with rounded corners

 

Any chance you can attach this a patch file?

On Sun, Mar 1, 2015 at 5:51 PM, Mathias Grimmberger <mgri@xxxxxxxxxxxxx>
wrote:

>
> Hi everybody,
>
> below is the fourth version of a patch to add support for rectangular
> pads with rounded corners to KiCad. The patch was generated against
> revision 5464.
>
>
> What is new:
>
> - export to VRML works,
>
> - export to Specctra DSN works, at least Freeroute reads and displays
> it,
>
> - pad to pad DRC is implemented with proper PAD_ROUNDRECT support, at
> least I think I got it right,
>
> - in the process I fixed what I think was a bug in trapezoid2pointDRC(),
>
> - I changed the way generating the module report works to how I believe
> it is supposed to work.
>
>
> What is still to do:
>
> - GenCAD export, I do not understand what this is used for and couldn't
> find a viewer that would show something I could recognize, so
> PAD_ROUNDRECT is still handled the same way as PAD_TRAPEZOID,
>
> - proper support in the PNS router, without a SHAPE_CONVEX nothing can
> be done about that (I might look into that).
>
>
> This will be the last version of this patch for now, unless somebody
> points out a bug or some missing piece.
>
> IMHO this is now usable, so if you want it in KiCad... ;-)
>
>
> Enjoy,
>
> MGri
>
>
>
> === modified file 'common/common_plotDXF_functions.cpp'
> --- common/common_plotDXF_functions.cpp 2015-02-26 10:33:15 +0000
> +++ common/common_plotDXF_functions.cpp 2015-03-01 22:25:20 +0000
> @@ -623,6 +623,12 @@
>      FinishTo( wxPoint( ox, oy ) );
>  }
>
> +void DXF_PLOTTER::FlashPadRoundRect( const wxPoint& pos, const wxPoint
> corners[12],
> +                                     int cornerRadius, double orient,
> +                                     EDA_DRAW_MODE_T trace_mode )
> +{
> +    // Not actually needed, because for DXF copper is plotted entirely as
> polygons
> +}
>
>  /**
>   * DXF trapezoidal pad: only sketch mode is supported
>
> === modified file 'common/common_plotGERBER_functions.cpp'
> --- common/common_plotGERBER_functions.cpp      2015-02-18 19:27:00 +0000
> +++ common/common_plotGERBER_functions.cpp      2015-03-01 22:25:20 +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-26 10:33:15 +0000
> +++ common/common_plotHPGL_functions.cpp        2015-03-01 22:25:20 +0000
> @@ -251,14 +251,21 @@
>
>
>  /**
> - * HPGL rectangle: fill not supported
> + * HPGL rectangle
>   */
>  void HPGL_PLOTTER::Rect( const wxPoint& p1, const wxPoint& p2, FILL_T
> fill, int width )
>  {
>      wxASSERT( outputFile );
>      DPOINT p2dev = userToDeviceCoordinates( p2 );
>      MoveTo( p1 );
> -    fprintf( outputFile, "EA %.0f,%.0f;\n", p2dev.x, p2dev.y );
> +    if( fill == NO_FILL )
> +    {
> +       fprintf( outputFile, "EA %.0f,%.0f;\n", p2dev.x, p2dev.y );
> +    }
> +    else
> +    {
> +       fprintf( outputFile, "RA %.0f,%.0f;\n", p2dev.x, p2dev.y );
> +    }
>      PenFinish();
>  }
>
> @@ -631,6 +638,115 @@
>      }
>  }
>
> +void HPGL_PLOTTER::FlashPadRoundRect( const wxPoint& pos, const wxPoint
> corners[12],
> +                                      int cornerRadius, double orient,
> +                                      EDA_DRAW_MODE_T trace_mode )
> +{
> +    std::vector< wxPoint > cornerList;
> +
> +    wxASSERT( outputFile );
> +
> +    for( int ii = 0; ii < 12; ii++ )
> +        cornerList.push_back( corners[ii] );
> +
> +    int w = KiROUND( penDiameter );
> +    int hw = w / 2;
> +
> +    if( trace_mode != FILLED )
> +    {
> +        cornerList[0].x += hw;
> +        cornerList[0].y -= hw;
> +        cornerList[1].x += hw;
> +        cornerList[1].y -= hw;
> +        cornerList[2].x -= hw;
> +        cornerList[2].y -= hw;
> +        cornerList[3].x -= hw;
> +        cornerList[3].y -= hw;
> +        cornerList[4].x -= hw;
> +        cornerList[4].y -= hw;
> +        cornerList[5].x -= hw;
> +        cornerList[5].y += hw;
> +        cornerList[6].x -= hw;
> +        cornerList[6].y += hw;
> +        cornerList[7].x -= hw;
> +        cornerList[7].y += hw;
> +        cornerList[8].x += hw;
> +        cornerList[8].y += hw;
> +        cornerList[9].x += hw;
> +        cornerList[9].y += hw;
> +        cornerList[10].x += hw;
> +        cornerList[10].y += hw;
> +        cornerList[11].x += hw;
> +        cornerList[11].y -= hw;
> +    }
> +
> +    for( unsigned ii = 0; ii < cornerList.size(); ii++ )
> +    {
> +        RotatePoint( &cornerList[ii], orient );
> +        cornerList[ii] += pos;
> +    }
> +
> +    if( trace_mode == FILLED )
> +    {
> +        wxPoint cpos;
> +
> +        if( orient == 0 || orient == 900 || orient == 1800 || orient ==
> 2700 )
> +        {
> +            Rect( cornerList[10], cornerList[4], FILLED_SHAPE, w );
> +            Rect( cornerList[0], cornerList[2], FILLED_SHAPE, w );
> +            Rect( cornerList[8], cornerList[6], FILLED_SHAPE, w );
> +        }
> +        else
> +        {
> +            // (ab)use FlashPadRect() as a generalized Rect()
> +            wxPoint s( corners[4] - corners[10] );
> +            FlashPadRect( pos, wxSize( s.x, s.y ), orient, FILLED );
> +            // small top reactangle
> +            cpos = wxPoint( 0, corners[1].y - cornerRadius / 2 );
> +            RotatePoint( &cpos, orient );
> +            s = corners[2] - corners[0];
> +            FlashPadRect( pos + cpos, wxSize( s.x, s.y ), orient, FILLED
> );
> +            // small bottom rectangle
> +            cpos = wxPoint( 0, corners[8].y + cornerRadius / 2 );
> +            RotatePoint( &cpos, orient );
> +            s = corners[6] - corners[8];
> +            FlashPadRect( pos + cpos, wxSize( s.x, s.y ), orient, FILLED
> );
> +        }
> +        // (ab)use FlashPadCircle for filled circle
> +        cpos = corners[0];
> +        RotatePoint( &cpos, orient );
> +        FlashPadCircle( pos + cpos, cornerRadius * 2, FILLED );
> +        cpos = corners[3];
> +        RotatePoint( &cpos, orient );
> +        FlashPadCircle( pos + cpos, cornerRadius * 2, FILLED );
> +        cpos = corners[6];
> +        RotatePoint( &cpos, orient );
> +        FlashPadCircle( pos + cpos, cornerRadius * 2, FILLED );
> +        cpos = corners[9];
> +        RotatePoint( &cpos, orient );
> +        FlashPadCircle( pos + cpos, cornerRadius * 2, FILLED );
> +    }
> +    else
> +    {
> +        MoveTo( cornerList[1] );
> +        LineTo( cornerList[2] );
> +        MoveTo( cornerList[4] );
> +        LineTo( cornerList[5] );
> +        MoveTo( cornerList[7] );
> +        LineTo( cornerList[8] );
> +        MoveTo( cornerList[10] );
> +        FinishTo( cornerList[11] );
> +
> +        Arc(cornerList[0], orient + 1800, orient + 2700, cornerRadius,
> +            NO_FILL, w );
> +        Arc(cornerList[3], orient + 2700, orient + 3600, cornerRadius,
> +            NO_FILL, w );
> +        Arc(cornerList[6], orient, orient + 900, cornerRadius,
> +            NO_FILL, w );
> +        Arc(cornerList[9], orient + 900, orient + 1800, cornerRadius,
> +            NO_FILL, w );
> +    }
> +}
>
>  void HPGL_PLOTTER::FlashPadTrapez( const wxPoint& aPadPos, const wxPoint*
> aCorners,
>                                     double aPadOrient, EDA_DRAW_MODE_T
> aTrace_Mode )
>
> === modified file 'common/common_plotPS_functions.cpp'
> --- common/common_plotPS_functions.cpp  2014-10-19 20:20:16 +0000
> +++ common/common_plotPS_functions.cpp  2015-03-01 22:25:20 +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-03-01 22:25:20 +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-03-01 22:25:20 +0000
> @@ -15,7 +15,8 @@
>      PAD_ROUND = PAD_CIRCLE,
>      PAD_RECT,
>      PAD_OVAL,
> -    PAD_TRAPEZOID
> +    PAD_TRAPEZOID,
> +    PAD_ROUNDRECT
>  };
>
>  /**
>
> === modified file 'include/plot_common.h'
> --- include/plot_common.h       2015-02-26 10:33:15 +0000
> +++ include/plot_common.h       2015-03-01 22:25:20 +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 );
>
> @@ -921,6 +939,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
>       */
> @@ -1049,6 +1074,9 @@
>                                 EDA_DRAW_MODE_T trace_mode );
>      virtual void FlashPadRect( const wxPoint& pos, const wxSize& size,
>                                 double orient, EDA_DRAW_MODE_T trace_mode
> );
> +    virtual void FlashPadRoundRect( const wxPoint& pos, const wxPoint
> corners[12],
> +                                    int cornerRadius, double orient,
> +                                    EDA_DRAW_MODE_T trace_mode );
>      virtual void FlashPadTrapez( const wxPoint& aPadPos, const wxPoint
> *aCorners,
>                                   double aPadOrient, EDA_DRAW_MODE_T
> aTrace_Mode );
>
>
> === modified file 'pcbnew/board_items_to_polygon_shape_transform.cpp'
> --- pcbnew/board_items_to_polygon_shape_transform.cpp   2015-02-18
> 19:27:00 +0000
> +++ pcbnew/board_items_to_polygon_shape_transform.cpp   2015-03-01
> 22:25:20 +0000
> @@ -605,6 +605,44 @@
>          aCornerBuffer.ImportFrom( shapeWithClearance );
>      }
>          break;
> +
> +    case PAD_ROUNDRECT:
> +    {
> +        wxPoint corners[12];
> +        int r = BuildPadPolygonRoundRect( corners, wxSize( 0, 0 ), angle
> );
> +
> +        // We are using ClipperLib to inflate the polygon shape, using
> +        // arcs to connect moved segments.
> +        ClipperLib::Path outline;
> +        ClipperLib::Paths shapeWithClearance;
> +
> +        for( int ii = 0; ii < 12; ii += 3 )
> +        {
> +            corners[ii] += PadShapePos;
> +            outline << ClipperLib::IntPoint( corners[ii].x, corners[ii].y
> );
> +        }
> +
> +        ClipperLib::ClipperOffset offset_engine;
> +        // Prepare an offset (inflate) transform, with edges connected by
> arcs
> +        offset_engine.AddPath( outline, ClipperLib::jtRound,
> ClipperLib::etClosedPolygon );
> +
> +        // Clipper approximates arcs by segments
> +        // It uses a value called ArcTolerance which is the max error
> between the arc
> +        // and segments created to approximate this arc
> +        // the number of segm per circle is:
> +        // n = PI / acos(1 - arc_tolerance / (arc radius))
> +        // the arc radius is aClearanceValue
> +        // because arc_tolerance is << aClearanceValue and
> aClearanceValue >= 0
> +        // n = PI / (arc_tolerance / aClearanceValue )
> +        offset_engine.ArcTolerance = ((double)aClearanceValue + r) / 3.14
> / aCircleToSegmentsCount;
> +
> +        double rounding_radius = (aClearanceValue + r) *
> aCorrectionFactor;
> +        offset_engine.Execute( shapeWithClearance, rounding_radius );
> +
> +        // get new outline (only one polygon is expected)
> +        aCornerBuffer.ImportFrom( shapeWithClearance );
> +    }
> +        break;
>      }
>  }
>
> @@ -626,6 +664,7 @@
>      {
>      case PAD_CIRCLE:
>      case PAD_OVAL:
> +    case PAD_ROUNDRECT:
>          TransformShapeWithClearanceToPolygon( aCornerBuffer,
> aInflateValue.x,
>                                                aSegmentsPerCircle,
> aCorrectionFactor );
>          break;
> @@ -1052,6 +1091,79 @@
>          }
>          break;
>
> +    case PAD_ROUNDRECT:
> +        {
> +            std::vector <wxPoint> corners_buffer;          // Polygon
> buffer as vector
> +
> +            int dx = (aPad.GetSize().x / 2) + aThermalGap;
> +            int dy = (aPad.GetSize().y / 2) + aThermalGap;
> +
> +            // The first point of polygon buffer is left lower corner,
> second the crosspoint of
> +            // thermal spoke sides, the third is upper right corner and
> the rest are rounding
> +            // vertices going anticlockwise. Note the inveted Y-axis in
> CG.
> +            corners_buffer.push_back( wxPoint( -dx, -(aThermalGap / 4 +
> copper_thickness.y / 2) ) );    // Adds small miters to zone
> +            corners_buffer.push_back( wxPoint( -(dx - aThermalGap / 4),
> -copper_thickness.y / 2 ) );    // fill and spoke corner
> +            corners_buffer.push_back( wxPoint( -copper_thickness.x / 2,
> -copper_thickness.y / 2 ) );
> +            corners_buffer.push_back( wxPoint( -copper_thickness.x / 2,
> -(dy - aThermalGap / 4) ) );
> +            corners_buffer.push_back( wxPoint( -(aThermalGap / 4 +
> copper_thickness.x / 2), -dy ) );
> +
> +            int r = aPad.GetRoundRectCornerRadius();
> +            // the center around which the round part of the thermal gap
> is drawn
> +            wxPoint center = wxPoint( -(aPad.GetSize().x / 2 - r),
> -(aPad.GetSize().y / 2 - r) );
> +
> +            corners_buffer.push_back( wxPoint( center.x, -dy ));
> +
> +            for( int i = 1; i < aCircleToSegmentsCount / 4 + 1; i++ )
> +            {
> +                wxPoint corner_position = wxPoint( center.x, -dy );
> +
> +                double angle_pg = i * delta;
> +                RotatePoint( &corner_position, center, angle_pg );
> +
> +                corners_buffer.push_back( wxPoint( corner_position.x,
> corner_position.y ) );
> +            }
> +
> +            double angle = aPad.GetOrientation();
> +
> +            for( int irect = 0; irect < 2; irect++ )
> +            {
> +                for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
> +                {
> +                    wxPoint cpos = corners_buffer[ic];
> +                    RotatePoint( &cpos, angle );            // Rotate
> according to module orientation
> +                    cpos += PadShapePos;                    // Shift
> origin to position
> +                    aCornerBuffer.Append( CPolyPt( cpos.x, cpos.y ) );
> +                }
> +
> +                aCornerBuffer.CloseLastContour();
> +                angle = AddAngles( angle, 1800 );       // this is
> calculate hole 3
> +            }
> +
> +            // Create holes, that are the mirrored from the previous holes
> +            for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
> +            {
> +                wxPoint swap = corners_buffer[ic];
> +                swap.x = -swap.x;
> +                corners_buffer[ic] = swap;
> +            }
> +
> +            // Now add corner 4 and 2 (2 is the corner 4 rotated by 180
> deg
> +            for( int irect = 0; irect < 2; irect++ )
> +            {
> +                for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
> +                {
> +                    wxPoint cpos = corners_buffer[ic];
> +                    RotatePoint( &cpos, angle );
> +                    cpos += PadShapePos;
> +                    aCornerBuffer.Append( CPolyPt( cpos.x, cpos.y ) );
> +                }
> +
> +                aCornerBuffer.CloseLastContour();
> +                angle = AddAngles( angle, 1800 );
> +            }
> +        }
> +        break;
> +
>      case PAD_TRAPEZOID:
>          {
>          CPOLYGONS_LIST cbuffer;
>
> === modified file 'pcbnew/class_pad.cpp'
> --- pcbnew/class_pad.cpp        2015-02-28 17:39:05 +0000
> +++ pcbnew/class_pad.cpp        2015-03-01 22:25:20 +0000
> @@ -141,6 +141,14 @@
>          radius = 1 + KiROUND( hypot( x, y ) / 2 );
>          break;
>
> +    case PAD_ROUNDRECT:
> +       radius = GetRoundRectCornerRadius( m_Size );
> +       x = m_Size.x >> 1;
> +       y = m_Size.y >> 1;
> +       radius = 1 + KiROUND( EuclideanNorm( wxSize( x - radius, y -
> radius )))
> +           + radius;
> +        break;
> +
>      default:
>          radius = 0;
>      }
> @@ -180,6 +188,7 @@
>          break;
>
>      case PAD_RECT:
> +    case PAD_ROUNDRECT:
>          //Use two corners and track their rotation
>          // (utilise symmetry to avoid four points)
>          quadrant1.x =  m_Size.x/2;
> @@ -774,6 +783,30 @@
>              return true;
>
>          break;
> +
> +    case PAD_ROUNDRECT:
> +    {
> +        // First check for hit in polygon
> +        wxPoint poly[12];
> +        int r = BuildPadPolygonRoundRect( poly, wxSize(0,0), 0 );
> +        RotatePoint( &delta, -m_Orient );
> +        if( TestPointInsidePolygon( poly, 12, delta ))
> +            return true;
> +        // Then check the rounded corners
> +        delta = aPosition - shape_pos - poly[0];
> +        if( KiROUND( EuclideanNorm( delta ) ) <= r )
> +            return true;
> +        delta = aPosition - shape_pos - poly[3];
> +        if( KiROUND( EuclideanNorm( delta ) ) <= r )
> +            return true;
> +        delta = aPosition - shape_pos - poly[6];
> +        if( KiROUND( EuclideanNorm( delta ) ) <= r )
> +            return true;
> +        delta = aPosition - shape_pos - poly[9];
> +        if( KiROUND( EuclideanNorm( delta ) ) <= r )
> +            return true;
> +    }
> +        break;
>      }
>
>      return false;
> @@ -860,6 +893,9 @@
>      case PAD_TRAPEZOID:
>          return _( "Trap" );
>
> +    case PAD_ROUNDRECT:
> +        return _( "Roundrect" );
> +
>      default:
>          return wxT( "???" );
>      }
>
> === modified file 'pcbnew/class_pad.h'
> --- pcbnew/class_pad.h  2015-02-18 19:27:00 +0000
> +++ pcbnew/class_pad.h  2015-03-01 22:25:20 +0000
> @@ -292,6 +292,27 @@
>      void BuildPadPolygon( wxPoint aCoord[4], wxSize aInflateValue, double
> aRotation ) const;
>
>      /**
> +     * Function BuildPadPolygonRoundRect
> +     * Has meaning only for rounded rect pads
> +     * Build the Corner list of the polygonal center shape,
> +     * depending on shape, extra size (clearance ...) and orientation
> +     * @param aCoord = a buffer to fill (12 corners).
> +     * @param aInflateValue = wxSize: the clearance or margin value.
> value > 0:
> +     *                        inflate, < 0 deflate
> +     * @param aRotation = full rotation of the polygon
> +     * @return Radius of the rounded corner arcs
> +     */
> +    int BuildPadPolygonRoundRect( wxPoint aCoord[12], wxSize
> aInflateValue, double aRotation ) const;
> +
> +    /**
> +     * Function GetRoundRectCornerRadius
> +     * Has meaning only for rounded rect pads
> +     * Returns the radius of the rounded corners for this pad.
> +     * @return The radius of the rounded corners for this pad.
> +     */
> +    int GetRoundRectCornerRadius() const;
> +
> +    /**
>       * Function BuildPadShapePolygon
>       * Build the Corner list of the polygonal shape,
>       * depending on shape, extra size (clearance ...) pad and orientation
> @@ -475,6 +496,18 @@
>
>  private:
>      /**
> +     * Private helper function BuildPadPolygonRoundRect
> +     * Has meaning only for rounded rect pads
> +     * Build the Corner list of the non-rotated polygonal center shape
> +     * @param aCoord = a buffer to fill (12 corners).
> +     * @param size Size of shape to build
> +     * @return Radius of the rounded corner arcs
> +     */
> +    int BuildPadPolygonRoundRect( wxPoint aCoord[12], wxSize size ) const;
> +
> +    int GetRoundRectCornerRadius( wxSize size ) const;
> +
> +    /**
>       * Function boundingRadius
>       * returns a calculated radius of a bounding circle for this pad.
>       */
> @@ -494,7 +527,7 @@
>
>      wxPoint     m_Pos;              ///< pad Position on board
>
> -    PAD_SHAPE_T m_padShape;         ///< Shape: PAD_CIRCLE, PAD_RECT,
> PAD_OVAL, PAD_TRAPEZOID
> +    PAD_SHAPE_T m_padShape;         ///< Shape: PAD_CIRCLE, PAD_RECT,
> PAD_OVAL, PAD_TRAPEZOID, PAD_ROUNDRECT
>
>
>      int         m_SubRatsnest;      ///< variable used in rats nest
> computations
>
> === modified file 'pcbnew/class_pad_draw_functions.cpp'
> --- pcbnew/class_pad_draw_functions.cpp 2015-02-28 20:50:35 +0000
> +++ pcbnew/class_pad_draw_functions.cpp 2015-03-01 22:25:20 +0000
> @@ -315,9 +315,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 );
>
> @@ -401,6 +402,80 @@
>          }
>          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 );
> +            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
> +        {
> +            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,
> +                   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;
>      }
> @@ -763,3 +838,150 @@
>              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 && aInflateValue.y == 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 if( aInflateValue.x <= 0 && aInflateValue.y <= 0 ) // 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 );
> +    }
> +    else
> +    {
> +        // just in case return a valid but very small (100 nm) polygon
> +        r = BuildPadPolygonRoundRect( aCoord, wxSize( 100, 100 ) );
> +    }
> +
> +    // 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 clampedSize;
> +    wxSize halfsize;
> +    int r;
> +
> +    // clamp the minimum pad edge length to 100 nm to avoid numerical
> problems
> +    clampedSize.x = size.x < 100 ? 100 : size.x;
> +    clampedSize.y = size.y < 100 ? 100 : size.y;
> +
> +    halfsize.x = clampedSize.x >> 1;
> +    halfsize.y = clampedSize.y >> 1;
> +
> +    r = GetRoundRectCornerRadius( clampedSize );
> +
> +    /*
> +     * 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-03-01 22:25:20 +0000
> @@ -55,7 +55,8 @@
>      PAD_CIRCLE,
>      PAD_OVAL,
>      PAD_RECT,
> -    PAD_TRAPEZOID
> +    PAD_TRAPEZOID,
> +    PAD_ROUNDRECT
>  };
>
>
> @@ -512,6 +513,10 @@
>      case PAD_TRAPEZOID:
>          m_PadShape->SetSelection( 3 );
>          break;
> +
> +    case PAD_ROUNDRECT:
> +        m_PadShape->SetSelection( 4 );
> +        break;
>      }
>
>      msg.Printf( wxT( "%g" ), angle );
> @@ -592,6 +597,14 @@
>          m_ShapeOffset_X_Ctrl->Enable( true );
>          m_ShapeOffset_Y_Ctrl->Enable( true );
>          break;
> +
> +    case 4:     // PAD_ROUNDRECT:
> +        m_ShapeDelta_Ctrl->Enable( false );
> +        m_trapDeltaDirChoice->Enable( false );
> +        m_ShapeSize_Y_Ctrl->Enable( true );
> +        m_ShapeOffset_X_Ctrl->Enable( true );
> +        m_ShapeOffset_Y_Ctrl->Enable( true );
> +        break;
>      }
>
>      transferDataToPad( m_dummyPad );
> @@ -1126,6 +1139,10 @@
>      case PAD_TRAPEZOID:
>          break;
>
> +    case PAD_ROUNDRECT:
> +        aPad->SetDelta( wxSize( 0, 0 ) );
> +        break;
> +
>      default:
>          ;
>      }
>
> === modified file 'pcbnew/dialogs/dialog_pad_properties_base.cpp'
> --- pcbnew/dialogs/dialog_pad_properties_base.cpp       2015-02-18
> 19:27:00 +0000
> +++ pcbnew/dialogs/dialog_pad_properties_base.cpp       2015-03-01
> 22:25:20 +0000
> @@ -65,10 +65,10 @@
>         m_staticText45->Wrap( -1 );
>         fgSizerPadType->Add( m_staticText45, 0,
> wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxTOP, 5 );
>
> -       wxString m_PadShapeChoices[] = { _("Circular"), _("Oval"),
> _("Rectangular"), _("Trapezoidal") };
> +       wxString m_PadShapeChoices[] = { _("Circular"), _("Oval"),
> _("Rectangular"), _("Trapezoidal"), _("Rounded Rectangle") };
>         int m_PadShapeNChoices = sizeof( m_PadShapeChoices ) / sizeof(
> wxString );
>         m_PadShape = new wxChoice( m_panelGeneral, wxID_ANY,
> wxDefaultPosition, wxDefaultSize, m_PadShapeNChoices, m_PadShapeChoices, 0
> );
> -       m_PadShape->SetSelection( 0 );
> +       m_PadShape->SetSelection( 4 );
>         fgSizerPadType->Add( m_PadShape, 0,
> wxALIGN_CENTER_VERTICAL|wxALL|wxEXPAND, 5 );
>
>
>
> === modified file 'pcbnew/dialogs/dialog_pad_properties_base.fbp'
> --- pcbnew/dialogs/dialog_pad_properties_base.fbp       2015-02-18
> 19:27:00 +0000
> +++ pcbnew/dialogs/dialog_pad_properties_base.fbp       2015-03-01
> 22:25:20 +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-03-01 22:32:48 +0000
> @@ -47,27 +47,24 @@
>  #include <polygon_test_point_inside.h>
>
>
> -/* compare 2 trapezoids (can be rectangle) 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
> +     * This case is not covered by the following check if one polygon is
>       * completely contained in the other (because edges don't intersect)!
>       */
> -    if( TestPointInsidePolygon( aTref, 4, aTcompare[0] ) )
> +    if( TestPointInsidePolygon( aTref, aTrefCount, aTcompare[0] ) )
>          return false;
>
> -    if( TestPointInsidePolygon( aTcompare, 4, aTref[0] ) )
> +    if( TestPointInsidePolygon( aTcompare, aTcompareCount, 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( ii = 0, jj = aTrefCount - 1; ii < aTrefCount; jj = ii, ii++ ) //
> for all edges in aTref
>      {
> -        for( kk = 0, ll = 3; kk < 4; ll = kk, kk++ )    // for all edges
> in aTcompare
> +        for( kk = 0, ll = aTcompareCount - 1; kk < aTcompareCount; ll =
> kk, kk++ ) // for all edges in aTcompare
>          {
>              double d;
>              int    intersect = TestForIntersectionOfStraightLineSegments(
> aTref[ii].x,
> @@ -87,6 +84,14 @@
>      return true;
>  }
>
> +/* compare 2 trapezoids (can be rectangle) 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 )
> +{
> +    return convex2convexDRC( aTref, 4, aTcompare, 4, aDist );
> +}
>
>  /* compare a trapezoids (can be rectangle) and a segment and return true
> if distance > aDist
>   */
> @@ -121,28 +126,34 @@
>  }
>
>
> +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, aTrefCount, aPcompare ) )
> +    {
> +        return false;
> +    }
> +
> +    // Test distance between aPcompare and each segment of the polygon:
> +    for( int ii = 0, jj = aTrefCount - 1; ii < aTrefCount; jj = ii, ii++
> )  // for all edge in polygon
> +    {
> +        if( TestSegmentHit( aPcompare, aTref[ii], aTref[jj], aDist ) )
> +            return false;
> +    }
> +
> +    return true;
> +}
> +
> +
>  /* compare a trapezoid 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 )
>  {
> -    /* 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 ) )
> -    {
> -        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
> -    {
> -        if( TestSegmentHit( aTref[ii], aTref[jj], aPcompare, aDist ) )
> -            return false;
> -    }
> -
> -    return true;
> +    return convex2pointDRC( aTref, 4, aPcompare, aDist );
>  }
>
>
> @@ -618,10 +629,16 @@
>      swap_pads = false;
>
>      // swap pads to make comparisons easier
> -    // priority is aRefPad = ROUND then OVAL then RECT then other
> +    // priority is aRefPad = ROUND then OVAL then RECT then ROUNDRECT
> then other
> +    // possible combos:
> +    // C  C,O,R,RR,T
> +    // O  O,R,RR,T
> +    // R  R,RR,T
> +    // RR RR,T
> +    // T  T
>      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:
> @@ -637,6 +654,11 @@
>                      swap_pads = true;
>                  break;
>
> +            case PAD_ROUNDRECT:
> +                if( aRefPad->GetShape() != PAD_RECT )
> +                    swap_pads = true;
> +                break;
> +
>              default:
>                  break;
>          }
> @@ -650,8 +672,8 @@
>
>      /* Because pad exchange, aRefPad shape is PAD_CIRCLE or PAD_OVAL,
>       * if one of the 2 pads was a PAD_CIRCLE or PAD_OVAL.
> -     * Therefore, if aRefPad is a PAD_RECT or a PAD_TRAPEZOID,
> -     * aPad is also a PAD_RECT or a PAD_TRAPEZOID
> +     * Therefore, if aRefPad is a PAD_RECT, PAD_ROUNDRECT or a
> PAD_TRAPEZOID,
> +     * aPad is also a PAD_RECT, PAD_ROUNDRECT or a PAD_TRAPEZOID
>       */
>      bool diag = true;
>
> @@ -708,6 +730,7 @@
>              {   // 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() );
>
> @@ -720,6 +743,48 @@
>                      diag = false;
>              }
>          }
> +        else if( aPad->GetShape() == PAD_ROUNDRECT )
> +        {
> +            wxPoint polyref[4];      // Shape of aRefPad
> +            wxPoint polycompare[12]; // inner shape of aPad
> +            wxPoint polyconvex[8];   // convex inner shape of aPad
> +
> +            aRefPad->BuildPadPolygon( polyref, wxSize( 0, 0 ),
> aRefPad->GetOrientation() );
> +            int r = aPad->BuildPadPolygonRoundRect( polycompare, wxSize(
> 0, 0 ), aPad->GetOrientation() );
> +
> +            // Move aPad shape to relativePadPos
> +            for( int ii = 0; ii < 12; ii++ )
> +                polycompare[ii] += relativePadPos;
> +
> +            // build a convex inner shape for the ROUNDRECT pad
> +            // by leaving out the center points of the corner arcs
> +            polyconvex[0] = polycompare[1];
> +            polyconvex[1] = polycompare[2];
> +            polyconvex[2] = polycompare[4];
> +            polyconvex[3] = polycompare[5];
> +            polyconvex[4] = polycompare[7];
> +            polyconvex[5] = polycompare[8];
> +            polyconvex[6] = polycompare[10];
> +            polyconvex[7] = polycompare[11];
> +
> +            // And now test polygons:
> +            if( !convex2convexDRC( polyref, 4, polyconvex, 8, dist_min ) )
> +                diag = false;
> +
> +            // if not already failed, check the corner circles
> +            if( diag )
> +            {
> +                for( int ii = 0; ii < 12; ii += 3 )
> +                {
> +                    if( !trapezoid2pointDRC( polyref, polycompare[ii],
> +                                             dist_min + r ) )
> +                    {
> +                        diag = false;
> +                        break;
> +                    }
> +                }
> +            }
> +        }
>          else if( aPad->GetShape() == PAD_TRAPEZOID )
>          {
>              wxPoint polyref[4];         // Shape of aRefPad
> @@ -745,6 +810,144 @@
>          }
>          break;
>
> +    case PAD_ROUNDRECT:
> +        if( aPad->GetShape() == PAD_ROUNDRECT )
> +        {
> +            wxPoint polyref[12];       // inner shape of aRefPad
> +            wxPoint polycompare[12];   // inner shape of aPad
> +            wxPoint polyrefconvex[8];  // convex inner shape of aRefPad
> +            wxPoint polycompconvex[8]; // convex inner shape of aPad
> +
> +            int rref = aRefPad->BuildPadPolygonRoundRect( polyref,
> wxSize( 0, 0 ), aRefPad->GetOrientation() );
> +            int rcomp = aPad->BuildPadPolygonRoundRect( polycompare,
> wxSize( 0, 0 ), aPad->GetOrientation() );
> +
> +            // Move aPad shape to relativePadPos
> +            for( int ii = 0; ii < 12; ii++ )
> +                polycompare[ii] += relativePadPos;
> +
> +            // build a convex inner shape for aRefPad
> +            // by leaving out the center points of the corner arcs
> +            polyrefconvex[0] = polyref[1];
> +            polyrefconvex[1] = polyref[2];
> +            polyrefconvex[2] = polyref[4];
> +            polyrefconvex[3] = polyref[5];
> +            polyrefconvex[4] = polyref[7];
> +            polyrefconvex[5] = polyref[8];
> +            polyrefconvex[6] = polyref[10];
> +            polyrefconvex[7] = polyref[11];
> +
> +            // build a convex inner shape for aPad
> +            // by leaving out the center points of the corner arcs
> +            polycompconvex[0] = polycompare[1];
> +            polycompconvex[1] = polycompare[2];
> +            polycompconvex[2] = polycompare[4];
> +            polycompconvex[3] = polycompare[5];
> +            polycompconvex[4] = polycompare[7];
> +            polycompconvex[5] = polycompare[8];
> +            polycompconvex[6] = polycompare[10];
> +            polycompconvex[7] = polycompare[11];
> +
> +            // And now test inner polygons:
> +            if( !convex2convexDRC( polyrefconvex, 8, polycompconvex, 8,
> dist_min ) )
> +                diag = false;
> +
> +            // if not already failed test ref corner arcs against aPad
> +            if( diag )
> +            {
> +                for( int ii = 0; ii < 12; ii += 3 )
> +                {
> +                    if( !convex2pointDRC( polycompconvex, 8, polyref[ii],
> +                                          dist_min + rref ) )
> +                    {
> +                        diag = false;
> +                        break;
> +                    }
> +                }
> +            }
> +
> +            // if not already failed test aPad corner arcs against aRefPad
> +            if( diag )
> +            {
> +                for( int ii = 0; ii < 12; ii += 3 )
> +                {
> +                    if( !convex2pointDRC( polyrefconvex, 8,
> polycompare[ii],
> +                                          dist_min + rcomp ) )
> +                    {
> +                        diag = false;
> +                        break;
> +                    }
> +                }
> +            }
> +
> +            // finally test corner arcs against each other if still not
> +            // failed
> +            if( diag )
> +            {
> +                for( int ii = 0; ii < 12 && diag; ii += 3 )
> +                {
> +                    for( int jj = 0; jj < 12; jj += 3 )
> +                    {
> +                        if( ( KiROUND( EuclideanNorm( polyref[ii] -
> polycompare[jj] ) )
> +                              - rref - rcomp ) < dist_min )
> +                        {
> +                            diag = false;
> +                            break;
> +                        }
> +                    }
> +                }
> +            }
> +        }
> +        else if( aPad->GetShape() == PAD_TRAPEZOID )
> +        {
> +            wxPoint polyref[12];    // inner shape of aRefPad
> +            wxPoint polycompare[4]; // shape of aPad
> +            wxPoint polyconvex[8];  // convex inner shape of aRefPad
> +
> +            int r = aRefPad->BuildPadPolygonRoundRect( 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;
> +
> +            // build a convex inner shape for the ROUNDRECT pad
> +            // by leaving out the center points of the corner arcs
> +            polyconvex[0] = polyref[1];
> +            polyconvex[1] = polyref[2];
> +            polyconvex[2] = polyref[4];
> +            polyconvex[3] = polyref[5];
> +            polyconvex[4] = polyref[7];
> +            polyconvex[5] = polyref[8];
> +            polyconvex[6] = polyref[10];
> +            polyconvex[7] = polyref[11];
> +
> +            // And now test polygons:
> +            if( !convex2convexDRC( polycompare, 4, polyconvex, 8,
> dist_min ) )
> +                diag = false;
> +
> +            // if not already failed, check the corner circles
> +            if( diag )
> +            {
> +                for( int ii = 0; ii < 12; ii += 3 )
> +                {
> +                    if( !trapezoid2pointDRC( polycompare, polyref[ii],
> +                                             dist_min + r ) )
> +                    {
> +                        diag = false;
> +                        break;
> +                    }
> +                }
> +            }
> +        }
> +        else
> +        {
> +            // Should not occur
> +            wxLogDebug( wxT( "DRC::checkClearancePadToPad: unexpected pad
> ref ROUNDRECT @ %d, %d to pad shape %d @ %d, %d"),
> +                aRefPad->GetPosition().x, aRefPad->GetPosition().y,
> +                aPad->GetShape(), aPad->GetPosition().x,
> aPad->GetPosition().y );
> +        }
> +        break;
> +
>      case PAD_OVAL:     /* an oval pad is like a track segment */
>      {
>          /* Create a track segment with same dimensions as the oval aRefPad
> @@ -828,6 +1031,7 @@
>      wxPoint startPoint, endPoint;
>      int     seuil;
>      int     deltay;
> +    int     r;
>
>      int     segmHalfWidth = aSegmentWidth / 2;
>
> @@ -992,6 +1196,66 @@
>
>          break;
>
> +    case PAD_ROUNDRECT:
> +        /* Test du rectangle dimx + seuil, dimy */
> +        m_xcliplo = m_padToTestPos.x - padHalfsize.x - seuil;
> +        m_ycliplo = m_padToTestPos.y - padHalfsize.y;
> +        m_xcliphi = m_padToTestPos.x + padHalfsize.x + seuil;
> +        m_ycliphi = m_padToTestPos.y + padHalfsize.y;
> +
> +        if( !checkLine( startPoint, endPoint ) )
> +            return false;
> +
> +        /* Test du rectangle dimx , dimy + seuil */
> +        m_xcliplo = m_padToTestPos.x - padHalfsize.x;
> +        m_ycliplo = m_padToTestPos.y - padHalfsize.y - seuil;
> +        m_xcliphi = m_padToTestPos.x + padHalfsize.x;
> +        m_ycliphi = m_padToTestPos.y + padHalfsize.y + seuil;
> +
> +        if( !checkLine( startPoint, endPoint ) )
> +            return false;
> +
> +       r = aPad->GetRoundRectCornerRadius();
> +
> +        /* test des 4 cercles ( surface d'solation autour des sommets */
> +        /* test du coin sup. gauche du pad */
> +        startPoint.x = m_padToTestPos.x - padHalfsize.x + r;
> +        startPoint.y = m_padToTestPos.y - padHalfsize.y + r;
> +        RotatePoint( &startPoint, m_padToTestPos, orient );
> +        RotatePoint( &startPoint, m_segmAngle );
> +
> +        if( !checkMarginToCircle( startPoint, seuil + r, m_segmLength ) )
> +            return false;
> +
> +        /* test du coin sup. droit du pad */
> +        startPoint.x = m_padToTestPos.x + padHalfsize.x - r;
> +        startPoint.y = m_padToTestPos.y - padHalfsize.y + r;
> +        RotatePoint( &startPoint, m_padToTestPos, orient );
> +        RotatePoint( &startPoint, m_segmAngle );
> +
> +        if( !checkMarginToCircle( startPoint, seuil + r, m_segmLength ) )
> +            return false;
> +
> +        /* test du coin inf. gauche du pad */
> +        startPoint.x = m_padToTestPos.x - padHalfsize.x + r;
> +        startPoint.y = m_padToTestPos.y + padHalfsize.y - r;
> +        RotatePoint( &startPoint, m_padToTestPos, orient );
> +        RotatePoint( &startPoint, m_segmAngle );
> +
> +        if( !checkMarginToCircle( startPoint, seuil + r, m_segmLength ) )
> +            return false;
> +
> +        /* test du coin inf. droit du pad */
> +        startPoint.x = m_padToTestPos.x + padHalfsize.x - r;
> +        startPoint.y = m_padToTestPos.y + padHalfsize.y - r;
> +        RotatePoint( &startPoint, m_padToTestPos, orient );
> +        RotatePoint( &startPoint, m_segmAngle );
> +
> +        if( !checkMarginToCircle( startPoint, seuil + r, m_segmLength ) )
> +            return false;
> +
> +        break;
> +
>      case PAD_TRAPEZOID:
>      {
>          wxPoint poly[4];
>
> === modified file 'pcbnew/exporters/export_gencad.cpp'
> --- pcbnew/exporters/export_gencad.cpp  2015-02-22 14:43:44 +0000
> +++ pcbnew/exporters/export_gencad.cpp  2015-03-01 22:25:20 +0000
> @@ -553,6 +553,13 @@
>
>              // XXX TO BE IMPLEMENTED! and I don't know if it could be
> actually imported by something
>              break;
> +
> +        case PAD_ROUNDRECT:
> +            fprintf( aFile, " POLYGON %g\n",
> +                     pad->GetDrillSize().x / SCALE_FACTOR );
> +
> +            // XXX TO BE IMPLEMENTED! But how to test it?
> +            break;
>          }
>      }
>
>
> === modified file 'pcbnew/exporters/export_vrml.cpp'
> --- pcbnew/exporters/export_vrml.cpp    2015-02-18 19:27:00 +0000
> +++ pcbnew/exporters/export_vrml.cpp    2015-03-01 22:25:20 +0000
> @@ -1095,6 +1095,53 @@
>          break;
>      }
>
> +    case PAD_ROUNDRECT:
> +    {
> +        // integer coordinates of pad center polygon (already rotated)
> +        wxPoint coordsi[12];
> +        aPad->BuildPadPolygonRoundRect( coordsi, wxSize(0,0),
> +                                        aPad->GetOrientation() );
> +
> +        // double coordinates for VRML world
> +        VECTOR2D coordsd[12];
> +        for( int i = 0; i < 12; i++ )
> +        {
> +            coordsi[i] += aPad->ShapePos();
> +            coordsd[i] = VECTOR2D( coordsi[i].x * aModel.scale,
> +                                   coordsi[i].y * aModel.scale );
> +        }
> +
> +        int lines = aTinLayer->NewContour();
> +
> +        if( lines < 0 )
> +            throw( std::runtime_error( aTinLayer->GetError() ) );
> +
> +        for( int i = 1; i < 12; i += 3 )
> +        {
> +            // add one of the straight edges
> +            if( !aTinLayer->AddVertex( lines, coordsd[i].x, -coordsd[i].y
> ) )
> +                throw( std::runtime_error( aTinLayer->GetError() ) );
> +            if( !aTinLayer->AddVertex( lines, coordsd[i + 1].x,
> -coordsd[i + 1].y ) )
> +                throw( std::runtime_error( aTinLayer->GetError() ) );
> +            // add the quarter circle to the next straight edge
> +            // tried to use addArc() but it always looked weird
> +            for( int j = 1; j < 9; j++ )
> +            {
> +                VECTOR2D rp( coordsd[i + 1].x, coordsd[i + 1].y );
> +                RotatePoint( &rp.x, &rp.y,
> +                             coordsd[(i + 2) % 12].x, coordsd[(i + 2) %
> 12].y,
> +                             100 * j );
> +                if( !aTinLayer->AddVertex( lines, rp.x, -rp.y ) )
> +                    throw( std::runtime_error( aTinLayer->GetError() ) );
> +            }
> +        }
> +
> +        if( !aTinLayer->EnsureWinding( lines, false ) )
> +            throw( std::runtime_error( aTinLayer->GetError() ) );
> +
> +        break;
> +    }
> +
>      default:
>          break;
>      }
>
> === modified file 'pcbnew/exporters/gen_modules_placefile.cpp'
> --- pcbnew/exporters/gen_modules_placefile.cpp  2015-02-23 13:03:20 +0000
> +++ pcbnew/exporters/gen_modules_placefile.cpp  2015-03-01 22:25:20 +0000
> @@ -707,7 +707,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 );
>
> === modified file 'pcbnew/kicad_plugin.cpp'
> --- pcbnew/kicad_plugin.cpp     2015-02-22 21:25:29 +0000
> +++ pcbnew/kicad_plugin.cpp     2015-03-01 22:25:20 +0000
> @@ -1275,6 +1275,7 @@
>      case PAD_RECT:      shape = "rect";         break;
>      case PAD_OVAL:      shape = "oval";         break;
>      case PAD_TRAPEZOID: shape = "trapezoid";    break;
> +    case PAD_ROUNDRECT: shape = "roundrect";    break;
>
>      default:
>          THROW_IO_ERROR( wxString::Format( _( "unknown pad type: %d"),
> aPad->GetShape() ) );
>
> === modified file 'pcbnew/pcb_painter.cpp'
> --- pcbnew/pcb_painter.cpp      2015-02-18 19:27:00 +0000
> +++ pcbnew/pcb_painter.cpp      2015-03-01 22:25:20 +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-22 21:25:29 +0000
> +++ pcbnew/pcb_parser.cpp       2015-03-01 22:25:20 +0000
> @@ -2213,8 +2213,12 @@
>          pad->SetShape( PAD_TRAPEZOID );
>          break;
>
> +    case T_roundrect:
> +        pad->SetShape( PAD_ROUNDRECT );
> +        break;
> +
>      default:
> -        Expecting( "circle, rectangle, oval, or trapezoid" );
> +        Expecting( "circle, rectangle, roundrect, oval, or trapezoid" );
>      }
>
>      for( token = NextTok();  token != T_RIGHT;  token = NextTok() )
>
> === modified file 'pcbnew/plot_board_layers.cpp'
> --- pcbnew/plot_board_layers.cpp        2015-02-18 19:27:00 +0000
> +++ pcbnew/plot_board_layers.cpp        2015-03-01 22:25:20 +0000
> @@ -380,6 +380,7 @@
>                  // Fall through:
>              case PAD_TRAPEZOID:
>              case PAD_RECT:
> +            case PAD_ROUNDRECT:
>              default:
>                  itemplotter.PlotPad( pad, color, plotMode );
>                  break;
>
> === modified file 'pcbnew/plot_brditems_plotter.cpp'
> --- pcbnew/plot_brditems_plotter.cpp    2015-02-18 19:27:00 +0000
> +++ pcbnew/plot_brditems_plotter.cpp    2015-03-01 22:25:20 +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-03-01 22:25:20 +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-03-01 22:25:20 +0000
> @@ -512,6 +512,56 @@
>          }
>          break;
>
> +    case PAD_ROUNDRECT:
> +        {
> +            wxPoint coordsi[12];
> +            POINT coordsd[12];
> +
> +            aPad->BuildPadPolygonRoundRect( coordsi, wxSize( 0, 0 ), 0 );
> +
> +            for( int i = 0; i < 12; i++ )
> +            {
> +                coordsd[i].x = scale( coordsi[i].x );
> +                coordsd[i].y = scale( coordsi[i].y );
> +                coordsd[i] += dsnOffset;
> +            }
> +
> +            for( int ndx = 0; ndx < reportedLayers; ++ndx )
> +            {
> +                SHAPE* shape = new SHAPE( padstack );
> +
> +                padstack->Append( shape );
> +
> +                PATH* polygon = new PATH( shape, T_polygon );
> +
> +                shape->SetShape( polygon );
> +
> +                polygon->SetLayerId( layerName[ndx] );
> +
> +                for( int i = 1; i < 12; i += 3 )
> +                {
> +                    polygon->AppendPoint( coordsd[i] );
> +                    polygon->AppendPoint( coordsd[i + 1] );
> +
> +                    for( int j = 1; j < 9; j++ )
> +                    {
> +                        POINT p( coordsd[i + 1] );
> +                        RotatePoint( &p.x, &p.y, coordsd[(i + 2) % 12].x,
> +                                     coordsd[(i + 2) % 12].y, 100 * j );
> +                        polygon->AppendPoint( p );
> +                    }
> +                }
> +            }
> +
> +            snprintf( name, sizeof(name), "RRect%sPad_%.6gx%.6g_um",
> +                      uniqifier.c_str(), IU2um( aPad->GetSize().x ),
> +                      IU2um( aPad->GetSize().y ) );
> +            name[ sizeof(name)-1 ] = 0;
> +
> +            padstack->SetPadstackId( name );
> +        }
> +        break;
> +
>      case PAD_OVAL:
>          {
>              double  dx  = scale( aPad->GetSize().x ) / 2.0;
>
>
> _______________________________________________
> Mailing list: https://launchpad.net/~kicad-developers
> Post to     : kicad-developers@xxxxxxxxxxxxxxxxxxx
> Unsubscribe : https://launchpad.net/~kicad-developers
> More help   : https://help.launchpad.net/ListHelp
>

Follow ups

References