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 );
|
||||
|
||||
// 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;
|
||||
start.x = aCenter.x + KiROUND( cosdecideg( aRadius, aStAngle ) );
|
||||
start.y = aCenter.y - KiROUND( sindecideg( aRadius, aStAngle ) );
|
||||
|
||||
if( !aPlotInRegion )
|
||||
MoveTo( start );
|
||||
else
|
||||
LineTo( start );
|
||||
|
||||
end.x = aCenter.x + KiROUND( cosdecideg( aRadius, aEndAngle ) );
|
||||
end.y = aCenter.y - KiROUND( sindecideg( aRadius, aEndAngle ) );
|
||||
DPOINT devEnd = userToDeviceCoordinates( end );
|
||||
|
@ -855,16 +868,14 @@ void GERBER_PLOTTER::FlashPadRect( const wxPoint& pos, const wxSize& aSize,
|
|||
}
|
||||
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];
|
||||
// coord[0] is assumed the lower left
|
||||
// coord[1] is assumed the upper left
|
||||
// coord[2] is assumed the upper right
|
||||
// coord[3] is assumed the lower right
|
||||
|
||||
/* Trace the outline. */
|
||||
coord[0].x = -size.x/2; // lower left
|
||||
coord[0].y = size.y/2;
|
||||
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 );
|
||||
|
||||
// Currently, a Pad RoundRect is plotted as polygon.
|
||||
// TODO: use Aperture macro and flash it
|
||||
if( aTraceMode != FILLED )
|
||||
{
|
||||
SHAPE_POLY_SET outline;
|
||||
TransformRoundChamferedRectToPolygon( outline, aPadPos, aSize, aOrient,
|
||||
aCornerRadius, 0.0, 0, GetPlotterArcHighDef() );
|
||||
|
||||
if( aTraceMode != FILLED )
|
||||
{
|
||||
SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH, &gbr_metadata );
|
||||
outline.Inflate( -GetCurrentLineWidth()/2, 16 );
|
||||
}
|
||||
|
||||
std::vector< wxPoint > cornerList;
|
||||
// TransformRoundRectToPolygon creates only one convex polygon
|
||||
|
@ -910,12 +918,152 @@ void GERBER_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aS
|
|||
// Close polygon
|
||||
cornerList.push_back( cornerList[0] );
|
||||
|
||||
if( aTraceMode == SKETCH )
|
||||
// plot outlines
|
||||
PlotPoly( cornerList, NO_FILL, GetCurrentLineWidth(), gbr_metadata );
|
||||
}
|
||||
else
|
||||
PlotGerberRegion( cornerList, gbr_metadata );
|
||||
{
|
||||
// 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,
|
||||
SHAPE_POLY_SET* aPolygons,
|
||||
EDA_DRAW_MODE_T aTraceMode, void* aData )
|
||||
|
|
|
@ -1328,6 +1328,30 @@ public:
|
|||
APERTURE::APERTURE_TYPE aType, int aApertureAttribute );
|
||||
|
||||
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
|
||||
* size, type and attributes.
|
||||
|
|
|
@ -792,6 +792,12 @@ void BRDITEMS_PLOTTER::PlotDrawSegment( DRAWSEGMENT* aSeg )
|
|||
if( aSeg->GetLayer() == Edge_Cuts )
|
||||
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() )
|
||||
{
|
||||
case S_CIRCLE:
|
||||
|
|
Loading…
Reference in New Issue