kicad-developers team mailing list archive
-
kicad-developers team
-
Mailing list archive
-
Message #16848
Re: [PATCH] V2 Rectangular pads with rounded corners
On 17.02.2015 23:55, Mathias Grimmberger wrote:
>
> Hi everybody,
>
> below is a new version of a patch to add support for rectangular pads
> with rounded corners to KiCad. The patch was created against revision
> 5428.
>
> What has changed:
>
> - optimized Gerber output
> - plotting to PDF and Postscript should now produce correct results (as
> far as I can check that)
> - plotting to SVG should work, but does produce little artifacts in the
> rounded corners, I think the SVG plotter does strange things with the
> fill mode
>
>
> BTW, does anybody know what the CERN people are doing? Because properly
> supporting roundrect pads in the PNS router needs an extension to the
> geometry primitives, something like a convex polygon shape (as a bonus
> this would make support for arbitrarily rotated pads possible).
Hi Mathias,
For the moment we could approximate them as ordinary rectangles.
I would love be extremely grateful if somebody wrote a SHAPE_CONVEX,
though, representing a convex polygon...
Regards,
Tom
>
> The thought of myself extending the geometry primitives is a bit
> scary... ;-)
>
>
> Enjoy,
>
> MGri
>
>
> === modified file 'common/common_plotDXF_functions.cpp'
> --- common/common_plotDXF_functions.cpp 2015-02-02 08:06:39 +0000
> +++ common/common_plotDXF_functions.cpp 2015-02-17 19:36:08 +0000
> @@ -601,6 +601,12 @@
> FinishTo( wxPoint( ox, oy ) );
> }
>
> +void DXF_PLOTTER::FlashPadRoundRect( const wxPoint& pos, const wxPoint corners[12],
> + int cornerRadius, double orient,
> + EDA_DRAW_MODE_T trace_mode )
> +{
> + // FIXME: MGri - not implemented yet
> +}
>
> /**
> * DXF trapezoidal pad: only sketch mode is supported
>
> === modified file 'common/common_plotGERBER_functions.cpp'
> --- common/common_plotGERBER_functions.cpp 2015-02-02 08:06:39 +0000
> +++ common/common_plotGERBER_functions.cpp 2015-02-17 19:36:08 +0000
> @@ -559,6 +559,120 @@
> }
>
>
> +void GERBER_PLOTTER::FlashPadRoundRect( const wxPoint& pos, const wxPoint corners[12],
> + int cornerRadius, double orient,
> + EDA_DRAW_MODE_T trace_mode )
> +
> +{
> + wxASSERT( outputFile );
> +
> + // XXX to do: use an aperture macro to declare the pad if possible
> +
> + if( ( orient == 0 || orient == 900 || orient == 1800 || orient == 2700 )
> + && trace_mode == FILLED )
> + {
> + wxSize size;
> + DPOINT pos_dev;
> +
> + // flash the large rectangle of the center polygon
> + pos_dev = userToDeviceCoordinates( pos );
> + if( orient == 0 || orient == 1800 )
> + {
> + size = wxSize( corners[4].x - corners[11].x,
> + corners[4].y - corners[5].y );
> + }
> + else
> + {
> + size = wxSize( corners[1].y - corners[8].y,
> + corners[3].x - corners[0].x );
> + }
> + selectAperture( size, APERTURE::Rect );
> + emitDcode( pos_dev, 3 );
> + // flash the top small rectangle of the center polygon
> + if( orient == 0 || orient == 1800 )
> + {
> + pos_dev = userToDeviceCoordinates( pos + wxPoint( 0, corners[0].y + cornerRadius / 2 ));
> + size = wxSize( corners[3].x - corners[0].x,
> + corners[1].y - corners[0].y );
> + }
> + else
> + {
> + pos_dev = userToDeviceCoordinates( pos + wxPoint( 0, corners[3].x + cornerRadius / 2 ));
> + size = wxSize( corners[3].y - corners[6].y,
> + corners[4].x - corners[3].x );
> + }
> + selectAperture( size, APERTURE::Rect );
> + emitDcode( pos_dev, 3 );
> + // flash the bottom small rectangle of the center polygon
> + if( orient == 0 || orient == 1800 )
> + {
> + pos_dev = userToDeviceCoordinates( pos - wxPoint( 0, corners[0].y + cornerRadius / 2 ));
> + }
> + else
> + {
> + pos_dev = userToDeviceCoordinates( pos - wxPoint( 0, corners[3].x + cornerRadius / 2 ));
> + }
> + selectAperture( size, APERTURE::Rect );
> + emitDcode( pos_dev, 3 );
> + // Flash the 4 corner circles
> + size = wxSize( cornerRadius << 1, cornerRadius << 1 );
> + selectAperture( size, APERTURE::Circle );
> + if( orient == 0 || orient == 1800 )
> + {
> + pos_dev = userToDeviceCoordinates( corners[0] + pos );
> + emitDcode( pos_dev, 3 );
> + pos_dev = userToDeviceCoordinates( corners[3] + pos );
> + emitDcode( pos_dev, 3 );
> + pos_dev = userToDeviceCoordinates( corners[6] + pos );
> + emitDcode( pos_dev, 3 );
> + pos_dev = userToDeviceCoordinates( corners[9] + pos );
> + emitDcode( pos_dev, 3 );
> + }
> + else
> + {
> + pos_dev = userToDeviceCoordinates(
> + wxPoint( corners[0].y, -corners[0].x ) + pos );
> + emitDcode( pos_dev, 3 );
> + pos_dev = userToDeviceCoordinates(
> + wxPoint( corners[3].y, -corners[3].x ) + pos );
> + emitDcode( pos_dev, 3 );
> + pos_dev = userToDeviceCoordinates(
> + wxPoint( corners[6].y, -corners[6].x ) + pos );
> + emitDcode( pos_dev, 3 );
> + pos_dev = userToDeviceCoordinates(
> + wxPoint( corners[9].y, -corners[9].x ) + pos );
> + emitDcode( pos_dev, 3 );
> + }
> + }
> + else
> + {
> + std::vector< wxPoint > cornerList;
> +
> + // construct the rotated polygons corner list
> + for( int i = 2; i < 12; i += 3 )
> + {
> + wxPoint p( corners[i] );
> + RotatePoint( &p, orient );
> + p += pos;
> + cornerList.push_back( p );
> + wxPoint center( corners[(i + 1) % 12] );
> + RotatePoint( ¢er, orient );
> + for( int rot = 100; rot < 900; rot += 100 )
> + {
> + wxPoint pr( corners[i] );
> + RotatePoint( &pr, orient );
> + RotatePoint( &pr, center, rot );
> + pr += pos;
> + cornerList.push_back( pr );
> + }
> + }
> + // plot it
> + SetCurrentLineWidth( -1 );
> + PlotPoly( cornerList, trace_mode == SKETCH ? NO_FILL : FILLED_SHAPE );
> + }
> +}
> +
> +
> void GERBER_PLOTTER::FlashPadTrapez( const wxPoint& aPadPos, const wxPoint* aCorners,
> double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode )
>
>
> === modified file 'common/common_plotHPGL_functions.cpp'
> --- common/common_plotHPGL_functions.cpp 2015-02-17 16:32:47 +0000
> +++ common/common_plotHPGL_functions.cpp 2015-02-17 19:36:08 +0000
> @@ -629,6 +629,12 @@
> }
> }
>
> +void HPGL_PLOTTER::FlashPadRoundRect( const wxPoint& pos, const wxPoint corners[12],
> + int cornerRadius, double orient,
> + EDA_DRAW_MODE_T trace_mode )
> +{
> + // FIXME: MGri - not implemented yet
> +}
>
> void HPGL_PLOTTER::FlashPadTrapez( const wxPoint& aPadPos, const wxPoint* aCorners,
> double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode )
>
> === modified file 'common/common_plotPS_functions.cpp'
> --- common/common_plotPS_functions.cpp 2014-10-19 20:20:16 +0000
> +++ common/common_plotPS_functions.cpp 2015-02-17 19:36:08 +0000
> @@ -181,6 +181,82 @@
> PlotPoly( cornerList, ( trace_mode == FILLED ) ? FILLED_SHAPE : NO_FILL );
> }
>
> +void PSLIKE_PLOTTER::FlashPadRoundRect( const wxPoint& pos, const wxPoint corners[12],
> + int cornerRadius, double orient,
> + EDA_DRAW_MODE_T trace_mode )
> +{
> + static std::vector< wxPoint > cornerList;
> + cornerList.clear();
> +
> + for( int ii = 0; ii < 12; ii++ )
> + cornerList.push_back( corners[ii] );
> +
> + // As far as I understand it line and pen width are the same thing???
> +
> + SetCurrentLineWidth( -1 );
> + int w = GetCurrentLineWidth();
> + int hw = w / 2;
> +
> + cornerList[0].x += hw;
> + cornerList[0].y -= hw;
> + cornerList[1].x += hw;
> + cornerList[1].y -= hw;
> + cornerList[2].x -= hw;
> + cornerList[2].y -= hw;
> + cornerList[3].x -= hw;
> + cornerList[3].y -= hw;
> + cornerList[4].x -= hw;
> + cornerList[4].y -= hw;
> + cornerList[5].x -= hw;
> + cornerList[5].y += hw;
> + cornerList[6].x -= hw;
> + cornerList[6].y += hw;
> + cornerList[7].x -= hw;
> + cornerList[7].y += hw;
> + cornerList[8].x += hw;
> + cornerList[8].y += hw;
> + cornerList[9].x += hw;
> + cornerList[9].y += hw;
> + cornerList[10].x += hw;
> + cornerList[10].y += hw;
> + cornerList[11].x += hw;
> + cornerList[11].y -= hw;
> +
> + for( unsigned ii = 0; ii < cornerList.size(); ii++ )
> + {
> + RotatePoint( &cornerList[ii], orient );
> + cornerList[ii] += pos;
> + }
> +
> + cornerList.push_back( cornerList[0] );
> +
> + if( trace_mode == FILLED )
> + {
> + PlotPoly( cornerList, FILLED_SHAPE );
> + }
> + else
> + {
> + for( unsigned ii = 1; ii < 12; ii += 3 )
> + {
> + MoveTo( cornerList[ii] );
> + FinishTo( cornerList[ii + 1] );
> + }
> + }
> +
> + if ( w > 2 * cornerRadius )
> + w = 2 * cornerRadius;
> +
> + Arc(cornerList[0], orient + 1800, orient + 2700, cornerRadius,
> + ( trace_mode == FILLED ) ? FILLED_SHAPE : NO_FILL, w );
> + Arc(cornerList[3], orient + 2700, orient + 3600, cornerRadius,
> + ( trace_mode == FILLED ) ? FILLED_SHAPE : NO_FILL, w );
> + Arc(cornerList[6], orient, orient + 900, cornerRadius,
> + ( trace_mode == FILLED ) ? FILLED_SHAPE : NO_FILL, w );
> + Arc(cornerList[9], orient + 900, orient + 1800, cornerRadius,
> + ( trace_mode == FILLED ) ? FILLED_SHAPE : NO_FILL, w );
> +
> + SetCurrentLineWidth( -1 );
> +}
>
> void PSLIKE_PLOTTER::FlashPadTrapez( const wxPoint& aPadPos, const wxPoint *aCorners,
> double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode )
>
> === modified file 'common/pcb.keywords'
> --- common/pcb.keywords 2013-09-17 00:52:08 +0000
> +++ common/pcb.keywords 2015-02-17 19:36:08 +0000
> @@ -142,6 +142,7 @@
> reference
> right
> rotate
> +roundrect
> scale
> segment
> segment_width
>
> === modified file 'include/pad_shapes.h'
> --- include/pad_shapes.h 2014-01-28 09:43:55 +0000
> +++ include/pad_shapes.h 2015-02-17 19:36:08 +0000
> @@ -15,7 +15,8 @@
> PAD_ROUND = PAD_CIRCLE,
> PAD_RECT,
> PAD_OVAL,
> - PAD_TRAPEZOID
> + PAD_TRAPEZOID,
> + PAD_ROUNDRECT
> };
>
> /**
>
> === modified file 'include/plot_common.h'
> --- include/plot_common.h 2014-12-23 13:01:59 +0000
> +++ include/plot_common.h 2015-02-17 19:36:08 +0000
> @@ -257,6 +257,18 @@
> virtual void FlashPadRect( const wxPoint& pos, const wxSize& size,
> double orient, EDA_DRAW_MODE_T trace_mode ) = 0;
>
> + /**
> + * @param pos Position of the shape
> + * @param corners List of the 12 corners of the inner polygon, the arcs
> + * for the corners are centered on corner 0, 3, 6 and 9
> + * @param cornerRadius Radius of the rounded corners
> + * @param orient The rotattion of the shape
> + * @param trace_mode FILLED or SKETCH
> + */
> + virtual void FlashPadRoundRect( const wxPoint& pos, const wxPoint corners[12],
> + int cornerRadius, double orient,
> + EDA_DRAW_MODE_T trace_mode ) = 0;
> +
> /** virtual function FlashPadTrapez
> * flash a trapezoidal pad
> * @param aPadPos = the position of the shape
> @@ -509,6 +521,9 @@
> EDA_DRAW_MODE_T trace_mode );
> virtual void FlashPadRect( const wxPoint& pos, const wxSize& size,
> double orient, EDA_DRAW_MODE_T trace_mode );
> + virtual void FlashPadRoundRect( const wxPoint& pos, const wxPoint corners[12],
> + int cornerRadius, double orient,
> + EDA_DRAW_MODE_T trace_mode );
> virtual void FlashPadTrapez( const wxPoint& aPadPos, const wxPoint *aCorners,
> double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode );
>
> @@ -561,6 +576,9 @@
> EDA_DRAW_MODE_T trace_mode );
> virtual void FlashPadRect( const wxPoint& pos, const wxSize& size,
> double orient, EDA_DRAW_MODE_T trace_mode );
> + virtual void FlashPadRoundRect( const wxPoint& pos, const wxPoint corners[12],
> + int cornerRadius, double orient,
> + EDA_DRAW_MODE_T trace_mode );
> virtual void FlashPadTrapez( const wxPoint& aPadPos, const wxPoint *aCorners,
> double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode );
>
> @@ -919,6 +937,13 @@
> double orient, EDA_DRAW_MODE_T trace_mode );
>
> /**
> + * Roundrect pad at the moment are *never* handled as aperture, since
> + * they require aperture macros
> + */
> + virtual void FlashPadRoundRect( const wxPoint& pos, const wxPoint corners[12],
> + int cornerRadius, double orient,
> + EDA_DRAW_MODE_T trace_mode );
> + /**
> * Trapezoidal pad at the moment are *never* handled as aperture, since
> * they require aperture macros
> */
> @@ -1045,6 +1070,9 @@
> EDA_DRAW_MODE_T trace_mode );
> virtual void FlashPadRect( const wxPoint& pos, const wxSize& size,
> double orient, EDA_DRAW_MODE_T trace_mode );
> + virtual void FlashPadRoundRect( const wxPoint& pos, const wxPoint corners[12],
> + int cornerRadius, double orient,
> + EDA_DRAW_MODE_T trace_mode );
> virtual void FlashPadTrapez( const wxPoint& aPadPos, const wxPoint *aCorners,
> double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode );
>
>
> === modified file 'pcbnew/board_items_to_polygon_shape_transform.cpp'
> --- pcbnew/board_items_to_polygon_shape_transform.cpp 2015-01-15 20:01:53 +0000
> +++ pcbnew/board_items_to_polygon_shape_transform.cpp 2015-02-17 19:36:08 +0000
> @@ -605,6 +605,44 @@
> aCornerBuffer.ImportFrom( shapeWithClearance );
> }
> break;
> +
> + case PAD_ROUNDRECT:
> + {
> + wxPoint corners[12];
> + int r = BuildPadPolygonRoundRect( corners, wxSize( 0, 0 ), angle );
> +
> + // We are using ClipperLib to inflate the polygon shape, using
> + // arcs to connect moved segments.
> + ClipperLib::Path outline;
> + ClipperLib::Paths shapeWithClearance;
> +
> + for( int ii = 0; ii < 12; ii += 3 )
> + {
> + corners[ii] += PadShapePos;
> + outline << ClipperLib::IntPoint( corners[ii].x, corners[ii].y );
> + }
> +
> + ClipperLib::ClipperOffset offset_engine;
> + // Prepare an offset (inflate) transform, with edges connected by arcs
> + offset_engine.AddPath( outline, ClipperLib::jtRound, ClipperLib::etClosedPolygon );
> +
> + // Clipper approximates arcs by segments
> + // It uses a value called ArcTolerance which is the max error between the arc
> + // and segments created to approximate this arc
> + // the number of segm per circle is:
> + // n = PI / acos(1 - arc_tolerance / (arc radius))
> + // the arc radius is aClearanceValue
> + // because arc_tolerance is << aClearanceValue and aClearanceValue >= 0
> + // n = PI / (arc_tolerance / aClearanceValue )
> + offset_engine.ArcTolerance = ((double)aClearanceValue + r) / 3.14 / aCircleToSegmentsCount;
> +
> + double rounding_radius = (aClearanceValue + r) * aCorrectionFactor;
> + offset_engine.Execute( shapeWithClearance, rounding_radius );
> +
> + // get new outline (only one polygon is expected)
> + aCornerBuffer.ImportFrom( shapeWithClearance );
> + }
> + break;
> }
> }
>
> @@ -626,6 +664,7 @@
> {
> case PAD_CIRCLE:
> case PAD_OVAL:
> + case PAD_ROUNDRECT:
> TransformShapeWithClearanceToPolygon( aCornerBuffer, aInflateValue.x,
> aSegmentsPerCircle, aCorrectionFactor );
> break;
> @@ -1052,6 +1091,79 @@
> }
> break;
>
> + case PAD_ROUNDRECT:
> + {
> + std::vector <wxPoint> corners_buffer; // Polygon buffer as vector
> +
> + int dx = (aPad.GetSize().x / 2) + aThermalGap;
> + int dy = (aPad.GetSize().y / 2) + aThermalGap;
> +
> + // The first point of polygon buffer is left lower corner, second the crosspoint of
> + // thermal spoke sides, the third is upper right corner and the rest are rounding
> + // vertices going anticlockwise. Note the inveted Y-axis in CG.
> + corners_buffer.push_back( wxPoint( -dx, -(aThermalGap / 4 + copper_thickness.y / 2) ) ); // Adds small miters to zone
> + corners_buffer.push_back( wxPoint( -(dx - aThermalGap / 4), -copper_thickness.y / 2 ) ); // fill and spoke corner
> + corners_buffer.push_back( wxPoint( -copper_thickness.x / 2, -copper_thickness.y / 2 ) );
> + corners_buffer.push_back( wxPoint( -copper_thickness.x / 2, -(dy - aThermalGap / 4) ) );
> + corners_buffer.push_back( wxPoint( -(aThermalGap / 4 + copper_thickness.x / 2), -dy ) );
> +
> + int r = aPad.GetRoundRectCornerRadius();
> + // the center around which the round part of the thermal gap is drawn
> + wxPoint center = wxPoint( -(aPad.GetSize().x / 2 - r), -(aPad.GetSize().y / 2 - r) );
> +
> + corners_buffer.push_back( wxPoint( center.x, -dy ));
> +
> + for( int i = 1; i < aCircleToSegmentsCount / 4 + 1; i++ )
> + {
> + wxPoint corner_position = wxPoint( center.x, -dy );
> +
> + double angle_pg = i * delta;
> + RotatePoint( &corner_position, center, angle_pg );
> +
> + corners_buffer.push_back( wxPoint( corner_position.x, corner_position.y ) );
> + }
> +
> + double angle = aPad.GetOrientation();
> +
> + for( int irect = 0; irect < 2; irect++ )
> + {
> + for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
> + {
> + wxPoint cpos = corners_buffer[ic];
> + RotatePoint( &cpos, angle ); // Rotate according to module orientation
> + cpos += PadShapePos; // Shift origin to position
> + aCornerBuffer.Append( CPolyPt( cpos.x, cpos.y ) );
> + }
> +
> + aCornerBuffer.CloseLastContour();
> + angle = AddAngles( angle, 1800 ); // this is calculate hole 3
> + }
> +
> + // Create holes, that are the mirrored from the previous holes
> + for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
> + {
> + wxPoint swap = corners_buffer[ic];
> + swap.x = -swap.x;
> + corners_buffer[ic] = swap;
> + }
> +
> + // Now add corner 4 and 2 (2 is the corner 4 rotated by 180 deg
> + for( int irect = 0; irect < 2; irect++ )
> + {
> + for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
> + {
> + wxPoint cpos = corners_buffer[ic];
> + RotatePoint( &cpos, angle );
> + cpos += PadShapePos;
> + aCornerBuffer.Append( CPolyPt( cpos.x, cpos.y ) );
> + }
> +
> + aCornerBuffer.CloseLastContour();
> + angle = AddAngles( angle, 1800 );
> + }
> + }
> + break;
> +
> case PAD_TRAPEZOID:
> {
> CPOLYGONS_LIST cbuffer;
>
> === modified file 'pcbnew/class_pad.cpp'
> --- pcbnew/class_pad.cpp 2015-01-17 08:01:16 +0000
> +++ pcbnew/class_pad.cpp 2015-02-17 19:36:08 +0000
> @@ -141,6 +141,14 @@
> radius = 1 + KiROUND( hypot( x, y ) / 2 );
> break;
>
> + case PAD_ROUNDRECT:
> + radius = GetRoundRectCornerRadius( m_Size );
> + x = m_Size.x >> 1;
> + y = m_Size.y >> 1;
> + radius = 1 + KiROUND( EuclideanNorm( wxSize( x - radius, y - radius )))
> + + radius;
> + break;
> +
> default:
> radius = 0;
> }
> @@ -180,6 +188,7 @@
> break;
>
> case PAD_RECT:
> + case PAD_ROUNDRECT:
> //Use two corners and track their rotation
> // (utilise symmetry to avoid four points)
> quadrant1.x = m_Size.x/2;
> @@ -765,6 +774,30 @@
> return true;
>
> break;
> +
> + case PAD_ROUNDRECT:
> + {
> + // First check for hit in polygon
> + wxPoint poly[12];
> + int r = BuildPadPolygonRoundRect( poly, wxSize(0,0), 0 );
> + RotatePoint( &delta, -m_Orient );
> + if( TestPointInsidePolygon( poly, 12, delta ))
> + return true;
> + // Then check the rounded corners
> + delta = aPosition - shape_pos - poly[0];
> + if( KiROUND( EuclideanNorm( delta ) ) <= r )
> + return true;
> + delta = aPosition - shape_pos - poly[3];
> + if( KiROUND( EuclideanNorm( delta ) ) <= r )
> + return true;
> + delta = aPosition - shape_pos - poly[6];
> + if( KiROUND( EuclideanNorm( delta ) ) <= r )
> + return true;
> + delta = aPosition - shape_pos - poly[9];
> + if( KiROUND( EuclideanNorm( delta ) ) <= r )
> + return true;
> + }
> + break;
> }
>
> return false;
> @@ -848,6 +881,9 @@
> case PAD_TRAPEZOID:
> return _( "Trap" );
>
> + case PAD_ROUNDRECT:
> + return _( "Roundrect" );
> +
> default:
> return wxT( "???" );
> }
>
> === modified file 'pcbnew/class_pad.h'
> --- pcbnew/class_pad.h 2015-01-17 08:01:16 +0000
> +++ pcbnew/class_pad.h 2015-02-17 19:36:08 +0000
> @@ -283,6 +283,27 @@
> void BuildPadPolygon( wxPoint aCoord[4], wxSize aInflateValue, double aRotation ) const;
>
> /**
> + * Function BuildPadPolygonRoundRect
> + * Has meaning only for rounded rect pads
> + * Build the Corner list of the polygonal center shape,
> + * depending on shape, extra size (clearance ...) and orientation
> + * @param aCoord = a buffer to fill (12 corners).
> + * @param aInflateValue = wxSize: the clearance or margin value. value > 0:
> + * inflate, < 0 deflate
> + * @param aRotation = full rotation of the polygon
> + * @return Radius of the rounded corner arcs
> + */
> + int BuildPadPolygonRoundRect( wxPoint aCoord[12], wxSize aInflateValue, double aRotation ) const;
> +
> + /**
> + * Function GetRoundRectCornerRadius
> + * Has meaning only for rounded rect pads
> + * Returns the radius of the rounded corners for this pad.
> + * @return The radius of the rounded corners for this pad.
> + */
> + int GetRoundRectCornerRadius() const;
> +
> + /**
> * Function BuildPadShapePolygon
> * Build the Corner list of the polygonal shape,
> * depending on shape, extra size (clearance ...) pad and orientation
> @@ -466,6 +487,18 @@
>
> private:
> /**
> + * Private helper function BuildPadPolygonRoundRect
> + * Has meaning only for rounded rect pads
> + * Build the Corner list of the non-rotated polygonal center shape
> + * @param aCoord = a buffer to fill (12 corners).
> + * @param size Size of shape to build
> + * @return Radius of the rounded corner arcs
> + */
> + int BuildPadPolygonRoundRect( wxPoint aCoord[12], wxSize size ) const;
> +
> + int GetRoundRectCornerRadius( wxSize size ) const;
> +
> + /**
> * Function boundingRadius
> * returns a calculated radius of a bounding circle for this pad.
> */
> @@ -485,7 +518,7 @@
>
> wxPoint m_Pos; ///< pad Position on board
>
> - PAD_SHAPE_T m_padShape; ///< Shape: PAD_CIRCLE, PAD_RECT, PAD_OVAL, PAD_TRAPEZOID
> + PAD_SHAPE_T m_padShape; ///< Shape: PAD_CIRCLE, PAD_RECT, PAD_OVAL, PAD_TRAPEZOID, PAD_ROUNDRECT
>
>
> int m_SubRatsnest; ///< variable used in rats nest computations
>
> === modified file 'pcbnew/class_pad_draw_functions.cpp'
> --- pcbnew/class_pad_draw_functions.cpp 2015-01-10 10:27:49 +0000
> +++ pcbnew/class_pad_draw_functions.cpp 2015-02-17 19:36:08 +0000
> @@ -311,9 +311,10 @@
>
> void D_PAD::DrawShape( EDA_RECT* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
> {
> - wxPoint coord[4];
> + wxPoint coord[12];
> double angle = m_Orient;
> int seg_width;
> + int r;
>
> GRSetDrawMode( aDC, aDrawInfo.m_DrawMode );
>
> @@ -397,6 +398,86 @@
> }
> break;
>
> + case PAD_ROUNDRECT:
> + r = BuildPadPolygonRoundRect( coord, aDrawInfo.m_Mask_margin, angle );
> +
> + for( int ii = 0; ii < 12; ii++ )
> + coord[ii] += shape_pos;
> +
> + if( aDrawInfo.m_ShowPadFilled )
> + {
> + GRClosedPoly( aClipBox, aDC, 12, coord, true, 0,
> + aDrawInfo.m_Color, aDrawInfo.m_Color );
> + }
> + else
> + {
> + for( int ii = 1; ii < 12; ii += 3 )
> + {
> + GRLine( aClipBox, aDC, coord[ii].x, coord[ii].y,
> + coord[ii + 1].x, coord[ii + 1].y, 0,
> + aDrawInfo.m_Color );
> + }
> + }
> + if( aDrawInfo.m_ShowPadFilled )
> + {
> + GRFilledArc( aClipBox, aDC, coord[0].x, coord[0].y,
> + 900.0 - angle, 1800.0 - angle, r,
> + aDrawInfo.m_Color, aDrawInfo.m_Color );
> + GRFilledArc( aClipBox, aDC, coord[3].x, coord[3].y,
> + 0.0 - angle, 900.0 - angle, r,
> + aDrawInfo.m_Color, aDrawInfo.m_Color );
> + GRFilledArc( aClipBox, aDC, coord[6].x, coord[6].y,
> + 2700.0 - angle, 0.0 - angle, r,
> + aDrawInfo.m_Color, aDrawInfo.m_Color );
> + GRFilledArc( aClipBox, aDC, coord[9].x, coord[9].y,
> + 1800.0 - angle, 2700.0 - angle, r,
> + aDrawInfo.m_Color, aDrawInfo.m_Color );
> + }
> + else
> + {
> + GRArc( aClipBox, aDC, coord[0].x, coord[0].y,
> + 900.0 - angle, 1800.0 - angle, r,
> + m_PadSketchModePenSize, aDrawInfo.m_Color );
> + GRArc( aClipBox, aDC, coord[3].x, coord[3].y,
> + 0.0 - angle, 900.0 - angle, r,
> + m_PadSketchModePenSize, aDrawInfo.m_Color );
> + GRArc( aClipBox, aDC, coord[6].x, coord[6].y,
> + 2700.0 - angle, 0.0 - angle, r,
> + m_PadSketchModePenSize, aDrawInfo.m_Color );
> + GRArc( aClipBox, aDC, coord[9].x, coord[9].y,
> + 1800.0 - angle, 2700.0 - angle, r,
> + m_PadSketchModePenSize, aDrawInfo.m_Color );
> + }
> +
> + if( aDrawInfo.m_PadClearance )
> + {
> + r = BuildPadPolygonRoundRect( coord, wxSize( aDrawInfo.m_PadClearance,
> + aDrawInfo.m_PadClearance ),
> + angle );
> + for( int ii = 0; ii < 12; ii++ )
> + coord[ii] += shape_pos;
> +
> + for( int ii = 1; ii < 12; ii += 3 )
> + {
> + GRLine( aClipBox, aDC, coord[ii].x, coord[ii].y,
> + coord[ii + 1].x, coord[ii + 1].y, 0,
> + aDrawInfo.m_Color );
> + }
> + GRArc( aClipBox, aDC, coord[0].x, coord[0].y,
> + 900.0 - angle, 1800.0 - angle, r,
> + 0, aDrawInfo.m_Color );
> + GRArc( aClipBox, aDC, coord[3].x, coord[3].y,
> + 0.0 - angle, 900.0 - angle, r,
> + 0, aDrawInfo.m_Color );
> + GRArc( aClipBox, aDC, coord[6].x, coord[6].y,
> + 2700.0 - angle, 0.0 - angle, r,
> + 0, aDrawInfo.m_Color );
> + GRArc( aClipBox, aDC, coord[9].x, coord[9].y,
> + 1800.0 - angle, 2700.0 - angle, r,
> + 0, aDrawInfo.m_Color );
> + }
> + break;
> +
> default:
> break;
> }
> @@ -759,3 +840,140 @@
> RotatePoint( &aCoord[ii], aRotation );
> }
> }
> +
> +int D_PAD::BuildPadPolygonRoundRect( wxPoint aCoord[12], wxSize aInflateValue,
> + double aRotation ) const
> +{
> + int r;
> +
> + /*
> + * There are three cases here:
> + *
> + * 1. aInflateValue.x == ainflateValue.y == 0
> + *
> + * This means the actual pad polygon is build.
> + *
> + * 2. aInflateValue.x == ainflateValue.y and both > 0
> + *
> + * This means the clearance polygon is build.
> + *
> + * 3. aInflateValue.x < 0 && ainflateValue.y < 0 but *.x and *.y may differ
> + *
> + * This means the paste polygon is build.
> + *
> + * Other cases are not supported (and can't happen as far as I see).
> + */
> +
> + if( aInflateValue.x == 0 ) // case 1
> + {
> + r = BuildPadPolygonRoundRect( aCoord, m_Size );
> + }
> + else if( aInflateValue.x > 0 ) // case 2
> + {
> + r = BuildPadPolygonRoundRect( aCoord, m_Size );
> +
> + // inflate the polygon and correct the corner radius
> + // this makes sure the distance between pad and clearance polygons
> + // is the same everywhere
> + aCoord[1].y += aInflateValue.y;
> + aCoord[2].y += aInflateValue.y;
> + aCoord[4].x += aInflateValue.x;
> + aCoord[5].x += aInflateValue.x;
> + aCoord[7].y -= aInflateValue.y;
> + aCoord[8].y -= aInflateValue.y;
> + aCoord[10].x -= aInflateValue.x;
> + aCoord[11].x -= aInflateValue.x;
> + r += aInflateValue.x;
> + }
> + else // case 3
> + {
> + // because inflation (actually shrinkage) may be asymmetrical here
> + // equal distance between pad and solder paste can't be done
> + // looks good enough anyway
> + r = BuildPadPolygonRoundRect( aCoord, m_Size + aInflateValue );
> + }
> +
> + // Finally rotate the polygon
> +
> + if( aRotation )
> + {
> + for( int ii = 0; ii < 12; ii++ )
> + RotatePoint( &aCoord[ii], aRotation );
> + }
> +
> + return r;
> +}
> +
> +int D_PAD::BuildPadPolygonRoundRect( wxPoint aCoord[12], wxSize size ) const
> +{
> + wxSize halfsize;
> + int r;
> +
> + halfsize.x = size.x >> 1;
> + halfsize.y = size.y >> 1;
> +
> + r = GetRoundRectCornerRadius( size );
> +
> + /*
> + * The unrotated pad polygon for PAD_ROUNDRECT looks like this:
> + *
> + * 1 2
> + * +----+
> + * 0| |3
> + * 11+--+ +--+4
> + * | |
> + * | |
> + * 10+--+ +--+5
> + * 9| |6
> + * +----+
> + * 8 7
> + *
> + * The centers of the rounded corner arcs are at 0, 3, 6 and 9
> + * DO NOT CHANGE THAT, callers depend on it
> + *
> + */
> + aCoord[0].x = -halfsize.x + r;
> + aCoord[0].y = +halfsize.y - r;
> + aCoord[1].x = -halfsize.x + r;
> + aCoord[1].y = +halfsize.y;
> + aCoord[2].x = +halfsize.x - r;
> + aCoord[2].y = +halfsize.y;
> + aCoord[3].x = +halfsize.x - r;
> + aCoord[3].y = +halfsize.y - r;
> + aCoord[4].x = +halfsize.x;
> + aCoord[4].y = +halfsize.y - r;
> + aCoord[5].x = +halfsize.x;
> + aCoord[5].y = -halfsize.y + r;
> + aCoord[6].x = +halfsize.x - r;
> + aCoord[6].y = -halfsize.y + r;
> + aCoord[7].x = +halfsize.x - r;
> + aCoord[7].y = -halfsize.y;
> + aCoord[8].x = -halfsize.x + r;
> + aCoord[8].y = -halfsize.y;
> + aCoord[9].x = -halfsize.x + r;
> + aCoord[9].y = -halfsize.y + r;
> + aCoord[10].x = -halfsize.x;
> + aCoord[10].y = -halfsize.y + r;
> + aCoord[11].x = -halfsize.x;
> + aCoord[11].y = +halfsize.y - r;
> +
> + return r;
> +}
> +
> +int D_PAD::GetRoundRectCornerRadius( wxSize size ) const
> +{
> + // radius of rounded corners, fixed 25% of shorter pad edge for now
> + int r = size.x > size.y ? (size.y >> 2) : (size.x >> 2);
> + // but not more than 0.25 mm
> + if ( r > 250000 )
> + {
> + r = 250000;
> + }
> +
> + return r;
> +}
> +
> +int D_PAD::GetRoundRectCornerRadius() const
> +{
> + return GetRoundRectCornerRadius( m_Size );
> +}
>
> === modified file 'pcbnew/dialogs/dialog_pad_properties.cpp'
> --- pcbnew/dialogs/dialog_pad_properties.cpp 2014-11-19 18:39:02 +0000
> +++ pcbnew/dialogs/dialog_pad_properties.cpp 2015-02-17 19:36:08 +0000
> @@ -55,7 +55,8 @@
> PAD_CIRCLE,
> PAD_OVAL,
> PAD_RECT,
> - PAD_TRAPEZOID
> + PAD_TRAPEZOID,
> + PAD_ROUNDRECT
> };
>
>
> @@ -512,6 +513,10 @@
> case PAD_TRAPEZOID:
> m_PadShape->SetSelection( 3 );
> break;
> +
> + case PAD_ROUNDRECT:
> + m_PadShape->SetSelection( 4 );
> + break;
> }
>
> msg.Printf( wxT( "%g" ), angle );
> @@ -592,6 +597,14 @@
> m_ShapeOffset_X_Ctrl->Enable( true );
> m_ShapeOffset_Y_Ctrl->Enable( true );
> break;
> +
> + case 4: // PAD_ROUNDRECT:
> + m_ShapeDelta_Ctrl->Enable( false );
> + m_trapDeltaDirChoice->Enable( false );
> + m_ShapeSize_Y_Ctrl->Enable( true );
> + m_ShapeOffset_X_Ctrl->Enable( true );
> + m_ShapeOffset_Y_Ctrl->Enable( true );
> + break;
> }
>
> transferDataToPad( m_dummyPad );
> @@ -1126,6 +1139,10 @@
> case PAD_TRAPEZOID:
> break;
>
> + case PAD_ROUNDRECT:
> + aPad->SetDelta( wxSize( 0, 0 ) );
> + break;
> +
> default:
> ;
> }
>
> === modified file 'pcbnew/dialogs/dialog_pad_properties_base.cpp'
> --- pcbnew/dialogs/dialog_pad_properties_base.cpp 2015-01-10 10:27:49 +0000
> +++ pcbnew/dialogs/dialog_pad_properties_base.cpp 2015-02-17 19:36:08 +0000
> @@ -65,10 +65,10 @@
> m_staticText45->Wrap( -1 );
> fgSizerPadType->Add( m_staticText45, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxTOP, 5 );
>
> - wxString m_PadShapeChoices[] = { _("Circular"), _("Oval"), _("Rectangular"), _("Trapezoidal") };
> + wxString m_PadShapeChoices[] = { _("Circular"), _("Oval"), _("Rectangular"), _("Trapezoidal"), _("Rounded Rectangle") };
> int m_PadShapeNChoices = sizeof( m_PadShapeChoices ) / sizeof( wxString );
> m_PadShape = new wxChoice( m_panelGeneral, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_PadShapeNChoices, m_PadShapeChoices, 0 );
> - m_PadShape->SetSelection( 0 );
> + m_PadShape->SetSelection( 4 );
> fgSizerPadType->Add( m_PadShape, 0, wxALIGN_CENTER_VERTICAL|wxALL|wxEXPAND, 5 );
>
>
>
> === modified file 'pcbnew/dialogs/dialog_pad_properties_base.fbp'
> --- pcbnew/dialogs/dialog_pad_properties_base.fbp 2015-01-10 10:27:49 +0000
> +++ pcbnew/dialogs/dialog_pad_properties_base.fbp 2015-02-17 19:36:08 +0000
> @@ -271,16 +271,16 @@
> <property name="border">5</property>
> <property name="flag">wxALL|wxEXPAND</property>
> <property name="proportion">3</property>
> - <object class="wxBoxSizer" expanded="0">
> + <object class="wxBoxSizer" expanded="1">
> <property name="minimum_size"></property>
> <property name="name">m_LeftBoxSizer</property>
> <property name="orient">wxVERTICAL</property>
> <property name="permission">none</property>
> - <object class="sizeritem" expanded="0">
> + <object class="sizeritem" expanded="1">
> <property name="border">5</property>
> <property name="flag">wxEXPAND|wxTOP|wxRIGHT|wxLEFT</property>
> <property name="proportion">0</property>
> - <object class="wxFlexGridSizer" expanded="0">
> + <object class="wxFlexGridSizer" expanded="1">
> <property name="cols">2</property>
> <property name="flexible_direction">wxBOTH</property>
> <property name="growablecols">1</property>
> @@ -912,7 +912,7 @@
> <property name="caption"></property>
> <property name="caption_visible">1</property>
> <property name="center_pane">0</property>
> - <property name="choices">"Circular" "Oval" "Rectangular" "Trapezoidal"</property>
> + <property name="choices">"Circular" "Oval" "Rectangular" "Trapezoidal" "Rounded Rectangle"</property>
> <property name="close_button">1</property>
> <property name="context_help"></property>
> <property name="context_menu">1</property>
> @@ -942,7 +942,7 @@
> <property name="pin_button">1</property>
> <property name="pos"></property>
> <property name="resize">Resizable</property>
> - <property name="selection">0</property>
> + <property name="selection">4</property>
> <property name="show">1</property>
> <property name="size"></property>
> <property name="style"></property>
>
> === modified file 'pcbnew/drc_clearance_test_functions.cpp'
> --- pcbnew/drc_clearance_test_functions.cpp 2014-06-25 17:01:50 +0000
> +++ pcbnew/drc_clearance_test_functions.cpp 2015-02-17 19:36:08 +0000
> @@ -595,6 +595,11 @@
>
> double pad_angle;
>
> + /*
> + * FIXME: MGri - for now treat PAD_ROUNDRECT like PAD_RECT
> + * This is suboptimal, around the corners clearance will be too large
> + */
> +
> // Get the clerance between the 2 pads. this is the min distance between aRefPad and aPad
> int dist_min = aRefPad->GetClearance( aPad );
>
> @@ -621,7 +626,7 @@
> // priority is aRefPad = ROUND then OVAL then RECT then other
> if( aRefPad->GetShape() != aPad->GetShape() && aRefPad->GetShape() != PAD_CIRCLE )
> {
> - // pad ref shape is here oval, rect or trapezoid
> + // pad ref shape is here oval, rect, roundrect or trapezoid
> switch( aPad->GetShape() )
> {
> case PAD_CIRCLE:
> @@ -633,6 +638,7 @@
> break;
>
> case PAD_RECT:
> + case PAD_ROUNDRECT: // FIXME: MGri - is this correct?
> if( aRefPad->GetShape() != PAD_OVAL )
> swap_pads = true;
> break;
> @@ -672,11 +678,12 @@
> break;
>
> case PAD_RECT:
> + case PAD_ROUNDRECT: // FIXME: MGri - not optimal, could go closer to round corners
> // pad_angle = pad orient relative to the aRefPad orient
> pad_angle = aRefPad->GetOrientation() + aPad->GetOrientation();
> NORMALIZE_ANGLE_POS( pad_angle );
>
> - if( aPad->GetShape() == PAD_RECT )
> + if( aPad->GetShape() == PAD_RECT || aPad->GetShape() == PAD_ROUNDRECT )
> {
> wxSize size = aPad->GetSize();
>
> @@ -708,8 +715,15 @@
> { // Use the trapezoid2trapezoidDRC which also compare 2 rectangles with any orientation
> wxPoint polyref[4]; // Shape of aRefPad
> wxPoint polycompare[4]; // Shape of aPad
> - aRefPad->BuildPadPolygon( polyref, wxSize( 0, 0 ), aRefPad->GetOrientation() );
> - aPad->BuildPadPolygon( polycompare, wxSize( 0, 0 ), aPad->GetOrientation() );
> +
> + // FIXME: MGri - Nasty hack here...
> + D_PAD p(*aPad);
> + p.SetShape( PAD_RECT );
> + D_PAD rp(*aRefPad);
> + rp.SetShape( PAD_RECT );
> +
> + rp.BuildPadPolygon( polyref, wxSize( 0, 0 ), rp.GetOrientation() );
> + p.BuildPadPolygon( polycompare, wxSize( 0, 0 ), p.GetOrientation() );
>
> // Move aPad shape to relativePadPos
> for( int ii = 0; ii < 4; ii++ )
> @@ -828,6 +842,7 @@
> wxPoint startPoint, endPoint;
> int seuil;
> int deltay;
> + int r;
>
> int segmHalfWidth = aSegmentWidth / 2;
>
> @@ -992,6 +1007,66 @@
>
> break;
>
> + case PAD_ROUNDRECT:
> + /* Test du rectangle dimx + seuil, dimy */
> + m_xcliplo = m_padToTestPos.x - padHalfsize.x - seuil;
> + m_ycliplo = m_padToTestPos.y - padHalfsize.y;
> + m_xcliphi = m_padToTestPos.x + padHalfsize.x + seuil;
> + m_ycliphi = m_padToTestPos.y + padHalfsize.y;
> +
> + if( !checkLine( startPoint, endPoint ) )
> + return false;
> +
> + /* Test du rectangle dimx , dimy + seuil */
> + m_xcliplo = m_padToTestPos.x - padHalfsize.x;
> + m_ycliplo = m_padToTestPos.y - padHalfsize.y - seuil;
> + m_xcliphi = m_padToTestPos.x + padHalfsize.x;
> + m_ycliphi = m_padToTestPos.y + padHalfsize.y + seuil;
> +
> + if( !checkLine( startPoint, endPoint ) )
> + return false;
> +
> + r = aPad->GetRoundRectCornerRadius();
> +
> + /* test des 4 cercles ( surface d'solation autour des sommets */
> + /* test du coin sup. gauche du pad */
> + startPoint.x = m_padToTestPos.x - padHalfsize.x + r;
> + startPoint.y = m_padToTestPos.y - padHalfsize.y + r;
> + RotatePoint( &startPoint, m_padToTestPos, orient );
> + RotatePoint( &startPoint, m_segmAngle );
> +
> + if( !checkMarginToCircle( startPoint, seuil + r, m_segmLength ) )
> + return false;
> +
> + /* test du coin sup. droit du pad */
> + startPoint.x = m_padToTestPos.x + padHalfsize.x - r;
> + startPoint.y = m_padToTestPos.y - padHalfsize.y + r;
> + RotatePoint( &startPoint, m_padToTestPos, orient );
> + RotatePoint( &startPoint, m_segmAngle );
> +
> + if( !checkMarginToCircle( startPoint, seuil + r, m_segmLength ) )
> + return false;
> +
> + /* test du coin inf. gauche du pad */
> + startPoint.x = m_padToTestPos.x - padHalfsize.x + r;
> + startPoint.y = m_padToTestPos.y + padHalfsize.y - r;
> + RotatePoint( &startPoint, m_padToTestPos, orient );
> + RotatePoint( &startPoint, m_segmAngle );
> +
> + if( !checkMarginToCircle( startPoint, seuil + r, m_segmLength ) )
> + return false;
> +
> + /* test du coin inf. droit du pad */
> + startPoint.x = m_padToTestPos.x + padHalfsize.x - r;
> + startPoint.y = m_padToTestPos.y + padHalfsize.y - r;
> + RotatePoint( &startPoint, m_padToTestPos, orient );
> + RotatePoint( &startPoint, m_segmAngle );
> +
> + if( !checkMarginToCircle( startPoint, seuil + r, m_segmLength ) )
> + return false;
> +
> + break;
> +
> case PAD_TRAPEZOID:
> {
> wxPoint poly[4];
>
> === modified file 'pcbnew/kicad_plugin.cpp'
> --- pcbnew/kicad_plugin.cpp 2015-02-17 18:47:21 +0000
> +++ pcbnew/kicad_plugin.cpp 2015-02-17 19:36:08 +0000
> @@ -1275,6 +1275,7 @@
> case PAD_RECT: shape = "rect"; break;
> case PAD_OVAL: shape = "oval"; break;
> case PAD_TRAPEZOID: shape = "trapezoid"; break;
> + case PAD_ROUNDRECT: shape = "roundrect"; break;
>
> default:
> THROW_IO_ERROR( wxString::Format( _( "unknown pad type: %d"), aPad->GetShape() ) );
>
> === modified file 'pcbnew/pcb_painter.cpp'
> --- pcbnew/pcb_painter.cpp 2015-01-10 10:27:49 +0000
> +++ pcbnew/pcb_painter.cpp 2015-02-17 19:36:08 +0000
> @@ -650,6 +650,44 @@
> m_gal->DrawRectangle( VECTOR2D( -size.x, -size.y ), VECTOR2D( size.x, size.y ) );
> break;
>
> + case PAD_ROUNDRECT:
> + {
> + std::deque<VECTOR2D> pointList;
> + wxPoint corners[12];
> +
> + VECTOR2D padSize = VECTOR2D( aPad->GetSize().x, aPad->GetSize().y ) / 2;
> + VECTOR2D deltaPadSize = size - padSize; // = solder[Paste/Mask]Margin or 0
> +
> + int r = aPad->BuildPadPolygonRoundRect( corners, wxSize( deltaPadSize.x, deltaPadSize.y ), 0.0 );
> +
> + if( m_pcbSettings.m_sketchMode[ITEM_GAL_LAYER( PADS_VISIBLE )] )
> + {
> + // Outline mode
> + m_gal->DrawLine( VECTOR2D( corners[1] ), VECTOR2D( corners[2] ) );
> + m_gal->DrawLine( VECTOR2D( corners[4] ), VECTOR2D( corners[5] ) );
> + m_gal->DrawLine( VECTOR2D( corners[7] ), VECTOR2D( corners[8] ) );
> + m_gal->DrawLine( VECTOR2D( corners[10] ), VECTOR2D( corners[11] ) );
> + m_gal->DrawArc( VECTOR2D( corners[0] ), r, M_PI / 2, M_PI );
> + m_gal->DrawArc( VECTOR2D( corners[3] ), r, 0, M_PI / 2 );
> + m_gal->DrawArc( VECTOR2D( corners[6] ), r, 3 * M_PI / 2, 2 * M_PI );
> + m_gal->DrawArc( VECTOR2D( corners[9] ), r, M_PI, 3 * M_PI / 2 );
> + }
> + else
> + {
> + // Filled mode
> + for( int ii = 0; ii < 12; ii++ )
> + {
> + pointList.push_back( VECTOR2D( corners[ii] ) );
> + }
> + m_gal->DrawPolygon( pointList );
> + m_gal->DrawArc( VECTOR2D( corners[0] ), r, M_PI / 2, M_PI );
> + m_gal->DrawArc( VECTOR2D( corners[3] ), r, 0, M_PI / 2 );
> + m_gal->DrawArc( VECTOR2D( corners[6] ), r, 3 * M_PI / 2, 2 * M_PI );
> + m_gal->DrawArc( VECTOR2D( corners[9] ), r, M_PI, 3 * M_PI / 2 );
> + }
> + break;
> + }
> +
> case PAD_TRAPEZOID:
> {
> std::deque<VECTOR2D> pointList;
>
> === modified file 'pcbnew/pcb_parser.cpp'
> --- pcbnew/pcb_parser.cpp 2015-02-17 18:47:21 +0000
> +++ pcbnew/pcb_parser.cpp 2015-02-17 19:36:08 +0000
> @@ -2213,8 +2213,12 @@
> pad->SetShape( PAD_TRAPEZOID );
> break;
>
> + case T_roundrect:
> + pad->SetShape( PAD_ROUNDRECT );
> + break;
> +
> default:
> - Expecting( "circle, rectangle, oval, or trapezoid" );
> + Expecting( "circle, rectangle, roundrect, oval, or trapezoid" );
> }
>
> for( token = NextTok(); token != T_RIGHT; token = NextTok() )
>
> === modified file 'pcbnew/plot_board_layers.cpp'
> --- pcbnew/plot_board_layers.cpp 2015-02-02 08:06:39 +0000
> +++ pcbnew/plot_board_layers.cpp 2015-02-17 19:36:08 +0000
> @@ -380,6 +380,7 @@
> // Fall through:
> case PAD_TRAPEZOID:
> case PAD_RECT:
> + case PAD_ROUNDRECT:
> default:
> itemplotter.PlotPad( pad, color, plotMode );
> break;
>
> === modified file 'pcbnew/plot_brditems_plotter.cpp'
> --- pcbnew/plot_brditems_plotter.cpp 2015-02-02 08:06:39 +0000
> +++ pcbnew/plot_brditems_plotter.cpp 2015-02-17 19:36:08 +0000
> @@ -91,6 +91,15 @@
> }
> break;
>
> + case PAD_ROUNDRECT:
> + {
> + wxPoint coord[12];
> + int r = aPad->BuildPadPolygonRoundRect( coord, wxSize(0,0), 0 );
> + m_plotter->FlashPadRoundRect( shape_pos, coord, r,
> + aPad->GetOrientation(), aPlotMode );
> + }
> + break;
> +
> case PAD_RECT:
> default:
> m_plotter->FlashPadRect( shape_pos, aPad->GetSize(),
>
> === modified file 'pcbnew/router/pns_router.cpp'
> --- pcbnew/router/pns_router.cpp 2014-11-27 10:51:16 +0000
> +++ pcbnew/router/pns_router.cpp 2015-02-17 19:36:08 +0000
> @@ -205,6 +205,11 @@
> solid->SetShape( new SHAPE_RECT( c - sz / 2, sz.x, sz.y ) );
> break;
>
> + case PAD_ROUNDRECT:
> + // FIXME: not optimal and the optical effect is confusing
> + solid->SetShape( new SHAPE_RECT( c - sz / 2, sz.x, sz.y ) );
> + break;
> +
> default:
> TRACEn( 0, "unsupported pad shape" );
> delete solid;
>
> === modified file 'pcbnew/specctra_export.cpp'
> --- pcbnew/specctra_export.cpp 2015-02-17 18:47:21 +0000
> +++ pcbnew/specctra_export.cpp 2015-02-17 19:36:08 +0000
> @@ -477,6 +477,7 @@
> break;
>
> case PAD_RECT:
> + case PAD_ROUNDRECT: // Does Specctra know round rects?
> {
> double dx = scale( aPad->GetSize().x ) / 2.0;
> double dy = scale( aPad->GetSize().y ) / 2.0;
>
>
> _______________________________________________
> 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
>
References