Gerber plot: better handling of polygonal pad shapes plotting

update GBR_CMP_PNP_METADATA.
This commit is contained in:
jean-pierre charras 2019-10-06 13:39:50 +02:00
parent 36253450e7
commit 47f9c505c5
6 changed files with 139 additions and 116 deletions

View File

@ -590,6 +590,12 @@ wxString GBR_CMP_PNP_METADATA::FormatCmpPnPMetadata()
if( !m_Value.IsEmpty() )
text << start_of_line << "CVal," << m_Value << end_of_line;
if( !m_LibraryName.IsEmpty() )
text << start_of_line << "CLbN," << m_LibraryName << end_of_line;
if( !m_LibraryDescr.IsEmpty() )
text << start_of_line << "CLbD," << m_LibraryDescr << end_of_line;
text << start_of_line << "CMnt," << mounType[m_MountType] << end_of_line;
text << start_of_line << "CRot," << m_Orientation << end_of_line;

View File

@ -105,6 +105,17 @@ void GERBER_PLOTTER::emitDcode( const DPOINT& pt, int dcode )
KiROUND( pt.x ), KiROUND( pt.y ), dcode );
}
void GERBER_PLOTTER::ClearAllAttributes()
{
// Remove all attributes from object attributes dictionary (TO. and TA commands)
if( m_useX2format )
fputs( "%TD*%\n", outputFile );
else
fputs( "G04 #@! TD*\n", outputFile );
m_objectAttributesDictionnary.clear();
}
void GERBER_PLOTTER::clearNetAttribute()
{
@ -535,6 +546,43 @@ void GERBER_PLOTTER::Arc( const wxPoint& aCenter, double aStAngle, double aEndAn
}
void GERBER_PLOTTER::PlotGerberRegion( const std::vector< wxPoint >& aCornerList,
void * aData )
{
if( aCornerList.size() <= 2 )
return;
GBR_METADATA* gbr_metadata = static_cast<GBR_METADATA*>( aData );
bool clearTA_AperFunction = false; // true if a TA.AperFunction is used
if( gbr_metadata )
{
std::string attrib = gbr_metadata->m_ApertureMetadata.FormatAttribute( !m_useX2format );
if( !attrib.empty() )
{
fputs( attrib.c_str(), outputFile );
clearTA_AperFunction = true;
}
}
PlotPoly( aCornerList, FILLED_SHAPE, 0 , gbr_metadata );
// 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::PlotPoly( const std::vector< wxPoint >& aCornerList,
FILL_T aFill, int aWidth, void * aData )
{
@ -546,7 +594,8 @@ void GERBER_PLOTTER::PlotPoly( const std::vector< wxPoint >& aCornerList,
// one should plot outline as thick segments
GBR_METADATA* gbr_metadata = static_cast<GBR_METADATA*>( aData );
SetCurrentLineWidth( aWidth, gbr_metadata );
if( !aFill )
SetCurrentLineWidth( aWidth, gbr_metadata );
if( gbr_metadata )
formatNetAttribute( &gbr_metadata->m_NetlistMetadata );
@ -716,7 +765,7 @@ void GERBER_PLOTTER::FlashPadOval( const wxPoint& pos, const wxSize& aSize, doub
wxSize size( aSize );
GBR_METADATA* gbr_metadata = static_cast<GBR_METADATA*>( aData );
/* Plot a flashed shape. */
// Flash a vertical or horizontal shape (this is a basic aperture).
if( ( orient == 0 || orient == 900 || orient == 1800 || orient == 2700 )
&& trace_mode == FILLED )
{
@ -732,7 +781,7 @@ void GERBER_PLOTTER::FlashPadOval( const wxPoint& pos, const wxSize& aSize, doub
emitDcode( pos_dev, 3 );
}
else /* Plot pad as a segment. */
else // Plot pad as a segment.
{
if( size.x > size.y )
{
@ -747,10 +796,8 @@ void GERBER_PLOTTER::FlashPadOval( const wxPoint& pos, const wxSize& aSize, doub
if( trace_mode == FILLED )
{
// TODO: use an aperture macro to declare the rotated pad
// Flash a pad anchor, if a netlist attribute is set
if( aData )
FlashPadCircle( pos, size.x, trace_mode, aData );
// to be able to flash the shape
// For now, the pad is painted.
// The pad is reduced to an segment with dy > dx
int delta = size.y - size.x;
@ -766,14 +813,12 @@ void GERBER_PLOTTER::FlashPadOval( const wxPoint& pos, const wxSize& aSize, doub
{
metadata = *gbr_metadata;
// If the pad is drawn on a copper layer,
// set attribute to GBR_APERTURE_ATTRIB_CONDUCTOR
if( metadata.IsCopper() )
metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_CONDUCTOR );
#if 0 // See if one can use TO.P attribute in this case (only one segment to draw a pad)
// Clear .P attribute, only allowed for flashed items
// (not allowed for painted pads)
wxString attrname( ".P" );
metadata.m_NetlistMetadata.ClearAttribute( &attrname );
#endif
}
ThickSegment( wxPoint( pos.x + x0, pos.y + y0 ),
@ -861,22 +906,10 @@ void GERBER_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aS
EDA_DRAW_MODE_T aTraceMode, void* aData )
{
GBR_METADATA gbr_metadata;
GBR_METADATA* gbr_metadata;
if( aData )
{
gbr_metadata = *static_cast<GBR_METADATA*>( aData );
// If the pad is drawn on a copper layer,
// set attribute to GBR_APERTURE_ATTRIB_CONDUCTOR
if( gbr_metadata.IsCopper() )
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_CONDUCTOR );
wxString attrname( ".P" );
gbr_metadata.m_NetlistMetadata.ClearAttribute( &attrname ); // not allowed on inner layers
}
if( aTraceMode != FILLED )
SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH, &gbr_metadata );
gbr_metadata = static_cast<GBR_METADATA*>( aData );
// Currently, a Pad RoundRect is plotted as polygon.
// TODO: use Aperture macro and flash it
@ -898,16 +931,10 @@ void GERBER_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aS
// Close polygon
cornerList.push_back( cornerList[0] );
PlotPoly( cornerList, aTraceMode == FILLED ? FILLED_SHAPE : NO_FILL,
aTraceMode == FILLED ? 0 : GetCurrentLineWidth(), &gbr_metadata );
// Now, flash a pad anchor, if a netlist attribute is set
// (remove me when a Aperture macro will be used)
if( aData && aTraceMode == FILLED )
{
int diameter = std::min( aSize.x, aSize.y );
FlashPadCircle( aPadPos, diameter, aTraceMode , aData );
}
if( aTraceMode == SKETCH )
PlotPoly( cornerList, NO_FILL, GetCurrentLineWidth(), gbr_metadata );
else
PlotGerberRegion( cornerList, gbr_metadata );
}
void GERBER_PLOTTER::FlashPadCustom( const wxPoint& aPadPos, const wxSize& aSize,
@ -915,28 +942,12 @@ void GERBER_PLOTTER::FlashPadCustom( const wxPoint& aPadPos, const wxSize& aSize
EDA_DRAW_MODE_T aTraceMode, void* aData )
{
// A Pad custom is plotted as polygon.
// A flashed circle @aPadPos is added (anchor pad)
// However, because the anchor pad can be circle or rect, we use only
// a circle not bigger than the rect.
// the main purpose is to print a flashed DCode as pad anchor
if( aTraceMode == FILLED )
FlashPadCircle( aPadPos, std::min( aSize.x, aSize.y ), aTraceMode, aData );
// A Pad custom is plotted as polygon (a region in Gerber language).
GBR_METADATA gbr_metadata;
if( aData )
{
gbr_metadata = *static_cast<GBR_METADATA*>( aData );
// If the pad is drawn on a copper layer,
// set attribute to GBR_APERTURE_ATTRIB_CONDUCTOR
if( gbr_metadata.IsCopper() )
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_CONDUCTOR );
wxString attrname( ".P" );
gbr_metadata.m_NetlistMetadata.ClearAttribute( &attrname ); // not allowed on inner layers
}
SHAPE_POLY_SET polyshape = *aPolygons;
@ -960,9 +971,10 @@ void GERBER_PLOTTER::FlashPadCustom( const wxPoint& aPadPos, const wxSize& aSize
// Close polygon
cornerList.push_back( cornerList[0] );
PlotPoly( cornerList,
aTraceMode == FILLED ? FILLED_SHAPE : NO_FILL,
aTraceMode == FILLED ? 0 : GetCurrentLineWidth(), &gbr_metadata );
if( aTraceMode == SKETCH )
PlotPoly( cornerList, NO_FILL, GetCurrentLineWidth(), &gbr_metadata );
else
PlotGerberRegion( cornerList, &gbr_metadata );
}
}
@ -971,7 +983,6 @@ void GERBER_PLOTTER::FlashPadTrapez( const wxPoint& aPadPos, const wxPoint* aCo
double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode, void* aData )
{
// Currently, a Pad Trapezoid is plotted as polygon.
// TODO: use Aperture macro and flash it
// polygon corners list
@ -980,25 +991,6 @@ void GERBER_PLOTTER::FlashPadTrapez( const wxPoint& aPadPos, const wxPoint* aCo
for( int ii = 0; ii < 4; ii++ )
cornerList.push_back( aCorners[ii] );
// Now, flash a pad anchor, if a netlist attribute is set
// (remove me when a Aperture macro will be used)
if( aData && ( aTrace_Mode == FILLED ) )
{
// Calculate the radius of the circle inside the shape
// It is the smaller dist from shape pos to edges
int radius = INT_MAX;
for( unsigned ii = 0, jj = cornerList.size()-1; ii < cornerList.size();
jj = ii, ii++ )
{
SEG segment( aCorners[ii], aCorners[jj] );
int dist = segment.LineDistance( VECTOR2I( 0, 0) );
radius = std::min( radius, dist );
}
FlashPadCircle( aPadPos, radius*2, aTrace_Mode, aData );
}
// Draw the polygon and fill the interior as required
for( unsigned ii = 0; ii < 4; ii++ )
{
@ -1013,21 +1005,13 @@ void GERBER_PLOTTER::FlashPadTrapez( const wxPoint& aPadPos, const wxPoint* aCo
GBR_METADATA metadata;
if( gbr_metadata )
{
metadata = *gbr_metadata;
// If the pad is drawn on a copper layer,
// set attribute to GBR_APERTURE_ATTRIB_CONDUCTOR
if( metadata.IsCopper() )
metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_CONDUCTOR );
wxString attrname( ".P" );
metadata.m_NetlistMetadata.ClearAttribute( &attrname ); // not allowed on inner layers
}
SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH, &metadata );
PlotPoly( cornerList, aTrace_Mode == FILLED ? FILLED_SHAPE : NO_FILL,
aTrace_Mode == FILLED ? 0 : GetCurrentLineWidth(),
&metadata );
if( aTrace_Mode == SKETCH )
PlotPoly( cornerList, NO_FILL, USE_DEFAULT_LINE_WIDTH,
&metadata );
else
PlotGerberRegion( cornerList, &metadata );
}

View File

@ -40,11 +40,17 @@
* %TO.CMfr,<string> Manufacturer
* %TO.CMPN,<string> Manufacturer part number
* %TO.Cpkg,<string> Package, as per IPC-7351
* %TO.CVal,<string> Value, a string. E.g. 220nF
* %TO.CMnt,<string> Mount type: (SMD|BGA|TH|Other)
* %TO.CFtp,<string> Footprint name, a string. E.g. LQFP-100_14x14mm_P0.5mm
This is the footprint name coming from the CAD tool libraries.
* %TO.CVal,<string> Value, a string. E.g. 220nF
* %TO.CMnt,<string> Mount type: (SMD|TH|Other)
* %TO.CPgN,<string> Package name, like the JEDEC JEP95 standard.
* %TO.CPgD,<string> Package description.
* %TO.CHgt,<string> Height, a decimal, in the unit of the file.
* %TO.CLbN,<string> Library name.
* %TO.CLbD,<string> Library description.
* %TO.Sup,<SN>,<SPN> SN is a field with the supppier name.
* SPN is a field with the supppier part name
*/
class GBR_CMP_PNP_METADATA
{
@ -62,6 +68,8 @@ public:
wxString m_MPN; // Manufacturer part number
wxString m_Package; // Package, as per IPC-7351
wxString m_Footprint; // Footprint name, from library
wxString m_LibraryName; // Library name, containing the footprint
wxString m_LibraryDescr; // Library description
wxString m_Value; // Component value
MOUNT_TYPE m_MountType; // SMD|TH|Other

View File

@ -1174,7 +1174,7 @@ public:
*/
virtual void PlotPoly( const std::vector< wxPoint >& aCornerList,
FILL_T aFill, int aWidth = USE_DEFAULT_LINE_WIDTH,
void * aData = NULL ) override;
void* aData = nullptr ) override;
virtual void PenTo( const wxPoint& pos, char plume ) override;
@ -1232,6 +1232,14 @@ public:
virtual void FlashRegularPolygon( const wxPoint& aShapePos, int aDiameter, int aCornerCount,
double aOrient, EDA_DRAW_MODE_T aTraceMode, void* aData ) override;
/**
* Plot a Gerber region: similar to PlotPoly but plot only filled polygon,
* and add the TA.AperFunction if aData contains this attribute, and clear it
* after plotting
*/
void PlotGerberRegion( const std::vector< wxPoint >& aCornerList,
void * aData = NULL );
/**
* Change the plot polarity and begin a new layer
* Used to 'scratch off' silk screen away from solder mask
@ -1268,6 +1276,11 @@ public:
*/
virtual void EndBlock( void* aData ) override;
/** Remove (clear) all attributes from object attributes dictionary (TO. and TA commands)
* similar to clearNetAttribute(), this is an unconditional reset of TO. and TA. attributes
*/
void ClearAllAttributes();
protected:
/**
* Pick an existing aperture or create a new one, matching the
@ -1304,9 +1317,11 @@ protected:
/**
* clear a Gerber net attribute record (clear object attribute dictionary)
* and output the clear object attribute dictionary command to gerber file
* has effect only if a net attribute is stored in m_objectAttributesDictionnary
*/
void clearNetAttribute();
// Remove all attributes from object attributes dictionary (TO. and TA commands)
/**
* Function getAperture returns a reference to the aperture which meets the size anf type of tool
* if the aperture does not exist, it is created and entered in aperture list

View File

@ -49,10 +49,10 @@ PLACEFILE_GERBER_WRITER::PLACEFILE_GERBER_WRITER( BOARD* aPcb )
{
m_pcb = aPcb;
/* Set conversion scale depending on drill file units */
m_conversionUnits = 1.0 / IU_PER_MM; // Gerber units = mm
m_conversionUnits = 1.0 / IU_PER_MM; // Gerber units = mm
m_forceSmdItems = false;
m_plotPad1Marker = true; // Place a marker to pin 1 (or A1) position
m_plotOtherPadsMarker = false; // Place a marker to other pins position
m_plotPad1Marker = true; // Place a marker to pin 1 (or A1) position
m_plotOtherPadsMarker = true; // Place a marker to other pins position
}
@ -146,8 +146,12 @@ int PLACEFILE_GERBER_WRITER::CreatePlaceFile( wxString& aFullFilename,
pnpAttrib.m_Value = FormatStringFromGerber( footprint->GetValue() );
// Add component footprint info:
wxString fp_name = FROM_UTF8( footprint->GetFPID().GetLibItemName().c_str() );
pnpAttrib.m_Footprint = FormatStringFromGerber( fp_name );
wxString fp_info = FROM_UTF8( footprint->GetFPID().GetLibItemName().c_str() );
pnpAttrib.m_Footprint = FormatStringFromGerber( fp_info );
// Add footprint lib name:
fp_info = FROM_UTF8( footprint->GetFPID().GetLibNickname().c_str() );
pnpAttrib.m_LibraryName = FormatStringFromGerber( fp_info );
gbr_metadata.m_NetlistMetadata.SetExtraData( pnpAttrib.FormatCmpPnPMetadata() );
@ -174,13 +178,13 @@ int PLACEFILE_GERBER_WRITER::CreatePlaceFile( wxString& aFullFilename,
}
}
D_PAD* pad1 = nullptr;
std::vector<D_PAD*>pad_key_list;
if( m_plotPad1Marker )
{
pad1 = findPad1( footprint );
findPads1( pad_key_list, footprint );
if( pad1 )
for( D_PAD* pad1 : pad_key_list )
{
gbr_metadata.SetApertureAttrib(
GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_PAD1_POSITION );
@ -205,7 +209,18 @@ int PLACEFILE_GERBER_WRITER::CreatePlaceFile( wxString& aFullFilename,
for( D_PAD* pad: footprint->Pads() )
{
if( pad == pad1 ) // Already plotted
bool skip_pad = false;
for( D_PAD* pad1 : pad_key_list )
{
if( pad == pad1 ) // Already plotted
{
skip_pad = true;
break;
}
}
if( skip_pad )
continue;
// Skip also pads not on the current layer, like pads only
@ -216,13 +231,13 @@ int PLACEFILE_GERBER_WRITER::CreatePlaceFile( wxString& aFullFilename,
gbr_metadata.SetPadName( pad->GetName() );
// Flashes a round, 0 sized round shape at pad position
int mark_size = Millimeter2iu( 0.1 );
int mark_size = 0;
plotter.FlashPadCircle( pad->GetPosition() + m_offset, mark_size,
FILLED, &gbr_metadata );
FILLED, &gbr_metadata );
}
}
plotter.EndBlock( nullptr ); // Close all .TO attributes
plotter.ClearAllAttributes(); // Unconditionally close all .TO attributes
cmp_count++;
}
@ -241,27 +256,20 @@ double PLACEFILE_GERBER_WRITER::mapRotationAngle( double aAngle )
}
D_PAD* PLACEFILE_GERBER_WRITER::findPad1( MODULE* aFootprint )
void PLACEFILE_GERBER_WRITER::findPads1( std::vector<D_PAD*>& aPadList, MODULE* aFootprint ) const
{
// Fint the pad "1" or pad "A1"
// this is possible only if only one pad is found
// Usefull to place a marker in this position
std::vector<D_PAD*> pad1_list;
for( D_PAD* pad : aFootprint->Pads() )
{
if( !pad->IsOnLayer( m_layer ) )
continue;
if( pad->GetName() == "1" || pad->GetName() == "A1")
pad1_list.push_back( pad );
aPadList.push_back( pad );
}
if( pad1_list.size() == 1 )
return pad1_list[0];
return nullptr;
}

View File

@ -93,10 +93,12 @@ private:
*/
double mapRotationAngle( double aAngle );
/** Find the pad 1 (or pad "A1") of a footprint
* Usefull to plot a marker at this position
/** Find the pad(s) 1 (or pad "A1") of a footprint
* Usefull to plot a marker at this (these) position(s)
* @param aPadList is the list to fill
* @param aFootprint is the footprint to test
*/
D_PAD* findPad1( MODULE* aFootprint );
void findPads1( std::vector<D_PAD*>& aPadList, MODULE* aFootprint ) const;
};
#endif // #ifndef PLACEFILE_GERBER_WRITER_H