Refinements in gerber placefile writer: allows adding board edge cuts in file.

Use a pad bounding box for footprints having no valid courtyard defined.
Refinement also in Gerber files when plotting oval pads.
This commit is contained in:
jean-pierre charras 2019-11-01 13:35:42 +01:00
parent dc5e8aa609
commit 65bf669387
10 changed files with 267 additions and 53 deletions

View File

@ -797,38 +797,16 @@ void GERBER_PLOTTER::FlashPadOval( const wxPoint& pos, const wxSize& aSize, doub
{
// TODO: use an aperture macro to declare the rotated pad
// to be able to flash the shape
// For now, the pad is drawn as polygon (region in Gerber dialect),
// with TO attributes of a flased pad
// For now, the pad is drawn as thick segment (painted with only one segment)
// The pad is reduced to an segment with dy > dx
int delta = size.y - size.x;
int x0 = 0;
int y0 = -delta / 2;
int x1 = 0;
int y1 = delta / 2;
RotatePoint( &x0, &y0, orient );
RotatePoint( &x1, &y1, orient );
wxPoint p0( 0, -delta / 2 );
wxPoint p1( 0, delta / 2 );
RotatePoint( &p0.x, &p0.y, orient );
RotatePoint( &p1.x, &p1.y, orient );
SHAPE_POLY_SET outline;
// Max error to approximate arcs by segments
// Currently 2 micrometers give a good approximation
double iu_per_micron = m_IUsPerDecimil / 2.54;
int arc_approx_error = KiROUND( iu_per_micron * 2 );
TransformOvalToPolygon( outline,
wxPoint( pos.x + x0, pos.y + y0 ),
wxPoint( pos.x + x1, pos.y + y1 ),
size.x, arc_approx_error );
std::vector<wxPoint> cornerList;
for( int ii = 0; ii < outline.Outline(0).PointCount(); ++ii )
{
VECTOR2I& point = outline.Outline(0).Point( ii );
cornerList.emplace_back( wxPoint( point.x, point.y ) );
}
PlotGerberRegion( cornerList, gbr_metadata );
ThickSegment( pos + p0, pos + p1, size.x, trace_mode, gbr_metadata );
}
else
sketchOval( pos, size, orient, -1 );

View File

@ -446,6 +446,28 @@ EDA_RECT MODULE::GetFootprintRect() const
}
EDA_RECT MODULE::GetFpPadsLocalBbox() const
{
EDA_RECT area;
// We want the bounding box of the footprint pads at rot 0, not flipped
// Create such a image:
MODULE dummy( *this );
dummy.SetPosition( wxPoint( 0, 0 ) );
if( dummy.IsFlipped() )
dummy.Flip( wxPoint( 0, 0 ) , false );
if( dummy.GetOrientation() )
dummy.SetOrientation( 0 );
for( auto pad : dummy.Pads() )
area.Merge( pad->GetBoundingBox() );
return area;
}
const EDA_RECT MODULE::GetBoundingBox() const
{
EDA_RECT area = GetFootprintRect();

View File

@ -42,8 +42,8 @@
#include <list>
#include "zones.h"
#include <class_text_mod.h>
#include <class_zone.h>
#include <class_text_mod.h>
#include <class_zone.h>
#include <core/iterators.h>
@ -153,6 +153,15 @@ public:
*/
EDA_RECT GetFootprintRect() const;
/**
* Returns the bounding box containing pads when the footprint
* is on the front side, orientation 0, position 0,0.
* mainly used in Gerber place file to draw a fp outline when the coutyard
* is missing or broken
* @return EDA_RECT - The rectangle containing the pads for the normalized footprint.
*/
EDA_RECT GetFpPadsLocalBbox() const;
/**
* Returns a bounding polygon for the shapes and pads in the module
* This operation is slower but more accurate than calculating a bounding box
@ -180,10 +189,10 @@ public:
}
const MODULE_ZONE_CONTAINERS& Zones() const
{
{
return m_fp_zones;
}
}
const DRAWINGS& GraphicalItems() const
{
return m_drawings;

View File

@ -39,7 +39,7 @@ DIALOG_GEN_FOOTPRINT_POSITION_BASE::DIALOG_GEN_FOOTPRINT_POSITION_BASE( wxWindow
bSizerdirBrowse->Add( m_browseButton, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
bUpperSizer->Add( bSizerdirBrowse, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT|wxTOP, 10 );
bUpperSizer->Add( bSizerdirBrowse, 0, wxEXPAND|wxALL, 5 );
m_MainSizer->Add( bUpperSizer, 0, wxEXPAND, 2 );
@ -50,7 +50,7 @@ DIALOG_GEN_FOOTPRINT_POSITION_BASE::DIALOG_GEN_FOOTPRINT_POSITION_BASE( wxWindow
wxString m_rbFormatChoices[] = { _("ASCII"), _("CSV"), _("Gerber (very experimental)") };
int m_rbFormatNChoices = sizeof( m_rbFormatChoices ) / sizeof( wxString );
m_rbFormat = new wxRadioBox( this, wxID_ANY, _("Format"), wxDefaultPosition, wxDefaultSize, m_rbFormatNChoices, m_rbFormatChoices, 1, wxRA_SPECIFY_COLS );
m_rbFormat->SetSelection( 0 );
m_rbFormat->SetSelection( 2 );
bSizerMiddle->Add( m_rbFormat, 0, wxALL, 5 );
wxString m_radioBoxUnitsChoices[] = { _("Inches"), _("Millimeters") };
@ -68,7 +68,7 @@ DIALOG_GEN_FOOTPRINT_POSITION_BASE::DIALOG_GEN_FOOTPRINT_POSITION_BASE( wxWindow
bSizerMiddle->Add( m_radioBoxFilesCount, 0, wxALL, 5 );
m_MainSizer->Add( bSizerMiddle, 0, wxTOP|wxRIGHT|wxLEFT|wxEXPAND, 5 );
m_MainSizer->Add( bSizerMiddle, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 );
wxBoxSizer* bSizerLower;
bSizerLower = new wxBoxSizer( wxVERTICAL );
@ -76,6 +76,9 @@ DIALOG_GEN_FOOTPRINT_POSITION_BASE::DIALOG_GEN_FOOTPRINT_POSITION_BASE( wxWindow
m_forceSMDOpt = new wxCheckBox( this, wxID_ANY, _("Include footprints with SMD pads even if not marked Surface Mount"), wxDefaultPosition, wxDefaultSize, 0 );
bSizerLower->Add( m_forceSMDOpt, 0, wxALL, 5 );
m_cbIncludeBoardEdge = new wxCheckBox( this, wxID_ANY, _("Include board edge layer"), wxDefaultPosition, wxDefaultSize, 0 );
bSizerLower->Add( m_cbIncludeBoardEdge, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_messagesPanel = new WX_HTML_REPORT_PANEL( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
m_messagesPanel->SetMinSize( wxSize( 350,300 ) );
@ -84,6 +87,9 @@ DIALOG_GEN_FOOTPRINT_POSITION_BASE::DIALOG_GEN_FOOTPRINT_POSITION_BASE( wxWindow
m_MainSizer->Add( bSizerLower, 1, wxEXPAND|wxRIGHT|wxLEFT, 5 );
m_staticline = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
m_MainSizer->Add( m_staticline, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 );
m_sdbSizer = new wxStdDialogButtonSizer();
m_sdbSizerOK = new wxButton( this, wxID_OK );
m_sdbSizer->AddButton( m_sdbSizerOK );
@ -104,6 +110,8 @@ DIALOG_GEN_FOOTPRINT_POSITION_BASE::DIALOG_GEN_FOOTPRINT_POSITION_BASE( wxWindow
m_rbFormat->Connect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_GEN_FOOTPRINT_POSITION_BASE::onSelectFormat ), NULL, this );
m_radioBoxUnits->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_GEN_FOOTPRINT_POSITION_BASE::onUpdateUIUnits ), NULL, this );
m_radioBoxFilesCount->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_GEN_FOOTPRINT_POSITION_BASE::onUpdateUIFileOpt ), NULL, this );
m_forceSMDOpt->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_GEN_FOOTPRINT_POSITION_BASE::onUpdateUIforceSMDOpt ), NULL, this );
m_cbIncludeBoardEdge->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_GEN_FOOTPRINT_POSITION_BASE::onUpdateUIincludeBoardEdge ), NULL, this );
m_sdbSizerOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_GEN_FOOTPRINT_POSITION_BASE::OnGenerate ), NULL, this );
}
@ -114,6 +122,8 @@ DIALOG_GEN_FOOTPRINT_POSITION_BASE::~DIALOG_GEN_FOOTPRINT_POSITION_BASE()
m_rbFormat->Disconnect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_GEN_FOOTPRINT_POSITION_BASE::onSelectFormat ), NULL, this );
m_radioBoxUnits->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_GEN_FOOTPRINT_POSITION_BASE::onUpdateUIUnits ), NULL, this );
m_radioBoxFilesCount->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_GEN_FOOTPRINT_POSITION_BASE::onUpdateUIFileOpt ), NULL, this );
m_forceSMDOpt->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_GEN_FOOTPRINT_POSITION_BASE::onUpdateUIforceSMDOpt ), NULL, this );
m_cbIncludeBoardEdge->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_GEN_FOOTPRINT_POSITION_BASE::onUpdateUIincludeBoardEdge ), NULL, this );
m_sdbSizerOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_GEN_FOOTPRINT_POSITION_BASE::OnGenerate ), NULL, this );
}

View File

@ -70,8 +70,8 @@
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">10</property>
<property name="flag">wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT|wxTOP</property>
<property name="border">5</property>
<property name="flag">wxEXPAND|wxALL</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
@ -282,7 +282,7 @@
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxTOP|wxRIGHT|wxLEFT|wxEXPAND</property>
<property name="flag">wxEXPAND|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
@ -339,7 +339,7 @@
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="selection">0</property>
<property name="selection">2</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style">wxRA_SPECIFY_COLS</property>
@ -563,6 +563,72 @@
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnUpdateUI">onUpdateUIforceSMDOpt</event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxBOTTOM|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="checked">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Include board edge layer</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_cbIncludeBoardEdge</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnUpdateUI">onUpdateUIincludeBoardEdge</event>
</object>
</object>
<object class="sizeritem" expanded="1">
@ -624,6 +690,64 @@
</object>
</object>
</object>
<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="wxStaticLine" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_staticline</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style">wxLI_HORIZONTAL</property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property>

View File

@ -29,6 +29,7 @@ class WX_HTML_REPORT_PANEL;
#include <wx/radiobox.h>
#include <wx/checkbox.h>
#include <wx/panel.h>
#include <wx/statline.h>
#include <wx/dialog.h>
///////////////////////////////////////////////////////////////////////////
@ -49,7 +50,9 @@ class DIALOG_GEN_FOOTPRINT_POSITION_BASE : public DIALOG_SHIM
wxRadioBox* m_radioBoxUnits;
wxRadioBox* m_radioBoxFilesCount;
wxCheckBox* m_forceSMDOpt;
wxCheckBox* m_cbIncludeBoardEdge;
WX_HTML_REPORT_PANEL* m_messagesPanel;
wxStaticLine* m_staticline;
wxStdDialogButtonSizer* m_sdbSizer;
wxButton* m_sdbSizerOK;
wxButton* m_sdbSizerCancel;
@ -59,6 +62,8 @@ class DIALOG_GEN_FOOTPRINT_POSITION_BASE : public DIALOG_SHIM
virtual void onSelectFormat( wxCommandEvent& event ) { event.Skip(); }
virtual void onUpdateUIUnits( wxUpdateUIEvent& event ) { event.Skip(); }
virtual void onUpdateUIFileOpt( wxUpdateUIEvent& event ) { event.Skip(); }
virtual void onUpdateUIforceSMDOpt( wxUpdateUIEvent& event ) { event.Skip(); }
virtual void onUpdateUIincludeBoardEdge( wxUpdateUIEvent& event ) { event.Skip(); }
virtual void OnGenerate( wxCommandEvent& event ) { event.Skip(); }

View File

@ -51,6 +51,7 @@
#define PLACEFILE_UNITS_KEY wxT( "PlaceFileUnits" )
#define PLACEFILE_OPT_KEY wxT( "PlaceFileOpts" )
#define PLACEFILE_FORMAT_KEY wxT( "PlaceFileFormat" )
#define PLACEFILE_INCLUDE_BRD_EDGE_KEY wxT( "PlaceFileIncludeBrdEdge" )
/**
@ -89,6 +90,7 @@ private:
static int m_unitsOpt;
static int m_fileOpt;
static int m_fileFormat;
static bool m_includeBoardEdge;
void initDialog();
void OnOutputDirectoryBrowseClicked( wxCommandEvent& event ) override;
@ -104,6 +106,16 @@ private:
m_radioBoxFilesCount->Enable( m_rbFormat->GetSelection() != 2 );
}
void onUpdateUIforceSMDOpt( wxUpdateUIEvent& event ) override
{
m_radioBoxFilesCount->Enable( m_rbFormat->GetSelection() != 2 );
}
void onUpdateUIincludeBoardEdge( wxUpdateUIEvent& event ) override
{
m_cbIncludeBoardEdge->Enable( m_rbFormat->GetSelection() == 2 );
}
/** Creates files in text or csv format
*/
bool CreateAsciiFiles();
@ -139,6 +151,8 @@ private:
int DIALOG_GEN_FOOTPRINT_POSITION::m_unitsOpt = 0;
int DIALOG_GEN_FOOTPRINT_POSITION::m_fileOpt = 0;
int DIALOG_GEN_FOOTPRINT_POSITION::m_fileFormat = 0;
bool DIALOG_GEN_FOOTPRINT_POSITION::m_includeBoardEdge = false;
void DIALOG_GEN_FOOTPRINT_POSITION::initDialog()
@ -149,6 +163,7 @@ void DIALOG_GEN_FOOTPRINT_POSITION::initDialog()
m_config->Read( PLACEFILE_UNITS_KEY, &m_unitsOpt, 1 );
m_config->Read( PLACEFILE_OPT_KEY, &m_fileOpt, 0 );
m_config->Read( PLACEFILE_FORMAT_KEY, &m_fileFormat, 0 );
m_config->Read( PLACEFILE_INCLUDE_BRD_EDGE_KEY, &m_includeBoardEdge, false );
// Output directory
m_outputDirectoryName->SetValue( m_plotOpts.GetOutputDirectory() );
@ -157,6 +172,8 @@ void DIALOG_GEN_FOOTPRINT_POSITION::initDialog()
m_radioBoxUnits->SetSelection( m_unitsOpt );
m_radioBoxFilesCount->SetSelection( m_fileOpt );
m_rbFormat->SetSelection( m_fileFormat );
m_cbIncludeBoardEdge->SetValue( m_includeBoardEdge );
// Update sizes and sizers:
m_messagesPanel->MsgPanelSetMinSize( wxSize( -1, 160 ) );
@ -197,11 +214,12 @@ void DIALOG_GEN_FOOTPRINT_POSITION::OnGenerate( wxCommandEvent& event )
m_unitsOpt = m_radioBoxUnits->GetSelection();
m_fileOpt = m_radioBoxFilesCount->GetSelection();
m_fileFormat = m_rbFormat->GetSelection();
m_includeBoardEdge = m_cbIncludeBoardEdge->GetValue();
m_config->Write( PLACEFILE_UNITS_KEY, m_unitsOpt );
m_config->Write( PLACEFILE_OPT_KEY, m_fileOpt );
m_config->Write( PLACEFILE_FORMAT_KEY, m_fileFormat );
m_config->Write( PLACEFILE_INCLUDE_BRD_EDGE_KEY, m_includeBoardEdge );
// Set output directory and replace backslashes with forward ones
// (Keep unix convention in cfg files)
@ -244,14 +262,12 @@ bool DIALOG_GEN_FOOTPRINT_POSITION::CreateGerberFiles()
fn = m_parent->GetBoard()->GetFileName();
fn.SetPath( outputDir.GetPath() );
// Create the the Front or Top side placement file, or a single file
// Test for any footprint candidate in list, and display the list of forced footprints
// if ForceAllSmd() is true
// Create the the Front and Top side placement files. Gerber P&P files are always separated.
// Not also they include all footprints
PLACEFILE_GERBER_WRITER exporter( brd );
wxString filename = exporter.GetPlaceFileName( fn.GetFullPath(), F_Cu );
int fpcount = exporter.CreatePlaceFile( filename, F_Cu );
int fpcount = exporter.CreatePlaceFile( filename, F_Cu, m_includeBoardEdge );
if( fpcount < 0 )
{
@ -272,7 +288,7 @@ bool DIALOG_GEN_FOOTPRINT_POSITION::CreateGerberFiles()
filename = exporter.GetPlaceFileName( fn.GetFullPath(), B_Cu );
fpcount = exporter.CreatePlaceFile( filename, B_Cu );
fpcount = exporter.CreatePlaceFile( filename, B_Cu, m_includeBoardEdge );
if( fpcount < 0 )
{

View File

@ -57,7 +57,7 @@ PLACEFILE_GERBER_WRITER::PLACEFILE_GERBER_WRITER( BOARD* aPcb )
int PLACEFILE_GERBER_WRITER::CreatePlaceFile( wxString& aFullFilename,
PCB_LAYER_ID aLayer )
PCB_LAYER_ID aLayer, bool aIncludeBrdEdges )
{
m_layer = aLayer;
@ -106,10 +106,28 @@ int PLACEFILE_GERBER_WRITER::CreatePlaceFile( wxString& aFullFilename,
// We need a BRDITEMS_PLOTTER to plot pads
PCB_PLOT_PARAMS plotOpts;
BRDITEMS_PLOTTER brd_plotter( &plotter, m_pcb, plotOpts );
brd_plotter.SetLayerSet( LSET( aLayer ) );
plotter.StartPlot();
if( aIncludeBrdEdges )
{
brd_plotter.SetLayerSet( LSET( Edge_Cuts ) );
// Plot edge layer and graphic items
brd_plotter.PlotBoardGraphicItems();
// Draw footprint other graphic items:
for( MODULE* footprint : fp_list )
{
for( auto item : footprint->GraphicalItems() )
{
if( item->Type() == PCB_MODULE_EDGE_T && item->GetLayer() == Edge_Cuts )
brd_plotter.Plot_1_EdgeModule( (EDGE_MODULE*) item );
}
}
}
brd_plotter.SetLayerSet( LSET( aLayer ) );
int cmp_count = 0;
bool allowUtf8 = true;
@ -167,6 +185,10 @@ int PLACEFILE_GERBER_WRITER::CreatePlaceFile( wxString& aFullFilename,
// Now some extra metadata is output, avoid blindly clearing the full metadata list
gbr_metadata.m_NetlistMetadata.m_TryKeepPreviousAttributes = true;
// We plot the footprint courtyard when possible.
// If not, the pads bounding box will be used.
bool useFpPadsBbox = true;
if( footprint->BuildPolyCourtyard() )
{
int thickness = Millimeter2iu( 0.1 ); // arbitrary but reasonable value
@ -179,11 +201,40 @@ int PLACEFILE_GERBER_WRITER::CreatePlaceFile( wxString& aFullFilename,
for( int ii = 0; ii < courtyard.OutlineCount(); ii++ )
{
SHAPE_LINE_CHAIN poly = courtyard.Outline( ii );
if( !poly.PointCount() )
continue;
poly.Move( m_offset );
useFpPadsBbox = false;
plotter.PLOTTER::PlotPoly( poly, NO_FILL, thickness, &gbr_metadata );
}
}
if( useFpPadsBbox )
{
int thickness = Millimeter2iu( 0.1 ); // arbitrary but reasonable value
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_CMP_FOOTPRINT );
// bbox of fp pads, pos 0, rot 0, non flipped
EDA_RECT bbox = footprint->GetFpPadsLocalBbox();
// negate bbox Y values if the fp is flipped (always flipped around X axis
// in Gerber P&P files).
int y_sign = aLayer == B_Cu ? -1 : 1;
SHAPE_LINE_CHAIN poly;
poly.Append( bbox.GetLeft(), y_sign*bbox.GetTop() );
poly.Append( bbox.GetLeft(), y_sign*bbox.GetBottom() );
poly.Append( bbox.GetRight(), y_sign*bbox.GetBottom() );
poly.Append( bbox.GetRight(), y_sign*bbox.GetTop() );
poly.SetClosed( true );
poly.Rotate( -footprint->GetOrientationRadians(), VECTOR2I( 0, 0 ) );
poly.Move( footprint->GetPosition() + m_offset );
plotter.PLOTTER::PlotPoly( poly, NO_FILL, thickness, &gbr_metadata );
}
std::vector<D_PAD*>pad_key_list;
if( m_plotPad1Marker )

View File

@ -60,9 +60,10 @@ public:
* Creates an pnp gerber file
* @param aFullFilename = the full filename
* @param aLayer = layer (F_Cu or B_Cu) to generate
* @param aIncludeBrdEdges = true to include board outlines
* @return component count, or -1 if the file cannot be created
*/
int CreatePlaceFile( wxString& aFullFilename, PCB_LAYER_ID aLayer );
int CreatePlaceFile( wxString& aFullFilename, PCB_LAYER_ID aLayer, bool aIncludeBrdEdges );
/**
* @return a filename which identify the drill file function.

View File

@ -726,9 +726,7 @@ void BRDITEMS_PLOTTER::PlotDrawSegment( DRAWSEGMENT* aSeg )
GBR_METADATA gbr_metadata;
bool isOnCopperLayer = ( m_layerMask & LSET::AllCuMask() ).any();
if( isOnCopperLayer && aSeg->GetLayer() == Edge_Cuts ) // can happens when plotting copper layers
if( aSeg->GetLayer() == Edge_Cuts )
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_EDGECUT );
switch( aSeg->GetShape() )