3D model export improvements:

- Option to export pads separately from tracks+vias
- Options export silkscreen and soldermask as flat faces
- Improve 3D model export dialog layout
- Use VisMaterialTool to specify metallic-roughness for glTF.
- Less OCCT boolean operations (faster, less bugs)

Fixes https://gitlab.com/kicad/code/kicad/-/issues/2072
This commit is contained in:
Alex Shvartzkop 2024-05-19 04:28:43 +03:00
parent 6170151cbc
commit b89d4a7f20
13 changed files with 2499 additions and 2134 deletions

View File

@ -41,8 +41,11 @@ JOB_EXPORT_PCB_3D::JOB_EXPORT_PCB_3D( bool aIsCli ) :
m_exportBoardBody( true ),
m_exportComponents( true ),
m_exportTracks( false ),
m_exportPads( false ),
m_exportZones( false ),
m_exportInnerCopper( false ),
m_exportSilkscreen( false ),
m_exportSoldermask( false ),
m_fuseShapes( false ),
m_format( JOB_EXPORT_PCB_3D::FORMAT::UNKNOWN ),
m_vrmlUnits( JOB_EXPORT_PCB_3D::VRML_UNITS::METERS ),

View File

@ -66,8 +66,11 @@ public:
bool m_exportBoardBody;
bool m_exportComponents;
bool m_exportTracks;
bool m_exportPads;
bool m_exportZones;
bool m_exportInnerCopper;
bool m_exportSilkscreen;
bool m_exportSoldermask;
bool m_fuseShapes;
JOB_EXPORT_PCB_3D::FORMAT m_format;

View File

@ -41,8 +41,11 @@
#define ARG_NO_BOARD_BODY "--no-board-body"
#define ARG_NO_COMPONENTS "--no-components"
#define ARG_INCLUDE_TRACKS "--include-tracks"
#define ARG_INCLUDE_PADS "--include-pads"
#define ARG_INCLUDE_ZONES "--include-zones"
#define ARG_INCLUDE_INNER_COPPER "--include-inner-copper"
#define ARG_INCLUDE_SILKSCREEN "--include-silkscreen"
#define ARG_INCLUDE_SOLDERMASK "--include-soldermask"
#define ARG_FUSE_SHAPES "--fuse-shapes"
#define ARG_NO_OPTIMIZE_STEP "--no-optimize-step"
#define ARG_NET_FILTER "--net-filter"
@ -118,7 +121,11 @@ CLI::PCB_EXPORT_3D_COMMAND::PCB_EXPORT_3D_COMMAND( const std::string& aNa
.flag();
m_argParser.add_argument( ARG_INCLUDE_TRACKS )
.help( UTF8STDSTR( _( "Export tracks" ) ) )
.help( UTF8STDSTR( _( "Export tracks and vias" ) ) )
.flag();
m_argParser.add_argument( ARG_INCLUDE_PADS )
.help( UTF8STDSTR( _( "Export pads" ) ) )
.flag();
m_argParser.add_argument( ARG_INCLUDE_ZONES )
@ -129,6 +136,14 @@ CLI::PCB_EXPORT_3D_COMMAND::PCB_EXPORT_3D_COMMAND( const std::string& aNa
.help( UTF8STDSTR( _( "Export elements on inner copper layers" ) ) )
.flag();
m_argParser.add_argument( ARG_INCLUDE_SILKSCREEN )
.help( UTF8STDSTR( _( "Export silkscreen graphics as a set of flat faces" ) ) )
.flag();
m_argParser.add_argument( ARG_INCLUDE_SOLDERMASK )
.help( UTF8STDSTR( _( "Export soldermask layers as a set of flat faces" ) ) )
.flag();
m_argParser.add_argument( ARG_FUSE_SHAPES )
.help( UTF8STDSTR( _( "Fuse overlapping geometry together" ) ) )
.flag();
@ -192,8 +207,11 @@ int CLI::PCB_EXPORT_3D_COMMAND::doPerform( KIWAY& aKiway )
step->m_exportBoardBody = !m_argParser.get<bool>( ARG_NO_BOARD_BODY );
step->m_exportComponents = !m_argParser.get<bool>( ARG_NO_COMPONENTS );
step->m_exportTracks = m_argParser.get<bool>( ARG_INCLUDE_TRACKS );
step->m_exportPads = m_argParser.get<bool>( ARG_INCLUDE_PADS );
step->m_exportZones = m_argParser.get<bool>( ARG_INCLUDE_ZONES );
step->m_exportInnerCopper = m_argParser.get<bool>( ARG_INCLUDE_INNER_COPPER );
step->m_exportSilkscreen = m_argParser.get<bool>( ARG_INCLUDE_SILKSCREEN );
step->m_exportSoldermask = m_argParser.get<bool>( ARG_INCLUDE_SOLDERMASK );
step->m_fuseShapes = m_argParser.get<bool>( ARG_FUSE_SHAPES );
step->m_boardOnly = m_argParser.get<bool>( ARG_BOARD_ONLY );
step->m_netFilter = From_UTF8( m_argParser.get<std::string>( ARG_NET_FILTER ).c_str() );

View File

@ -47,9 +47,24 @@
#include <widgets/text_ctrl_eval.h>
#include <wildcards_and_files_ext.h>
#include <filename_resolver.h>
#include <core/map_helpers.h>
#include <settings/settings_manager.h>
// Maps m_choiceFormat selection to extension (and kicad-cli command)
static const std::vector<wxString> c_formatCommand = { FILEEXT::StepFileExtension,
FILEEXT::GltfBinaryFileExtension,
FILEEXT::XaoFileExtension,
FILEEXT::BrepFileExtension };
// Maps file extensions to m_choiceFormat selection
static const std::map<wxString, int> c_formatExtToChoice = { { FILEEXT::StepFileExtension, 0 },
{ FILEEXT::StepFileAbrvExtension, 0 },
{ FILEEXT::GltfBinaryFileExtension, 1 },
{ FILEEXT::XaoFileExtension, 2 },
{ FILEEXT::BrepFileExtension, 3 } };
class DIALOG_EXPORT_STEP : public DIALOG_EXPORT_STEP_BASE
{
public:
@ -71,6 +86,7 @@ protected:
void onUpdateXPos( wxUpdateUIEvent& aEvent ) override;
void onUpdateYPos( wxUpdateUIEvent& aEvent ) override;
void onExportButton( wxCommandEvent& aEvent ) override;
void onFormatChoice( wxCommandEvent& event ) override;
int GetOrgUnitsChoice() const
{
@ -118,25 +134,33 @@ private:
bool m_noUnspecified; // remember last preference for No Unspecified Component
bool m_noDNP; // remember last preference for No DNP Component
static bool m_optimizeStep; // remember last preference for Optimize STEP file (stored only for the session)
static bool m_exportBoardBody; // remember last preference to export board body (stored only for the session)
static bool m_exportBoardBody; // remember last preference to export board body (stored only for the session)
static bool m_exportComponents; // remember last preference to export components (stored only for the session)
static bool m_exportTracks; // remember last preference to export tracks (stored only for the session)
static bool m_exportTracks; // remember last preference to export tracks and vias (stored only for the session)
static bool m_exportPads; // remember last preference to export pads (stored only for the session)
static bool m_exportZones; // remember last preference to export zones (stored only for the session)
static bool m_fuseShapes; // remember last preference to fuse shapes (stored only for the session)
static bool m_exportInnerCopper; // remember last preference to export inner layers (stored only for the session)
static bool m_exportSilkscreen; // remember last preference to export silkscreen (stored only for the session)
static bool m_exportSoldermask; // remember last preference to export soldermask (stored only for the session)
static bool m_fuseShapes; // remember last preference to fuse shapes (stored only for the session)
wxString m_netFilter; // filter copper nets
wxString m_boardPath; // path to the exported board file
static int m_toleranceLastChoice; // Store m_tolerance option during a session
static int m_formatLastChoice; // Store format option during a session
};
int DIALOG_EXPORT_STEP::m_toleranceLastChoice = -1; // Use default
int DIALOG_EXPORT_STEP::m_formatLastChoice = -1; // Use default
bool DIALOG_EXPORT_STEP::m_optimizeStep = true;
bool DIALOG_EXPORT_STEP::m_exportBoardBody = true;
bool DIALOG_EXPORT_STEP::m_exportComponents = true;
bool DIALOG_EXPORT_STEP::m_exportTracks = false;
bool DIALOG_EXPORT_STEP::m_exportPads = false;
bool DIALOG_EXPORT_STEP::m_exportZones = false;
bool DIALOG_EXPORT_STEP::m_exportInnerCopper = false;
bool DIALOG_EXPORT_STEP::m_exportSilkscreen = false;
bool DIALOG_EXPORT_STEP::m_exportSoldermask = false;
bool DIALOG_EXPORT_STEP::m_fuseShapes = false;
DIALOG_EXPORT_STEP::DIALOG_EXPORT_STEP( PCB_EDIT_FRAME* aParent, const wxString& aBoardPath ) :
@ -192,8 +216,11 @@ DIALOG_EXPORT_STEP::DIALOG_EXPORT_STEP( PCB_EDIT_FRAME* aParent, const wxString&
m_cbExportBody->SetValue( m_exportBoardBody );
m_cbExportComponents->SetValue( m_exportComponents );
m_cbExportTracks->SetValue( m_exportTracks );
m_cbExportPads->SetValue( m_exportPads );
m_cbExportZones->SetValue( m_exportZones );
m_cbExportInnerCopper->SetValue( m_exportInnerCopper );
m_cbExportSilkscreen->SetValue( m_exportSilkscreen );
m_cbExportSoldermask->SetValue( m_exportSoldermask );
m_cbFuseShapes->SetValue( m_fuseShapes );
m_cbRemoveUnspecified->SetValue( m_noUnspecified );
m_cbRemoveDNP->SetValue( m_noDNP );
@ -247,6 +274,9 @@ DIALOG_EXPORT_STEP::DIALOG_EXPORT_STEP( PCB_EDIT_FRAME* aParent, const wxString&
if( m_toleranceLastChoice >= 0 )
m_choiceTolerance->SetSelection( m_toleranceLastChoice );
if( m_formatLastChoice >= 0 )
m_choiceFormat->SetSelection( m_formatLastChoice );
// Now all widgets have the size fixed, call FinishDialogSettings
finishDialogSettings();
}
@ -288,12 +318,16 @@ DIALOG_EXPORT_STEP::~DIALOG_EXPORT_STEP()
m_netFilter = m_txtNetFilter->GetValue();
m_toleranceLastChoice = m_choiceTolerance->GetSelection();
m_formatLastChoice = m_choiceFormat->GetSelection();
m_optimizeStep = m_cbOptimizeStep->GetValue();
m_exportBoardBody = m_cbExportBody->GetValue();
m_exportComponents = m_cbExportComponents->GetValue();
m_exportTracks = m_cbExportTracks->GetValue();
m_exportPads = m_cbExportPads->GetValue();
m_exportZones = m_cbExportZones->GetValue();
m_exportInnerCopper = m_cbExportInnerCopper->GetValue();
m_exportSilkscreen = m_cbExportSilkscreen->GetValue();
m_exportSoldermask = m_cbExportSoldermask->GetValue();
m_fuseShapes = m_cbFuseShapes->GetValue();
}
@ -374,22 +408,51 @@ void DIALOG_EXPORT_STEP::onUpdateYPos( wxUpdateUIEvent& aEvent )
void DIALOG_EXPORT_STEP::onBrowseClicked( wxCommandEvent& aEvent )
{
// clang-format off
wxString filter = _( "STEP files" )
+ AddFileExtListToFilter( { FILEEXT::StepFileExtension, FILEEXT::StepFileAbrvExtension } ) + "|"
+ _( "Binary glTF files" )
+ AddFileExtListToFilter( { FILEEXT::GltfBinaryFileExtension } );
+ AddFileExtListToFilter( { FILEEXT::GltfBinaryFileExtension } ) + "|"
+ _( "XAO files" )
+ AddFileExtListToFilter( { FILEEXT::XaoFileExtension} ) + "|"
+ _( "BREP (OCCT) files" )
+ AddFileExtListToFilter( { FILEEXT::BrepFileExtension } );
// clang-format on
// Build the absolute path of current output directory to preselect it in the file browser.
wxString path = ExpandEnvVarSubstitutions( m_outputFileName->GetValue(), &Prj() );
wxFileName fn( Prj().AbsolutePath( path ) );
wxFileDialog dlg( this, _( "STEP Output File" ), fn.GetPath(), fn.GetFullName(), filter,
wxFileDialog dlg( this, _( "3D Model Output File" ), fn.GetPath(), fn.GetFullName(), filter,
wxFD_SAVE );
if( dlg.ShowModal() == wxID_CANCEL )
return;
m_outputFileName->SetValue( dlg.GetPath() );
path = dlg.GetPath();
m_outputFileName->SetValue( path );
fn = wxFileName( path );
if( auto formatChoice = get_opt( c_formatExtToChoice, fn.GetExt().Lower() ) )
m_choiceFormat->SetSelection( *formatChoice );
}
void DIALOG_EXPORT_STEP::onFormatChoice( wxCommandEvent& event )
{
wxString newExt = c_formatCommand[m_choiceFormat->GetSelection()];
wxString path = m_outputFileName->GetValue();
int sepIdx = std::max( path.Find( '/', true ), path.Find( '\\', true ) );
int dotIdx = path.Find( '.', true );
if( dotIdx == -1 || dotIdx < sepIdx )
path << '.' << newExt;
else
path = path.Mid( 0, dotIdx ) << '.' << newExt;
m_outputFileName->SetValue( path );
}
@ -419,12 +482,16 @@ void DIALOG_EXPORT_STEP::onExportButton( wxCommandEvent& aEvent )
double tolerance; // default value in mm
m_toleranceLastChoice = m_choiceTolerance->GetSelection();
m_formatLastChoice = m_choiceFormat->GetSelection();
m_optimizeStep = m_cbOptimizeStep->GetValue();
m_exportBoardBody = m_cbExportBody->GetValue();
m_exportComponents = m_cbExportComponents->GetValue();
m_exportTracks = m_cbExportTracks->GetValue();
m_exportPads = m_cbExportPads->GetValue();
m_exportZones = m_cbExportZones->GetValue();
m_exportInnerCopper = m_cbExportInnerCopper->GetValue();
m_exportSilkscreen = m_cbExportSilkscreen->GetValue();
m_exportSoldermask = m_cbExportSoldermask->GetValue();
m_fuseShapes = m_cbFuseShapes->GetValue();
switch( m_choiceTolerance->GetSelection() )
@ -494,14 +561,8 @@ void DIALOG_EXPORT_STEP::onExportButton( wxCommandEvent& aEvent )
cmdK2S.Append( wxT( " pcb" ) );
cmdK2S.Append( wxT( " export" ) );
if( fn.GetExt() == FILEEXT::GltfBinaryFileExtension )
cmdK2S.Append( wxT( " glb" ) );
else if( fn.GetExt() == FILEEXT::BrepFileExtension )
cmdK2S.Append( wxT( " brep" ) );
else if( fn.GetExt() == FILEEXT::XaoFileExtension )
cmdK2S.Append( wxT( " xao" ) );
else
cmdK2S.Append( wxT( " step" ) );
cmdK2S.Append( wxT( " " ) );
cmdK2S.Append( c_formatCommand[m_choiceFormat->GetSelection()] );
if( GetNoUnspecifiedOption() )
cmdK2S.Append( wxT( " --no-unspecified" ) );
@ -524,12 +585,21 @@ void DIALOG_EXPORT_STEP::onExportButton( wxCommandEvent& aEvent )
if( m_exportTracks )
cmdK2S.Append( wxT( " --include-tracks" ) );
if( m_exportPads )
cmdK2S.Append( wxT( " --include-pads" ) );
if( m_exportZones )
cmdK2S.Append( wxT( " --include-zones" ) );
if( m_exportInnerCopper )
cmdK2S.Append( wxT( " --include-inner-copper" ) );
if( m_exportSilkscreen )
cmdK2S.Append( wxT( " --include-silkscreen" ) );
if( m_exportSoldermask )
cmdK2S.Append( wxT( " --include-soldermask" ) );
if( m_fuseShapes )
cmdK2S.Append( wxT( " --fuse-shapes" ) );
@ -607,5 +677,4 @@ void DIALOG_EXPORT_STEP::onExportButton( wxCommandEvent& aEvent )
DIALOG_EXPORT_STEP_LOG* log = new DIALOG_EXPORT_STEP_LOG( this, cmdK2S );
log->ShowModal();
Close();
}

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.0.0-0-g0efcecf)
// C++ code generated with wxFormBuilder (version 4.1.0-0-g733bf3d)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -20,13 +20,23 @@ DIALOG_EXPORT_STEP_BASE::DIALOG_EXPORT_STEP_BASE( wxWindow* parent, wxWindowID i
bSizerTop = new wxBoxSizer( wxHORIZONTAL );
m_txtFormat = new wxStaticText( this, wxID_ANY, _("Format:"), wxDefaultPosition, wxDefaultSize, 0 );
m_txtFormat->Wrap( -1 );
bSizerTop->Add( m_txtFormat, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
wxString m_choiceFormatChoices[] = { _("STEP"), _("GLB (Binary glTF)"), _("XAO"), _("BREP (OCCT)") };
int m_choiceFormatNChoices = sizeof( m_choiceFormatChoices ) / sizeof( wxString );
m_choiceFormat = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choiceFormatNChoices, m_choiceFormatChoices, 0 );
m_choiceFormat->SetSelection( 0 );
bSizerTop->Add( m_choiceFormat, 0, wxALL, 5 );
m_txtBrdFile = new wxStaticText( this, wxID_ANY, _("File:"), wxDefaultPosition, wxDefaultSize, 0 );
m_txtBrdFile->Wrap( -1 );
bSizerTop->Add( m_txtBrdFile, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_outputFileName = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_outputFileName->SetToolTip( _("Enter a filename if you do not want to use default file names\nCan be used only when printing the current sheet") );
m_outputFileName->SetMinSize( wxSize( 450,-1 ) );
m_outputFileName->SetMinSize( wxSize( 400,-1 ) );
bSizerTop->Add( m_outputFileName, 1, wxALIGN_CENTER_VERTICAL, 5 );
@ -34,28 +44,107 @@ DIALOG_EXPORT_STEP_BASE::DIALOG_EXPORT_STEP_BASE( wxWindow* parent, wxWindowID i
bSizerTop->Add( m_browseButton, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
bSizerSTEPFile->Add( bSizerTop, 0, wxEXPAND|wxALL, 10 );
bSizerSTEPFile->Add( bSizerTop, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 6 );
wxBoxSizer* bSizer2;
bSizer2 = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* bSizerMain;
bSizerMain = new wxBoxSizer( wxHORIZONTAL );
wxStaticBoxSizer* sbGeneralOptions;
sbGeneralOptions = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("General Options") ), wxVERTICAL );
m_cbExportCompound_hidden = new wxCheckBox( sbGeneralOptions->GetStaticBox(), wxID_ANY, _("Export as Compound shape"), wxDefaultPosition, wxDefaultSize, 0 );
m_cbExportCompound_hidden->Hide();
m_cbExportCompound_hidden->SetToolTip( _("Merges all shapes into a single Compound shape. Useful for external software that does de-duplication based on shape names.") );
sbGeneralOptions->Add( m_cbExportCompound_hidden, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_cbExportBody = new wxCheckBox( sbGeneralOptions->GetStaticBox(), wxID_ANY, _("Export board body"), wxDefaultPosition, wxDefaultSize, 0 );
sbGeneralOptions->Add( m_cbExportBody, 0, wxALL, 5 );
m_cbExportComponents = new wxCheckBox( sbGeneralOptions->GetStaticBox(), wxID_ANY, _("Export components"), wxDefaultPosition, wxDefaultSize, 0 );
sbGeneralOptions->Add( m_cbExportComponents, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_cbExportTracks = new wxCheckBox( sbGeneralOptions->GetStaticBox(), wxID_ANY, _("Export tracks and vias"), wxDefaultPosition, wxDefaultSize, 0 );
m_cbExportTracks->SetToolTip( _("Export tracks and vias on external copper layers.") );
sbGeneralOptions->Add( m_cbExportTracks, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_cbExportPads = new wxCheckBox( sbGeneralOptions->GetStaticBox(), wxID_ANY, _("Export pads"), wxDefaultPosition, wxDefaultSize, 0 );
sbGeneralOptions->Add( m_cbExportPads, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_cbExportZones = new wxCheckBox( sbGeneralOptions->GetStaticBox(), wxID_ANY, _("Export zones"), wxDefaultPosition, wxDefaultSize, 0 );
m_cbExportZones->SetToolTip( _("Export zones on external copper layers.") );
sbGeneralOptions->Add( m_cbExportZones, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_cbExportInnerCopper = new wxCheckBox( sbGeneralOptions->GetStaticBox(), wxID_ANY, _("Export inner copper layers"), wxDefaultPosition, wxDefaultSize, 0 );
sbGeneralOptions->Add( m_cbExportInnerCopper, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_cbExportSilkscreen = new wxCheckBox( sbGeneralOptions->GetStaticBox(), wxID_ANY, _("Export silkscreen"), wxDefaultPosition, wxDefaultSize, 0 );
m_cbExportSilkscreen->SetToolTip( _("Export silkscreen graphics as a set of flat faces.") );
sbGeneralOptions->Add( m_cbExportSilkscreen, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_cbExportSoldermask = new wxCheckBox( sbGeneralOptions->GetStaticBox(), wxID_ANY, _("Export solder mask"), wxDefaultPosition, wxDefaultSize, 0 );
m_cbExportSoldermask->SetToolTip( _("Export solder mask layers as a set of flat faces.") );
sbGeneralOptions->Add( m_cbExportSoldermask, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_cbFuseShapes = new wxCheckBox( sbGeneralOptions->GetStaticBox(), wxID_ANY, _("Fuse shapes (time consuming)"), wxDefaultPosition, wxDefaultSize, 0 );
m_cbFuseShapes->SetToolTip( _("Combine intersecting geometry into one shape.") );
sbGeneralOptions->Add( m_cbFuseShapes, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_cbExportSolderpaste_hidden = new wxCheckBox( sbGeneralOptions->GetStaticBox(), wxID_ANY, _("Export solder paste"), wxDefaultPosition, wxDefaultSize, 0 );
m_cbExportSolderpaste_hidden->Hide();
m_cbExportSolderpaste_hidden->SetToolTip( _("Export solder paste graphics.") );
sbGeneralOptions->Add( m_cbExportSolderpaste_hidden, 0, wxBOTTOM|wxRIGHT, 5 );
m_staticTextNetFilter = new wxStaticText( sbGeneralOptions->GetStaticBox(), wxID_ANY, _("Net filter (supports wildcards):"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextNetFilter->Wrap( -1 );
sbGeneralOptions->Add( m_staticTextNetFilter, 0, wxLEFT|wxRIGHT|wxTOP, 5 );
m_txtNetFilter = new wxTextCtrl( sbGeneralOptions->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_txtNetFilter->SetToolTip( _("Only copper items belonging to nets matching this filter will be exported.") );
sbGeneralOptions->Add( m_txtNetFilter, 0, wxALL|wxEXPAND, 5 );
m_staticTextTolerance = new wxStaticText( sbGeneralOptions->GetStaticBox(), wxID_ANY, _("Board outline chaining tolerance:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextTolerance->Wrap( -1 );
sbGeneralOptions->Add( m_staticTextTolerance, 0, wxLEFT|wxRIGHT|wxTOP, 5 );
wxString m_choiceToleranceChoices[] = { _("Tight (0.001 mm)"), _("Standard (0.01 mm)"), _("Loose (0.1 mm)") };
int m_choiceToleranceNChoices = sizeof( m_choiceToleranceChoices ) / sizeof( wxString );
m_choiceTolerance = new wxChoice( sbGeneralOptions->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choiceToleranceNChoices, m_choiceToleranceChoices, 0 );
m_choiceTolerance->SetSelection( 1 );
m_choiceTolerance->SetToolTip( _("Tolerance sets the distance between two points that are considered joined when building the board outlines.") );
sbGeneralOptions->Add( m_choiceTolerance, 0, wxALL|wxEXPAND, 5 );
bSizerMain->Add( sbGeneralOptions, 1, wxEXPAND|wxALL, 5 );
wxBoxSizer* bSizer5;
bSizer5 = new wxBoxSizer( wxVERTICAL );
wxStaticBoxSizer* sbCoordinates;
sbCoordinates = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Coordinates") ), wxVERTICAL );
m_rbDrillAndPlotOrigin = new wxRadioButton( sbCoordinates->GetStaticBox(), wxID_ANY, _("Drill/place file origin"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP );
sbCoordinates->Add( m_rbDrillAndPlotOrigin, 0, wxBOTTOM|wxRIGHT, 5 );
sbCoordinates->Add( m_rbDrillAndPlotOrigin, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
m_rbGridOrigin = new wxRadioButton( sbCoordinates->GetStaticBox(), wxID_ANY, _("Grid origin"), wxDefaultPosition, wxDefaultSize, 0 );
sbCoordinates->Add( m_rbGridOrigin, 0, wxBOTTOM|wxRIGHT, 5 );
sbCoordinates->Add( m_rbGridOrigin, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
m_rbUserDefinedOrigin = new wxRadioButton( sbCoordinates->GetStaticBox(), wxID_ANY, _("User defined origin"), wxDefaultPosition, wxDefaultSize, 0 );
sbCoordinates->Add( m_rbUserDefinedOrigin, 0, wxBOTTOM|wxRIGHT, 5 );
sbCoordinates->Add( m_rbUserDefinedOrigin, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
m_rbBoardCenterOrigin = new wxRadioButton( sbCoordinates->GetStaticBox(), wxID_ANY, _("Board center origin"), wxDefaultPosition, wxDefaultSize, 0 );
sbCoordinates->Add( m_rbBoardCenterOrigin, 0, wxBOTTOM|wxRIGHT, 5 );
sbCoordinates->Add( m_rbBoardCenterOrigin, 0, wxALL, 5 );
bSizer2->Add( sbCoordinates, 0, wxEXPAND|wxRIGHT|wxLEFT, 10 );
bSizer5->Add( sbCoordinates, 0, wxEXPAND|wxALL, 5 );
wxStaticBoxSizer* sbUserDefinedOrigin;
sbUserDefinedOrigin = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("User Defined Origin") ), wxVERTICAL );
@ -106,10 +195,10 @@ DIALOG_EXPORT_STEP_BASE::DIALOG_EXPORT_STEP_BASE( wxWindow* parent, wxWindowID i
fgSizer1->Add( m_STEP_Yorg, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxRIGHT|wxLEFT, 5 );
sbUserDefinedOrigin->Add( fgSizer1, 1, wxEXPAND, 5 );
sbUserDefinedOrigin->Add( fgSizer1, 1, wxEXPAND|wxTOP|wxBOTTOM, 5 );
bSizer2->Add( sbUserDefinedOrigin, 0, wxEXPAND|wxRIGHT|wxLEFT, 10 );
bSizer5->Add( sbUserDefinedOrigin, 0, wxEXPAND|wxALL, 5 );
wxStaticBoxSizer* sbOtherOptions;
sbOtherOptions = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Other Options") ), wxVERTICAL );
@ -117,114 +206,34 @@ DIALOG_EXPORT_STEP_BASE::DIALOG_EXPORT_STEP_BASE( wxWindow* parent, wxWindowID i
m_cbRemoveDNP = new wxCheckBox( sbOtherOptions->GetStaticBox(), wxID_ANY, _("Ignore 'Do not populate' components"), wxDefaultPosition, wxDefaultSize, 0 );
m_cbRemoveDNP->SetToolTip( _("Do not show components marked 'Do not populate'") );
sbOtherOptions->Add( m_cbRemoveDNP, 0, wxBOTTOM|wxRIGHT, 5 );
sbOtherOptions->Add( m_cbRemoveDNP, 0, wxALL, 5 );
m_cbRemoveUnspecified = new wxCheckBox( sbOtherOptions->GetStaticBox(), wxID_ANY, _("Ignore 'Unspecified' components"), wxDefaultPosition, wxDefaultSize, 0 );
m_cbRemoveUnspecified->SetToolTip( _("Do not show components with Footprint Type 'Unspecified'") );
sbOtherOptions->Add( m_cbRemoveUnspecified, 0, wxBOTTOM|wxRIGHT, 5 );
sbOtherOptions->Add( m_cbRemoveUnspecified, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_cbSubstModels = new wxCheckBox( sbOtherOptions->GetStaticBox(), wxID_ANY, _("Substitute similarly named models"), wxDefaultPosition, wxDefaultSize, 0 );
m_cbSubstModels->SetToolTip( _("Replace VRML models with STEP models of the same name") );
sbOtherOptions->Add( m_cbSubstModels, 0, wxBOTTOM|wxRIGHT, 5 );
sbOtherOptions->Add( m_cbSubstModels, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_cbOverwriteFile = new wxCheckBox( sbOtherOptions->GetStaticBox(), wxID_ANY, _("Overwrite old file"), wxDefaultPosition, wxDefaultSize, 0 );
sbOtherOptions->Add( m_cbOverwriteFile, 0, wxBOTTOM|wxRIGHT, 5 );
m_staticline11_hidden = new wxStaticLine( sbOtherOptions->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
m_staticline11_hidden->Hide();
sbOtherOptions->Add( m_staticline11_hidden, 0, wxEXPAND|wxTOP|wxBOTTOM, 5 );
sbOtherOptions->Add( m_cbOverwriteFile, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_cbOptimizeStep = new wxCheckBox( sbOtherOptions->GetStaticBox(), wxID_ANY, _("Optimize STEP file"), wxDefaultPosition, wxDefaultSize, 0 );
m_cbOptimizeStep->SetToolTip( _("Disables writing parametric curves. Optimizes file size and write/read times, but may reduce compatibility with other software.") );
sbOtherOptions->Add( m_cbOptimizeStep, 0, wxBOTTOM|wxRIGHT, 5 );
m_cbExportCompound_hidden = new wxCheckBox( sbOtherOptions->GetStaticBox(), wxID_ANY, _("Export as Compound shape"), wxDefaultPosition, wxDefaultSize, 0 );
m_cbExportCompound_hidden->Hide();
m_cbExportCompound_hidden->SetToolTip( _("Merges all shapes into a single Compound shape. Useful for external software that does de-duplication based on shape names.") );
sbOtherOptions->Add( m_cbExportCompound_hidden, 0, wxBOTTOM|wxRIGHT, 5 );
m_staticline1 = new wxStaticLine( sbOtherOptions->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
sbOtherOptions->Add( m_staticline1, 0, wxEXPAND|wxTOP|wxBOTTOM, 5 );
m_cbExportBody = new wxCheckBox( sbOtherOptions->GetStaticBox(), wxID_ANY, _("Export board body"), wxDefaultPosition, wxDefaultSize, 0 );
sbOtherOptions->Add( m_cbExportBody, 0, wxBOTTOM|wxRIGHT, 5 );
m_cbExportComponents = new wxCheckBox( sbOtherOptions->GetStaticBox(), wxID_ANY, _("Export components"), wxDefaultPosition, wxDefaultSize, 0 );
sbOtherOptions->Add( m_cbExportComponents, 0, wxBOTTOM|wxRIGHT, 5 );
m_cbExportTracks = new wxCheckBox( sbOtherOptions->GetStaticBox(), wxID_ANY, _("Export tracks, pads and vias"), wxDefaultPosition, wxDefaultSize, 0 );
m_cbExportTracks->SetToolTip( _("Export tracks, pads and vias on external copper layers.") );
sbOtherOptions->Add( m_cbExportTracks, 0, wxBOTTOM|wxRIGHT, 5 );
m_cbExportZones = new wxCheckBox( sbOtherOptions->GetStaticBox(), wxID_ANY, _("Export zones"), wxDefaultPosition, wxDefaultSize, 0 );
m_cbExportZones->SetToolTip( _("Export zones on external copper layers.") );
sbOtherOptions->Add( m_cbExportZones, 0, wxBOTTOM|wxRIGHT, 5 );
m_cbExportInnerCopper = new wxCheckBox( sbOtherOptions->GetStaticBox(), wxID_ANY, _("Export inner copper layers"), wxDefaultPosition, wxDefaultSize, 0 );
sbOtherOptions->Add( m_cbExportInnerCopper, 0, wxBOTTOM|wxEXPAND|wxRIGHT, 5 );
m_cbFuseShapes = new wxCheckBox( sbOtherOptions->GetStaticBox(), wxID_ANY, _("Fuse shapes (time consuming)"), wxDefaultPosition, wxDefaultSize, 0 );
m_cbFuseShapes->SetToolTip( _("Combine intersecting geometry into one shape.") );
sbOtherOptions->Add( m_cbFuseShapes, 0, wxBOTTOM|wxRIGHT, 5 );
m_cbExportSilkscreen_hidden = new wxCheckBox( sbOtherOptions->GetStaticBox(), wxID_ANY, _("Export silkscreen"), wxDefaultPosition, wxDefaultSize, 0 );
m_cbExportSilkscreen_hidden->Hide();
m_cbExportSilkscreen_hidden->SetToolTip( _("Export silkscreen graphics.") );
sbOtherOptions->Add( m_cbExportSilkscreen_hidden, 0, wxBOTTOM|wxRIGHT, 5 );
m_cbExportSoldermask_hidden = new wxCheckBox( sbOtherOptions->GetStaticBox(), wxID_ANY, _("Export solder mask"), wxDefaultPosition, wxDefaultSize, 0 );
m_cbExportSoldermask_hidden->Hide();
m_cbExportSoldermask_hidden->SetToolTip( _("Export solder mask graphics.") );
sbOtherOptions->Add( m_cbExportSoldermask_hidden, 0, wxBOTTOM|wxRIGHT, 5 );
m_cbExportSolderpaste_hidden = new wxCheckBox( sbOtherOptions->GetStaticBox(), wxID_ANY, _("Export solder paste"), wxDefaultPosition, wxDefaultSize, 0 );
m_cbExportSolderpaste_hidden->Hide();
m_cbExportSolderpaste_hidden->SetToolTip( _("Export solder paste graphics.") );
sbOtherOptions->Add( m_cbExportSolderpaste_hidden, 0, wxBOTTOM|wxRIGHT, 5 );
m_staticTextNetFilter = new wxStaticText( sbOtherOptions->GetStaticBox(), wxID_ANY, _("Net filter (supports wildcards):"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextNetFilter->Wrap( -1 );
sbOtherOptions->Add( m_staticTextNetFilter, 0, wxLEFT|wxRIGHT|wxTOP, 5 );
m_txtNetFilter = new wxTextCtrl( sbOtherOptions->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_txtNetFilter->SetToolTip( _("Only copper items belonging to nets matching this filter will be exported.") );
sbOtherOptions->Add( m_txtNetFilter, 0, wxALL|wxEXPAND, 5 );
m_staticTextTolerance = new wxStaticText( sbOtherOptions->GetStaticBox(), wxID_ANY, _("Board outline chaining tolerance:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextTolerance->Wrap( -1 );
sbOtherOptions->Add( m_staticTextTolerance, 0, wxLEFT|wxRIGHT|wxTOP, 5 );
wxString m_choiceToleranceChoices[] = { _("Tight (0.001 mm)"), _("Standard (0.01 mm)"), _("Loose (0.1 mm)") };
int m_choiceToleranceNChoices = sizeof( m_choiceToleranceChoices ) / sizeof( wxString );
m_choiceTolerance = new wxChoice( sbOtherOptions->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choiceToleranceNChoices, m_choiceToleranceChoices, 0 );
m_choiceTolerance->SetSelection( 1 );
m_choiceTolerance->SetToolTip( _("Tolerance sets the distance between two points that are considered joined when building the board outlines.") );
sbOtherOptions->Add( m_choiceTolerance, 0, wxALL|wxEXPAND, 5 );
sbOtherOptions->Add( m_cbOptimizeStep, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
bSizer2->Add( sbOtherOptions, 1, wxEXPAND|wxRIGHT|wxLEFT, 10 );
bSizer5->Add( sbOtherOptions, 1, wxEXPAND|wxALL, 5 );
bSizerSTEPFile->Add( bSizer2, 1, wxBOTTOM|wxEXPAND|wxTOP, 5 );
wxBoxSizer* bSizer81;
bSizer81 = new wxBoxSizer( wxHORIZONTAL );
bSizerMain->Add( bSizer5, 1, wxEXPAND, 5 );
bSizerSTEPFile->Add( bSizer81, 0, wxEXPAND|wxLEFT|wxRIGHT|wxTOP, 10 );
bSizerSTEPFile->Add( bSizerMain, 1, wxEXPAND, 5 );
m_sdbSizer = new wxStdDialogButtonSizer();
m_sdbSizerOK = new wxButton( this, wxID_OK );
@ -243,6 +252,7 @@ DIALOG_EXPORT_STEP_BASE::DIALOG_EXPORT_STEP_BASE( wxWindow* parent, wxWindowID i
this->Centre( wxBOTH );
// Connect Events
m_choiceFormat->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_EXPORT_STEP_BASE::onFormatChoice ), NULL, this );
m_browseButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EXPORT_STEP_BASE::onBrowseClicked ), NULL, this );
m_STEP_OrgUnitChoice->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_EXPORT_STEP_BASE::onUpdateUnits ), NULL, this );
m_STEP_Xorg->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_EXPORT_STEP_BASE::onUpdateXPos ), NULL, this );
@ -253,6 +263,7 @@ DIALOG_EXPORT_STEP_BASE::DIALOG_EXPORT_STEP_BASE( wxWindow* parent, wxWindowID i
DIALOG_EXPORT_STEP_BASE::~DIALOG_EXPORT_STEP_BASE()
{
// Disconnect Events
m_choiceFormat->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_EXPORT_STEP_BASE::onFormatChoice ), NULL, this );
m_browseButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EXPORT_STEP_BASE::onBrowseClicked ), NULL, this );
m_STEP_OrgUnitChoice->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_EXPORT_STEP_BASE::onUpdateUnits ), NULL, this );
m_STEP_Xorg->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_EXPORT_STEP_BASE::onUpdateXPos ), NULL, this );

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.0.0-0-g0efcecf)
// C++ code generated with wxFormBuilder (version 4.1.0-0-g733bf3d)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -20,6 +20,7 @@ class TEXT_CTRL_EVAL;
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/choice.h>
#include <wx/textctrl.h>
#include <wx/bmpbuttn.h>
#include <wx/bitmap.h>
@ -27,12 +28,10 @@ class TEXT_CTRL_EVAL;
#include <wx/icon.h>
#include <wx/button.h>
#include <wx/sizer.h>
#include <wx/radiobut.h>
#include <wx/statbox.h>
#include <wx/choice.h>
#include <wx/valtext.h>
#include <wx/checkbox.h>
#include <wx/statline.h>
#include <wx/statbox.h>
#include <wx/radiobut.h>
#include <wx/valtext.h>
#include <wx/dialog.h>
///////////////////////////////////////////////////////////////////////////
@ -47,9 +46,26 @@ class DIALOG_EXPORT_STEP_BASE : public DIALOG_SHIM
protected:
wxBoxSizer* bSizerSTEPFile;
wxBoxSizer* bSizerTop;
wxStaticText* m_txtFormat;
wxChoice* m_choiceFormat;
wxStaticText* m_txtBrdFile;
wxTextCtrl* m_outputFileName;
STD_BITMAP_BUTTON* m_browseButton;
wxCheckBox* m_cbExportCompound_hidden;
wxCheckBox* m_cbExportBody;
wxCheckBox* m_cbExportComponents;
wxCheckBox* m_cbExportTracks;
wxCheckBox* m_cbExportPads;
wxCheckBox* m_cbExportZones;
wxCheckBox* m_cbExportInnerCopper;
wxCheckBox* m_cbExportSilkscreen;
wxCheckBox* m_cbExportSoldermask;
wxCheckBox* m_cbFuseShapes;
wxCheckBox* m_cbExportSolderpaste_hidden;
wxStaticText* m_staticTextNetFilter;
wxTextCtrl* m_txtNetFilter;
wxStaticText* m_staticTextTolerance;
wxChoice* m_choiceTolerance;
wxRadioButton* m_rbDrillAndPlotOrigin;
wxRadioButton* m_rbGridOrigin;
wxRadioButton* m_rbUserDefinedOrigin;
@ -64,28 +80,13 @@ class DIALOG_EXPORT_STEP_BASE : public DIALOG_SHIM
wxCheckBox* m_cbRemoveUnspecified;
wxCheckBox* m_cbSubstModels;
wxCheckBox* m_cbOverwriteFile;
wxStaticLine* m_staticline11_hidden;
wxCheckBox* m_cbOptimizeStep;
wxCheckBox* m_cbExportCompound_hidden;
wxStaticLine* m_staticline1;
wxCheckBox* m_cbExportBody;
wxCheckBox* m_cbExportComponents;
wxCheckBox* m_cbExportTracks;
wxCheckBox* m_cbExportZones;
wxCheckBox* m_cbExportInnerCopper;
wxCheckBox* m_cbFuseShapes;
wxCheckBox* m_cbExportSilkscreen_hidden;
wxCheckBox* m_cbExportSoldermask_hidden;
wxCheckBox* m_cbExportSolderpaste_hidden;
wxStaticText* m_staticTextNetFilter;
wxTextCtrl* m_txtNetFilter;
wxStaticText* m_staticTextTolerance;
wxChoice* m_choiceTolerance;
wxStdDialogButtonSizer* m_sdbSizer;
wxButton* m_sdbSizerOK;
wxButton* m_sdbSizerCancel;
// Virtual event handlers, override them in your derived class
virtual void onFormatChoice( wxCommandEvent& event ) { event.Skip(); }
virtual void onBrowseClicked( wxCommandEvent& event ) { event.Skip(); }
virtual void onUpdateUnits( wxUpdateUIEvent& event ) { event.Skip(); }
virtual void onUpdateXPos( wxUpdateUIEvent& event ) { event.Skip(); }
@ -95,7 +96,7 @@ class DIALOG_EXPORT_STEP_BASE : public DIALOG_SHIM
public:
DIALOG_EXPORT_STEP_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Export STEP / BREP / XAO / GLTF"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
DIALOG_EXPORT_STEP_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Export 3D Model"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
~DIALOG_EXPORT_STEP_BASE();

View File

@ -28,6 +28,7 @@
#include <board.h>
#include <board_design_settings.h>
#include <footprint.h>
#include <pcb_textbox.h>
#include <pcb_track.h>
#include <pcb_shape.h>
#include <pad.h>
@ -149,9 +150,16 @@ EXPORTER_STEP::EXPORTER_STEP( BOARD* aBoard, const EXPORTER_STEP_PARAMS& aParams
m_board( aBoard ),
m_pcbModel( nullptr )
{
m_solderMaskColor = COLOR4D( 0.08, 0.20, 0.14, 0.83 );
m_copperColor = COLOR4D( 0.7, 0.61, 0.0, 1.0 );
if( m_params.m_exportComponents )
m_padColor = COLOR4D( 0.50, 0.50, 0.50, 1.0 );
else
m_padColor = m_copperColor;
// TODO: make configurable
m_platingThickness = pcbIUScale.mmToIU( 0.025 );
// Init m_pcbBaseName to the board short filename (no path, no ext)
// m_pcbName is used later to identify items in step file
wxFileName fn( aBoard->GetFileName() );
@ -177,61 +185,99 @@ bool EXPORTER_STEP::buildFootprint3DShapes( FOOTPRINT* aFootprint, VECTOR2D aOri
{
bool hasdata = false;
std::vector<PAD*> padsMatchingNetFilter;
int maxError = m_board->GetDesignSettings().m_MaxError;
// Dump the pad holes into the PCB
for( PAD* pad : aFootprint->Pads() )
{
if( m_pcbModel->AddPadHole( pad, aOrigin ) )
hasdata = true;
std::shared_ptr<SHAPE_SEGMENT> holeShape = pad->GetEffectiveHoleShape();
SHAPE_POLY_SET holePoly;
holeShape->TransformToPolygon( holePoly, maxError, ERROR_INSIDE );
for( PCB_LAYER_ID pcblayer : pad->GetLayerSet().Seq() )
{
if( pad->IsOnLayer( pcblayer ) )
m_poly_holes[pcblayer].Append( holePoly );
}
if( pad->HasHole() )
{
int platingThickness = pad->GetAttribute() == PAD_ATTRIB::PTH ? m_platingThickness : 0;
if( m_pcbModel->AddHole( *holeShape, platingThickness, F_Cu, B_Cu, false, aOrigin ) )
hasdata = true;
//// Cut holes in silkscreen (buggy: insufficient polyset self-intersection checking)
//if( m_layersToExport.Contains( F_SilkS ) || m_layersToExport.Contains( B_SilkS ) )
//{
// m_poly_holes[F_SilkS].Append( holePoly );
// m_poly_holes[B_SilkS].Append( holePoly );
//}
}
if( !m_params.m_netFilter.IsEmpty() && !pad->GetNetname().Matches( m_params.m_netFilter ) )
continue;
if( m_params.m_exportTracksVias )
if( m_params.m_exportPads )
{
if( m_pcbModel->AddPadShape( pad, aOrigin, false ) )
hasdata = true;
if( m_params.m_exportSoldermask )
{
for( PCB_LAYER_ID pcblayer : pad->GetLayerSet().Seq() )
{
if( pcblayer != F_Mask && pcblayer != B_Mask )
continue;
SHAPE_POLY_SET poly;
pad->TransformShapeToPolygon( poly, pcblayer, pad->GetSolderMaskExpansion(),
maxError, ERROR_INSIDE );
m_poly_shapes[pcblayer].Append( poly );
}
}
}
padsMatchingNetFilter.push_back( pad );
}
// Build 3D shapes of the footprint graphic items on external layers:
if( m_params.m_exportTracksVias )
// Build 3D shapes of the footprint graphic items:
for( PCB_LAYER_ID pcblayer : m_layersToExport.Seq() )
{
int maxError = m_board->GetDesignSettings().m_MaxError;
if( IsCopperLayer( pcblayer ) && !m_params.m_exportTracksVias )
continue;
for( PCB_LAYER_ID pcblayer : LSET( aFootprint->GetLayerSet() & LSET::AllCuMask() ).Seq() )
SHAPE_POLY_SET buffer;
aFootprint->TransformFPShapesToPolySet( buffer, pcblayer, 0, maxError, ERROR_INSIDE,
true, /* include text */
true, /* include shapes */
false /* include private items */ );
if( m_params.m_netFilter.IsEmpty() || !IsCopperLayer( pcblayer ) )
{
SHAPE_POLY_SET buffer;
aFootprint->TransformFPShapesToPolySet( buffer, pcblayer, 0, maxError, ERROR_INSIDE,
false, /* include text */
true, /* include shapes */
false /* include private items */ );
if( m_params.m_netFilter.IsEmpty() )
m_poly_shapes[pcblayer].Append( buffer );
}
else
{
// Only add shapes colliding with any matching pads
for( const SHAPE_POLY_SET::POLYGON& poly : buffer.CPolygons() )
{
m_poly_copper_shapes[pcblayer].Append( buffer );
}
else
{
// Only add shapes colliding with any matching pads
for( const SHAPE_POLY_SET::POLYGON& poly : buffer.CPolygons() )
for( PAD* pad : padsMatchingNetFilter )
{
for( PAD* pad : padsMatchingNetFilter )
if( !pad->IsOnLayer( pcblayer ) )
continue;
std::shared_ptr<SHAPE_POLY_SET> padPoly = pad->GetEffectivePolygon();
SHAPE_POLY_SET gfxPoly( poly );
if( padPoly->Collide( &gfxPoly ) )
{
if( !pad->IsOnLayer( pcblayer ) )
continue;
std::shared_ptr<SHAPE_POLY_SET> padPoly = pad->GetEffectivePolygon();
SHAPE_POLY_SET gfxPoly( poly );
if( padPoly->Collide( &gfxPoly ) )
{
m_poly_copper_shapes[pcblayer].Append( gfxPoly );
break;
}
m_poly_shapes[pcblayer].Append( gfxPoly );
break;
}
}
}
@ -340,25 +386,50 @@ bool EXPORTER_STEP::buildTrack3DShape( PCB_TRACK* aTrack, VECTOR2D aOrigin )
if( !m_params.m_netFilter.IsEmpty() && !aTrack->GetNetname().Matches( m_params.m_netFilter ) )
return true;
int maxError = m_board->GetDesignSettings().m_MaxError;
if( aTrack->Type() == PCB_VIA_T )
{
return m_pcbModel->AddViaShape( static_cast<const PCB_VIA*>( aTrack ), aOrigin );
PCB_VIA* via = static_cast<PCB_VIA*>( aTrack );
std::shared_ptr<SHAPE_SEGMENT> holeShape = via->GetEffectiveHoleShape();
SHAPE_POLY_SET holePoly;
holeShape->TransformToPolygon( holePoly, maxError, ERROR_INSIDE );
LSET layers( via->GetLayerSet() & m_layersToExport );
for( PCB_LAYER_ID pcblayer : layers.Seq() )
{
const std::shared_ptr<SHAPE>& shape = via->GetEffectiveShape( pcblayer );
SHAPE_POLY_SET poly;
shape->TransformToPolygon( poly, maxError, ERROR_INSIDE );
m_poly_shapes[pcblayer].Append( poly );
m_poly_holes[pcblayer].Append( holePoly );
}
//// Cut holes in silkscreen (buggy: insufficient polyset self-intersection checking)
//if( m_layersToExport.Contains( F_SilkS ) || m_layersToExport.Contains( B_SilkS ) )
//{
// m_poly_holes[F_SilkS].Append( holePoly );
// m_poly_holes[B_SilkS].Append( holePoly );
//}
PCB_LAYER_ID top_layer, bot_layer;
via->LayerPair( &top_layer, &bot_layer );
m_pcbModel->AddHole( *holeShape, m_platingThickness, top_layer, bot_layer, true, aOrigin );
m_pcbModel->AddBarrel( *holeShape, top_layer, bot_layer, true, aOrigin );
return true;
}
PCB_LAYER_ID pcblayer = aTrack->GetLayer();
if( !IsCopperLayer( pcblayer ) )
if( !m_layersToExport.Contains( pcblayer ) )
return false;
if( aTrack->Type() == PCB_ARC_T )
{
int maxError = m_board->GetDesignSettings().m_MaxError;
aTrack->TransformShapeToPolygon( m_poly_copper_shapes[pcblayer], pcblayer, 0, maxError,
ERROR_INSIDE );
}
else
m_pcbModel->AddTrackSegment( aTrack, aOrigin );
aTrack->TransformShapeToPolygon( m_poly_shapes[pcblayer], pcblayer, 0, maxError, ERROR_INSIDE );
return true;
}
@ -368,19 +439,23 @@ void EXPORTER_STEP::buildZones3DShape( VECTOR2D aOrigin )
{
for( ZONE* zone : m_board->Zones() )
{
if( !m_params.m_netFilter.IsEmpty() && !zone->GetNetname().Matches( m_params.m_netFilter ) )
continue;
LSET layers = zone->GetLayerSet();
for( PCB_LAYER_ID layer : zone->GetLayerSet().CuStack() )
if( ( layers & LSET::AllCuMask() ).count() && !m_params.m_netFilter.IsEmpty()
&& !zone->GetNetname().Matches( m_params.m_netFilter ) )
{
SHAPE_POLY_SET copper_shape;
zone->TransformSolidAreasShapesToPolygon( layer, copper_shape );
copper_shape.Unfracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
continue;
}
copper_shape.SimplifyOutlines(
ADVANCED_CFG::GetCfg().m_TriangulateSimplificationLevel );
for( PCB_LAYER_ID layer : layers.Seq() )
{
SHAPE_POLY_SET fill_shape;
zone->TransformSolidAreasShapesToPolygon( layer, fill_shape );
fill_shape.Unfracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
m_pcbModel->AddCopperPolygonShapes( &copper_shape, layer, aOrigin, false );
fill_shape.SimplifyOutlines( ADVANCED_CFG::GetCfg().m_TriangulateSimplificationLevel );
m_poly_shapes[layer].Append( fill_shape );
}
}
}
@ -388,23 +463,53 @@ void EXPORTER_STEP::buildZones3DShape( VECTOR2D aOrigin )
bool EXPORTER_STEP::buildGraphic3DShape( BOARD_ITEM* aItem, VECTOR2D aOrigin )
{
PCB_SHAPE* graphic = dynamic_cast<PCB_SHAPE*>( aItem );
PCB_LAYER_ID pcblayer = aItem->GetLayer();
if( !graphic )
return false;
if( !m_params.m_netFilter.IsEmpty() && !graphic->GetNetname().Matches( m_params.m_netFilter ) )
return true;
PCB_LAYER_ID pcblayer = graphic->GetLayer();
if( !IsCopperLayer( pcblayer ) )
if( !m_layersToExport.Contains( pcblayer ) )
return false;
int maxError = m_board->GetDesignSettings().m_MaxError;
graphic->TransformShapeToPolygon( m_poly_copper_shapes[pcblayer], pcblayer, 0, maxError,
ERROR_INSIDE );
switch( aItem->Type() )
{
case PCB_SHAPE_T:
{
PCB_SHAPE* graphic = static_cast<PCB_SHAPE*>( aItem );
if( IsCopperLayer( pcblayer ) && !m_params.m_netFilter.IsEmpty()
&& !graphic->GetNetname().Matches( m_params.m_netFilter ) )
{
return true;
}
graphic->TransformShapeToPolygon( m_poly_shapes[pcblayer], pcblayer, 0, maxError,
ERROR_INSIDE );
break;
}
case PCB_TEXT_T:
{
PCB_TEXT* text = static_cast<PCB_TEXT*>( aItem );
text->TransformTextToPolySet( m_poly_shapes[pcblayer], 0, maxError, ERROR_INSIDE );
break;
}
case PCB_TEXTBOX_T:
{
PCB_TEXTBOX* textbox = static_cast<PCB_TEXTBOX*>( aItem );
textbox->TransformTextToPolySet( m_poly_shapes[pcblayer], 0, maxError, ERROR_INSIDE );
break;
}
case PCB_TABLE_T:
// JEY TODO: tables
break;
default: wxFAIL_MSG( "buildGraphic3DShape: unhandled item type" );
}
return true;
}
@ -424,13 +529,6 @@ bool EXPORTER_STEP::buildBoard3DShapes()
wxLogWarning( _( "Board outline is malformed. Run DRC for a full analysis." ) );
}
LSET layersToExport = LSET::ExternalCuMask();
if( m_params.m_exportInnerCopper )
layersToExport |= LSET::InternalCuMask();
layersToExport &= m_board->GetEnabledLayers();
VECTOR2D origin;
// Determine the coordinate system reference:
@ -444,12 +542,11 @@ bool EXPORTER_STEP::buildBoard3DShapes()
m_pcbModel = std::make_unique<STEP_PCB_MODEL>( m_pcbBaseName );
// TODO: Handle when top & bottom soldermask colours are different...
m_pcbModel->SetBoardColor( m_solderMaskColor.r, m_solderMaskColor.g, m_solderMaskColor.b );
m_pcbModel->SetCopperColor( m_copperColor.r, m_copperColor.g, m_copperColor.b );
m_pcbModel->SetPadColor( m_padColor.r, m_padColor.g, m_padColor.b );
m_pcbModel->SetStackup( m_board->GetStackupOrDefault() );
m_pcbModel->SetEnabledLayers( layersToExport );
m_pcbModel->SetEnabledLayers( m_layersToExport );
m_pcbModel->SetFuseShapes( m_params.m_fuseShapes );
m_pcbModel->SetNetFilter( m_params.m_netFilter );
@ -473,15 +570,45 @@ bool EXPORTER_STEP::buildBoard3DShapes()
{
for( PCB_TRACK* track : m_board->Tracks() )
buildTrack3DShape( track, origin );
for( BOARD_ITEM* item : m_board->Drawings() )
buildGraphic3DShape( item, origin );
}
for( PCB_LAYER_ID pcblayer : layersToExport.Seq() )
for( BOARD_ITEM* item : m_board->Drawings() )
buildGraphic3DShape( item, origin );
SHAPE_POLY_SET pcbOutlinesNoArcs = pcbOutlines;
pcbOutlinesNoArcs.ClearArcs();
for( PCB_LAYER_ID pcblayer : m_layersToExport.Seq() )
{
m_pcbModel->AddCopperPolygonShapes( &m_poly_copper_shapes[pcblayer], pcblayer, origin,
true );
SHAPE_POLY_SET poly = m_poly_shapes[pcblayer];
poly.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
poly.SimplifyOutlines( pcbIUScale.mmToIU( 0.003 ) );
poly.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
SHAPE_POLY_SET holes = m_poly_holes[pcblayer];
holes.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
// Mask layer is negative
if( pcblayer == F_Mask || pcblayer == B_Mask )
{
SHAPE_POLY_SET mask = pcbOutlinesNoArcs;
mask.BooleanSubtract( poly, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
mask.BooleanSubtract( holes, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
poly = mask;
}
else
{
// Subtract holes
poly.BooleanSubtract( holes, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
// Clip to board outline
poly.BooleanIntersection( pcbOutlinesNoArcs, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
}
m_pcbModel->AddPolygonShapes( &poly, pcblayer, origin );
}
if( m_params.m_exportZones )
@ -525,6 +652,25 @@ bool EXPORTER_STEP::Export()
m_params.m_outputFile = fn.GetFullName();
}
m_layersToExport = LSET::ExternalCuMask();
if( m_params.m_exportInnerCopper )
m_layersToExport |= LSET::InternalCuMask();
if( m_params.m_exportSilkscreen )
{
m_layersToExport.set( F_SilkS );
m_layersToExport.set( B_SilkS );
}
if( m_params.m_exportSoldermask )
{
m_layersToExport.set( F_Mask );
m_layersToExport.set( B_Mask );
}
m_layersToExport &= m_board->GetEnabledLayers();
try
{
ReportMessage( wxString::Format( _( "Build %s data\n" ), m_params.GetFormatName() ) );

View File

@ -58,8 +58,11 @@ public:
m_exportBoardBody( true ),
m_exportComponents( true ),
m_exportTracksVias( false ),
m_exportPads( false ),
m_exportZones( false ),
m_exportInnerCopper( false ),
m_exportSilkscreen( false ),
m_exportSoldermask( false ),
m_fuseShapes( false ),
m_optimizeStep( true ),
m_format( FORMAT::STEP )
@ -89,8 +92,11 @@ public:
bool m_exportBoardBody;
bool m_exportComponents;
bool m_exportTracksVias;
bool m_exportPads;
bool m_exportZones;
bool m_exportInnerCopper;
bool m_exportSilkscreen;
bool m_exportSoldermask;
bool m_fuseShapes;
bool m_optimizeStep;
FORMAT m_format;
@ -135,10 +141,15 @@ private:
/// used to identify items in step file
wxString m_pcbBaseName;
std::map<PCB_LAYER_ID, SHAPE_POLY_SET> m_poly_copper_shapes;
std::map<PCB_LAYER_ID, SHAPE_POLY_SET> m_poly_shapes;
std::map<PCB_LAYER_ID, SHAPE_POLY_SET> m_poly_holes;
KIGFX::COLOR4D m_solderMaskColor;
KIGFX::COLOR4D m_copperColor;
LSET m_layersToExport;
KIGFX::COLOR4D m_copperColor;
KIGFX::COLOR4D m_padColor;
int m_platingThickness; // plating thickness for TH pads/vias
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -81,36 +81,34 @@ public:
STEP_PCB_MODEL( const wxString& aPcbName );
virtual ~STEP_PCB_MODEL();
// add a pad hole or slot (must be in final position)
bool AddPadHole( const PAD* aPad, const VECTOR2D& aOrigin );
// add a pad shape (must be in final position)
bool AddPadShape( const PAD* aPad, const VECTOR2D& aOrigin, bool aVia );
// add a via shape
bool AddViaShape( const PCB_VIA* aVia, const VECTOR2D& aOrigin );
// add a pad hole or slot (must be in final position)
bool AddHole( const SHAPE_SEGMENT& aShape, int aPlatingThickness, PCB_LAYER_ID aLayerTop,
PCB_LAYER_ID aLayerBot, bool aVia, const VECTOR2D& aOrigin );
// add a track segment shape (do not use it for track arcs)
bool AddTrackSegment( const PCB_TRACK* aTrack, const VECTOR2D& aOrigin );
// add a plated hole shape (without the hole)
bool AddBarrel( const SHAPE_SEGMENT& aShape, PCB_LAYER_ID aLayerTop, PCB_LAYER_ID aLayerBot,
bool aVia, const VECTOR2D& aOrigin );
// add a set of polygons (must be in final position) on top or bottom of the board as copper
bool AddCopperPolygonShapes( const SHAPE_POLY_SET* aPolyShapes, PCB_LAYER_ID aLayer,
const VECTOR2D& aOrigin, bool aTrack );
// add a set of polygons (must be in final position)
bool AddPolygonShapes( const SHAPE_POLY_SET* aPolyShapes, PCB_LAYER_ID aLayer,
const VECTOR2D& aOrigin );
// add a component at the given position and orientation
bool AddComponent( const std::string& aFileName, const std::string& aRefDes, bool aBottom,
VECTOR2D aPosition, double aRotation, VECTOR3D aOffset,
VECTOR3D aOrientation, VECTOR3D aScale, bool aSubstituteModels = true );
void SetBoardColor( double r, double g, double b );
void SetCopperColor( double r, double g, double b );
void SetPadColor( double r, double g, double b );
void SetEnabledLayers( const LSET& aLayers );
void SetFuseShapes( bool aValue );
void SetSimplifyShapes( bool aValue );
void SetAddVisMaterials( bool aValue );
void SetStackup( const BOARD_STACKUP& aStackup );
void SetNetFilter( const wxString& aFilter );
// Set the max distance (in mm) to consider 2 points have the same coordinates
@ -123,11 +121,11 @@ public:
bool CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin, bool aPushBoardBody );
/**
* Convert a SHAPE_POLY_SET to TopoDS_Shape's (polygonal vertical prisms)
* Convert a SHAPE_POLY_SET to TopoDS_Shape's (polygonal vertical prisms, or flat faces)
* @param aShapes is the TopoDS_Shape list to append to
* @param aPolySet is a polygon set
* @param aConvertToArcs set to approximate with arcs
* @param aThickness is the height of the created prism
* @param aThickness is the height of the created prism, or 0.0: flat face pointing up, -0.0: down.
* @param aOrigin is the origin of the coordinates
* @return true if success
*/
@ -136,27 +134,13 @@ public:
const VECTOR2D& aOrigin );
/**
* Convert a SHAPE_LINE_CHAIN containing only one 360 deg arc to a TopoDS_Shape
* ( vertical cylinder)
* it is a specialized version of MakeShape()
* @param aShape is the TopoDS_Shape to initialize (must be empty)
* @param aChain is a closed SHAPE_LINE_CHAIN, image of a circle: containing one 360 deg arc
* @param aThickness is the height of the created cylinder
* @param aOrigin is the origin of the coordinates
* @return true if success
*/
bool MakeShapeAsCylinder( TopoDS_Shape& aShape, const SHAPE_LINE_CHAIN& aChain,
double aThickness, double aZposition, const VECTOR2D& aOrigin );
/**
* Convert a SHAPE_LINE_CHAIN containing only one 360 deg arc to a TopoDS_Shape
* ( vertical cylinder)
* it is a specialized version of MakeShape()
* Make a segment shape based on start and end point. If they're too close, make a cylinder.
* It is a specialized version of MakeShape()
* @param aShape is the TopoDS_Shape to initialize (must be empty)
* @param aStartPoint is the start point of the segment
* @param aEndPoint is the end point of the segment
* @param aWidth is the width of the segment
* @param aThickness is the height of the created cylinder
* @param aThickness is the height of the created segment, or 0.0: flat face pointing up, -0.0: down.
* @param aOrigin is the origin of the coordinates
* @return true if success
*/
@ -237,15 +221,15 @@ private:
Handle( XCAFDoc_ShapeTool ) m_assy;
TDF_Label m_assy_label;
bool m_hasPCB; // set true if CreatePCB() has been invoked
bool m_simplifyShapes; // convert parts of outlines to arcs where possible
bool m_fuseShapes; // fuse geometry together
int m_platingThickness; // plating thickness for TH pads/vias
std::vector<TDF_Label> m_pcb_labels; // labels for the PCB model (one by main outline)
MODEL_MAP m_models; // map of file names to model labels
int m_components; // number of successfully loaded components;
double m_precision; // model (length unit) numeric precision
double m_angleprec; // angle numeric precision
double m_boardColor[3]; // board body, RGB values
double m_copperColor[3]; // copper, RGB values
double m_padColor[3]; // pads, RGB values
BOARD_STACKUP m_stackup; // board stackup
LSET m_enabledLayers; // a set of layers enabled for export
wxString m_netFilter; // remove nets not matching this wildcard
@ -260,10 +244,12 @@ private:
// Main outlines (more than one board)
std::vector<TopoDS_Shape> m_board_outlines;
std::vector<TopoDS_Shape> m_board_copper_zones;
std::vector<TopoDS_Shape> m_board_copper_tracks;
std::vector<TopoDS_Shape> m_board_copper;
std::vector<TopoDS_Shape> m_board_copper_pads;
std::vector<TopoDS_Shape> m_board_copper_vias;
std::vector<TopoDS_Shape> m_board_copper_fused;
std::vector<TopoDS_Shape> m_board_silkscreen;
std::vector<TopoDS_Shape> m_board_soldermask;
// Data for pads
std::map<wxString, std::pair<gp_Pnt, TopoDS_Shape>> m_pad_points;

View File

@ -133,7 +133,8 @@ void PCB_EDIT_FRAME::doReCreateMenuBar()
ID_GEN_EXPORT_FILE_VRML, BITMAPS::export3d );
submenuExport->Add( _( "IDFv3..." ), _( "Export IDF 3D board representation" ),
ID_GEN_EXPORT_FILE_IDF3, BITMAPS::export_idf );
submenuExport->Add( _( "STEP / BREP / XAO..." ), _( "Export STEP / BREP / XAO 3D board representation" ),
submenuExport->Add( _( "STEP / GLB / BREP / XAO..." ),
_( "Export STEP / GLB / BREP / XAO 3D board representation" ),
ID_GEN_EXPORT_FILE_STEP, BITMAPS::export_step );
submenuExport->Add( _( "SVG..." ), _( "Export SVG board representation" ),
ID_GEN_PLOT_SVG, BITMAPS::export_svg );

View File

@ -195,8 +195,11 @@ int PCBNEW_JOBS_HANDLER::JobExportStep( JOB* aJob )
params.m_exportBoardBody = aStepJob->m_exportBoardBody;
params.m_exportComponents = aStepJob->m_exportComponents;
params.m_exportTracksVias = aStepJob->m_exportTracks;
params.m_exportPads = aStepJob->m_exportPads;
params.m_exportZones = aStepJob->m_exportZones;
params.m_exportInnerCopper = aStepJob->m_exportInnerCopper;
params.m_exportSilkscreen = aStepJob->m_exportSilkscreen;
params.m_exportSoldermask = aStepJob->m_exportSoldermask;
params.m_fuseShapes = aStepJob->m_fuseShapes;
params.m_includeUnspecified = aStepJob->m_includeUnspecified;
params.m_includeDNP = aStepJob->m_includeDNP;