Gerber plotter: plot round rectangle pads using a region with arcs.
Previously, the region was a usual polygon with arc approximated by segment. Using a region with arcs is a better way because it allows CAM tools to identify this region as a round-rect pad. A side effect is a better shape and smaller files, however not really noticeable in fact.
This commit is contained in:
parent
ba8c3a5582
commit
9cb3333d05
|
@ -520,10 +520,23 @@ void GERBER_PLOTTER::Arc( const wxPoint& aCenter, double aStAngle, double aEndAn
|
||||||
{
|
{
|
||||||
SetCurrentLineWidth( aWidth );
|
SetCurrentLineWidth( aWidth );
|
||||||
|
|
||||||
|
// aFill is not used here.
|
||||||
|
plotArc( aCenter, aStAngle, aEndAngle, aRadius, false );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GERBER_PLOTTER::plotArc( const wxPoint& aCenter, double aStAngle, double aEndAngle,
|
||||||
|
int aRadius, bool aPlotInRegion )
|
||||||
|
{
|
||||||
wxPoint start, end;
|
wxPoint start, end;
|
||||||
start.x = aCenter.x + KiROUND( cosdecideg( aRadius, aStAngle ) );
|
start.x = aCenter.x + KiROUND( cosdecideg( aRadius, aStAngle ) );
|
||||||
start.y = aCenter.y - KiROUND( sindecideg( aRadius, aStAngle ) );
|
start.y = aCenter.y - KiROUND( sindecideg( aRadius, aStAngle ) );
|
||||||
|
|
||||||
|
if( !aPlotInRegion )
|
||||||
MoveTo( start );
|
MoveTo( start );
|
||||||
|
else
|
||||||
|
LineTo( start );
|
||||||
|
|
||||||
end.x = aCenter.x + KiROUND( cosdecideg( aRadius, aEndAngle ) );
|
end.x = aCenter.x + KiROUND( cosdecideg( aRadius, aEndAngle ) );
|
||||||
end.y = aCenter.y - KiROUND( sindecideg( aRadius, aEndAngle ) );
|
end.y = aCenter.y - KiROUND( sindecideg( aRadius, aEndAngle ) );
|
||||||
DPOINT devEnd = userToDeviceCoordinates( end );
|
DPOINT devEnd = userToDeviceCoordinates( end );
|
||||||
|
@ -855,16 +868,14 @@ void GERBER_PLOTTER::FlashPadRect( const wxPoint& pos, const wxSize& aSize,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: // plot pad shape as polygon
|
default: // plot pad shape as Gerber region
|
||||||
{
|
{
|
||||||
// XXX to do: use an aperture macro to declare the rotated pad
|
|
||||||
wxPoint coord[4];
|
wxPoint coord[4];
|
||||||
// coord[0] is assumed the lower left
|
// coord[0] is assumed the lower left
|
||||||
// coord[1] is assumed the upper left
|
// coord[1] is assumed the upper left
|
||||||
// coord[2] is assumed the upper right
|
// coord[2] is assumed the upper right
|
||||||
// coord[3] is assumed the lower right
|
// coord[3] is assumed the lower right
|
||||||
|
|
||||||
/* Trace the outline. */
|
|
||||||
coord[0].x = -size.x/2; // lower left
|
coord[0].x = -size.x/2; // lower left
|
||||||
coord[0].y = size.y/2;
|
coord[0].y = size.y/2;
|
||||||
coord[1].x = -size.x/2; // upper left
|
coord[1].x = -size.x/2; // upper left
|
||||||
|
@ -887,17 +898,14 @@ void GERBER_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aS
|
||||||
{
|
{
|
||||||
GBR_METADATA* gbr_metadata = static_cast<GBR_METADATA*>( aData );
|
GBR_METADATA* gbr_metadata = static_cast<GBR_METADATA*>( aData );
|
||||||
|
|
||||||
// Currently, a Pad RoundRect is plotted as polygon.
|
if( aTraceMode != FILLED )
|
||||||
// TODO: use Aperture macro and flash it
|
{
|
||||||
SHAPE_POLY_SET outline;
|
SHAPE_POLY_SET outline;
|
||||||
TransformRoundChamferedRectToPolygon( outline, aPadPos, aSize, aOrient,
|
TransformRoundChamferedRectToPolygon( outline, aPadPos, aSize, aOrient,
|
||||||
aCornerRadius, 0.0, 0, GetPlotterArcHighDef() );
|
aCornerRadius, 0.0, 0, GetPlotterArcHighDef() );
|
||||||
|
|
||||||
if( aTraceMode != FILLED )
|
|
||||||
{
|
|
||||||
SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH, &gbr_metadata );
|
SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH, &gbr_metadata );
|
||||||
outline.Inflate( -GetCurrentLineWidth()/2, 16 );
|
outline.Inflate( -GetCurrentLineWidth()/2, 16 );
|
||||||
}
|
|
||||||
|
|
||||||
std::vector< wxPoint > cornerList;
|
std::vector< wxPoint > cornerList;
|
||||||
// TransformRoundRectToPolygon creates only one convex polygon
|
// TransformRoundRectToPolygon creates only one convex polygon
|
||||||
|
@ -910,11 +918,151 @@ void GERBER_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aS
|
||||||
// Close polygon
|
// Close polygon
|
||||||
cornerList.push_back( cornerList[0] );
|
cornerList.push_back( cornerList[0] );
|
||||||
|
|
||||||
if( aTraceMode == SKETCH )
|
// plot outlines
|
||||||
PlotPoly( cornerList, NO_FILL, GetCurrentLineWidth(), gbr_metadata );
|
PlotPoly( cornerList, NO_FILL, GetCurrentLineWidth(), gbr_metadata );
|
||||||
else
|
|
||||||
PlotGerberRegion( cornerList, gbr_metadata );
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// A Pad RoundRect is plotted as a Gerber region.
|
||||||
|
// Initialize region metadata:
|
||||||
|
bool clearTA_AperFunction = false; // true if a TA.AperFunction is used
|
||||||
|
|
||||||
|
if( gbr_metadata )
|
||||||
|
{
|
||||||
|
formatNetAttribute( &gbr_metadata->m_NetlistMetadata );
|
||||||
|
std::string attrib = gbr_metadata->m_ApertureMetadata.FormatAttribute( !m_useX2format );
|
||||||
|
|
||||||
|
if( !attrib.empty() )
|
||||||
|
{
|
||||||
|
fputs( attrib.c_str(), outputFile );
|
||||||
|
clearTA_AperFunction = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plot the region using arcs in corners.
|
||||||
|
plotRoundRectAsRegion( aPadPos, aSize, aCornerRadius, aOrient );
|
||||||
|
|
||||||
|
// Clear the TA attribute, to avoid the next item to inherit it:
|
||||||
|
if( clearTA_AperFunction )
|
||||||
|
{
|
||||||
|
if( m_useX2format )
|
||||||
|
{
|
||||||
|
fputs( "%TD.AperFunction*%\n", outputFile );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fputs( "G04 #@! TD.AperFunction*\n", outputFile );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GERBER_PLOTTER::plotRoundRectAsRegion( const wxPoint& aRectCenter, const wxSize& aSize,
|
||||||
|
int aCornerRadius, double aOrient )
|
||||||
|
{
|
||||||
|
// The region outline is generated by 4 sides and 4 90 deg arcs
|
||||||
|
// 1 --- 2
|
||||||
|
// | c |
|
||||||
|
// 4 --- 3
|
||||||
|
|
||||||
|
// Note also in user coordinates the Y axis is from top to bottom
|
||||||
|
// for historical reasons.
|
||||||
|
|
||||||
|
// A helper structure to handle outlines coordinates (segments and arcs)
|
||||||
|
// in user coordinates
|
||||||
|
struct RR_EDGE
|
||||||
|
{
|
||||||
|
wxPoint m_start;
|
||||||
|
wxPoint m_end;
|
||||||
|
wxPoint m_center;
|
||||||
|
// in decidegrees: angle start. angle end = m_arc_angle_start+arc_angle
|
||||||
|
double m_arc_angle_start;
|
||||||
|
};
|
||||||
|
|
||||||
|
const double arc_angle = -900.0; // in decidegrees
|
||||||
|
int hsizeX = aSize.x/2;
|
||||||
|
int hsizeY = aSize.y/2;
|
||||||
|
|
||||||
|
RR_EDGE curr_edge;
|
||||||
|
std::vector<RR_EDGE> rr_outline;
|
||||||
|
|
||||||
|
// Build outline coordinates, relative to rectangle center, rotation 0:
|
||||||
|
|
||||||
|
// Top left corner 1 (and 4 to 1 left vertical side @ x=-hsizeX)
|
||||||
|
curr_edge.m_start.x = -hsizeX;
|
||||||
|
curr_edge.m_start.y = hsizeY - aCornerRadius;
|
||||||
|
curr_edge.m_end.x = curr_edge.m_start.x;
|
||||||
|
curr_edge.m_end.y = -hsizeY + aCornerRadius;
|
||||||
|
curr_edge.m_center.x = -hsizeX + aCornerRadius;
|
||||||
|
curr_edge.m_center.y = curr_edge.m_end.y;
|
||||||
|
curr_edge.m_arc_angle_start = aOrient + 1800.0; // En decidegree
|
||||||
|
|
||||||
|
rr_outline.push_back( curr_edge );
|
||||||
|
|
||||||
|
// Top right corner 2 (and 1 to 2 top horizontal side @ y=-hsizeY)
|
||||||
|
curr_edge.m_start.x = -hsizeX + aCornerRadius;
|
||||||
|
curr_edge.m_start.y = -hsizeY;
|
||||||
|
curr_edge.m_end.x = hsizeX - aCornerRadius;
|
||||||
|
curr_edge.m_end.y = curr_edge.m_start.y;
|
||||||
|
curr_edge.m_center.x = curr_edge.m_end.x;
|
||||||
|
curr_edge.m_center.y = -hsizeY + aCornerRadius;
|
||||||
|
curr_edge.m_arc_angle_start = aOrient + 900.0; // En decidegree
|
||||||
|
|
||||||
|
rr_outline.push_back( curr_edge );
|
||||||
|
|
||||||
|
// bottom right corner 3 (and 2 to 3 right vertical side @ x=hsizeX)
|
||||||
|
curr_edge.m_start.x = hsizeX;
|
||||||
|
curr_edge.m_start.y = -hsizeY + aCornerRadius;
|
||||||
|
curr_edge.m_end.x = curr_edge.m_start.x;
|
||||||
|
curr_edge.m_end.y = hsizeY - aCornerRadius;
|
||||||
|
curr_edge.m_center.x = hsizeX - aCornerRadius;
|
||||||
|
curr_edge.m_center.y = curr_edge.m_end.y;
|
||||||
|
curr_edge.m_arc_angle_start = aOrient + 0.0; // En decidegree
|
||||||
|
|
||||||
|
rr_outline.push_back( curr_edge );
|
||||||
|
|
||||||
|
// bottom left corner 4 (and 3 to 4 bottom horizontal side @ y=hsizeY)
|
||||||
|
curr_edge.m_start.x = hsizeX - aCornerRadius;
|
||||||
|
curr_edge.m_start.y = hsizeY;
|
||||||
|
curr_edge.m_end.x = -hsizeX + aCornerRadius;
|
||||||
|
curr_edge.m_end.y = curr_edge.m_start.y;
|
||||||
|
curr_edge.m_center.x = curr_edge.m_end.x;
|
||||||
|
curr_edge.m_center.y = hsizeY - aCornerRadius;
|
||||||
|
curr_edge.m_arc_angle_start = aOrient - 900.0; // En decidegree
|
||||||
|
|
||||||
|
rr_outline.push_back( curr_edge );
|
||||||
|
|
||||||
|
// Move relative coordinates to the actual location and rotation:
|
||||||
|
for( RR_EDGE& rr_edge: rr_outline )
|
||||||
|
{
|
||||||
|
RotatePoint( &rr_edge.m_start, aOrient );
|
||||||
|
RotatePoint( &rr_edge.m_end, aOrient );
|
||||||
|
RotatePoint( &rr_edge.m_center, aOrient );
|
||||||
|
rr_edge.m_start += aRectCenter;
|
||||||
|
rr_edge.m_end += aRectCenter;
|
||||||
|
rr_edge.m_center += aRectCenter;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs( "G36*\n", outputFile ); // Start region
|
||||||
|
fputs( "G01*\n", outputFile ); // Set linear interpolation.
|
||||||
|
MoveTo( rr_outline[0].m_start ); // Start point of region
|
||||||
|
|
||||||
|
for( RR_EDGE& rr_edge: rr_outline )
|
||||||
|
{
|
||||||
|
if( aCornerRadius ) // Guard: ensure we do not create arcs with radius = 0
|
||||||
|
{
|
||||||
|
// LineTo( rr_edge.m_end ); // made in plotArc()
|
||||||
|
plotArc( rr_edge.m_center, rr_edge.m_arc_angle_start, rr_edge.m_arc_angle_start+arc_angle,
|
||||||
|
aCornerRadius, true );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LineTo( rr_edge.m_end );
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs( "G37*\n", outputFile ); // Close region
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void GERBER_PLOTTER::FlashPadCustom( const wxPoint& aPadPos, const wxSize& aSize,
|
void GERBER_PLOTTER::FlashPadCustom( const wxPoint& aPadPos, const wxSize& aSize,
|
||||||
SHAPE_POLY_SET* aPolygons,
|
SHAPE_POLY_SET* aPolygons,
|
||||||
|
|
|
@ -1328,6 +1328,30 @@ public:
|
||||||
APERTURE::APERTURE_TYPE aType, int aApertureAttribute );
|
APERTURE::APERTURE_TYPE aType, int aApertureAttribute );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
/** Plot a round rect (a round rect shape in fact) as a Gerber region
|
||||||
|
* using lines and arcs for corners
|
||||||
|
* @param aRectCenter is the center of the rectangle
|
||||||
|
* @param aSize is the size of the rectangle
|
||||||
|
* @param aCornerRadius is the radius of the corners
|
||||||
|
* @param aOrient is the rotation of the rectangle
|
||||||
|
* Note: only the G36 ... G37 region is created.
|
||||||
|
*/
|
||||||
|
void plotRoundRectAsRegion( const wxPoint& aRectCenter, const wxSize& aSize,
|
||||||
|
int aCornerRadius, double aOrient );
|
||||||
|
/**
|
||||||
|
* Plot a Gerber arc.
|
||||||
|
* if aPlotInRegion = true, the current pen position will not be
|
||||||
|
* initialized to the arc start position, and therefore the arc can be used
|
||||||
|
* to define a region outline item
|
||||||
|
* a line will be created from current ^position to arc start point
|
||||||
|
* if aPlotInRegion = false, the current pen position will be initialized
|
||||||
|
* to the arc start position, to plot an usual arc item
|
||||||
|
* The line thickness is not initialized in plotArc, and must be initialized
|
||||||
|
* before calling it if needed.
|
||||||
|
*/
|
||||||
|
void plotArc( const wxPoint& aCenter, double aStAngle, double aEndAngle,
|
||||||
|
int aRadius, bool aPlotInRegion );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pick an existing aperture or create a new one, matching the
|
* Pick an existing aperture or create a new one, matching the
|
||||||
* size, type and attributes.
|
* size, type and attributes.
|
||||||
|
|
|
@ -792,6 +792,12 @@ void BRDITEMS_PLOTTER::PlotDrawSegment( DRAWSEGMENT* aSeg )
|
||||||
if( aSeg->GetLayer() == Edge_Cuts )
|
if( aSeg->GetLayer() == Edge_Cuts )
|
||||||
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_EDGECUT );
|
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_EDGECUT );
|
||||||
|
|
||||||
|
if( IsCopperLayer( aSeg->GetLayer() ) )
|
||||||
|
// Graphic items (DRAWSEGMENT, TEXT) having no net have the NonConductor attribute
|
||||||
|
// Graphic items having a net have the Conductor attribute, but are not (yet?)
|
||||||
|
// supported in Pcbnew
|
||||||
|
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_NONCONDUCTOR );
|
||||||
|
|
||||||
switch( aSeg->GetShape() )
|
switch( aSeg->GetShape() )
|
||||||
{
|
{
|
||||||
case S_CIRCLE:
|
case S_CIRCLE:
|
||||||
|
|
Loading…
Reference in New Issue