vrml exporter: more cleaning code and enhancements. Dialog exporter: Add option to use board center as coord origin.

This commit is contained in:
jean-pierre charras 2021-03-17 14:26:26 +01:00
parent b050823c98
commit 074f0432f0
9 changed files with 850 additions and 782 deletions

View File

@ -1,7 +1,3 @@
/**
* @file dialog_export_vrml.cpp
*/
/* /*
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
@ -26,6 +22,10 @@
* or you may write to the Free Software Foundation, Inc., * or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
/**
* @file dialog_export_vrml.cpp
*/
#include <wx/dir.h> #include <wx/dir.h>
#include <board.h> #include <board.h>
@ -53,6 +53,8 @@ private:
int m_RefUnits; // Remember last units for Reference Point int m_RefUnits; // Remember last units for Reference Point
double m_XRef; // Remember last X Reference Point double m_XRef; // Remember last X Reference Point
double m_YRef; // Remember last Y Reference Point double m_YRef; // Remember last Y Reference Point
int m_originMode; // Origin selection option
// (0 = user, 1 = board center)
public: public:
DIALOG_EXPORT_3DFILE( PCB_EDIT_FRAME* parent ) : DIALOG_EXPORT_3DFILE( PCB_EDIT_FRAME* parent ) :
@ -60,7 +62,7 @@ public:
{ {
m_filePicker->SetFocus(); m_filePicker->SetFocus();
auto cfg = m_parent->GetPcbNewSettings(); PCBNEW_SETTINGS* cfg = m_parent->GetPcbNewSettings();
m_unitsOpt = cfg->m_ExportVrml.units; m_unitsOpt = cfg->m_ExportVrml.units;
m_copy3DFilesOpt = cfg->m_ExportVrml.copy_3d_models; m_copy3DFilesOpt = cfg->m_ExportVrml.copy_3d_models;
@ -69,7 +71,10 @@ public:
m_RefUnits = cfg->m_ExportVrml.ref_units; m_RefUnits = cfg->m_ExportVrml.ref_units;
m_XRef = cfg->m_ExportVrml.ref_x; m_XRef = cfg->m_ExportVrml.ref_x;
m_YRef = cfg->m_ExportVrml.ref_y; m_YRef = cfg->m_ExportVrml.ref_y;
m_originMode = cfg->m_ExportVrml.origin_mode;
m_rbCoordOrigin->SetSelection( m_originMode );
m_rbSelectUnits->SetSelection( m_unitsOpt ); m_rbSelectUnits->SetSelection( m_unitsOpt );
m_cbCopyFiles->SetValue( m_copy3DFilesOpt ); m_cbCopyFiles->SetValue( m_copy3DFilesOpt );
m_cbUseRelativePaths->SetValue( m_useRelativePathsOpt ); m_cbUseRelativePaths->SetValue( m_useRelativePathsOpt );
@ -81,13 +86,10 @@ public:
tmpStr = wxT( "" ); tmpStr = wxT( "" );
tmpStr << m_YRef; tmpStr << m_YRef;
m_VRML_Yref->SetValue( tmpStr ); m_VRML_Yref->SetValue( tmpStr );
m_sdbSizer1OK->SetDefault(); m_sdbSizerOK->SetDefault();
// Now all widgets have the size fixed, call FinishDialogSettings // Now all widgets have the size fixed, call FinishDialogSettings
finishDialogSettings(); finishDialogSettings();
Connect( ID_USE_ABS_PATH, wxEVT_UPDATE_UI,
wxUpdateUIEventHandler( DIALOG_EXPORT_3DFILE::OnUpdateUseRelativePath ) );
} }
~DIALOG_EXPORT_3DFILE() ~DIALOG_EXPORT_3DFILE()
@ -95,13 +97,14 @@ public:
m_unitsOpt = GetUnits(); m_unitsOpt = GetUnits();
m_copy3DFilesOpt = GetCopyFilesOption(); m_copy3DFilesOpt = GetCopyFilesOption();
auto cfg = m_parent->GetPcbNewSettings(); PCBNEW_SETTINGS* cfg = m_parent->GetPcbNewSettings();
cfg->m_ExportVrml.units = m_unitsOpt; cfg->m_ExportVrml.units = m_unitsOpt;
cfg->m_ExportVrml.copy_3d_models = m_copy3DFilesOpt; cfg->m_ExportVrml.copy_3d_models = m_copy3DFilesOpt;
cfg->m_ExportVrml.use_relative_paths = m_useRelativePathsOpt; cfg->m_ExportVrml.use_relative_paths = m_useRelativePathsOpt;
cfg->m_ExportVrml.use_plain_pcb = m_usePlainPCBOpt; cfg->m_ExportVrml.use_plain_pcb = m_usePlainPCBOpt;
cfg->m_ExportVrml.ref_units = m_VRML_RefUnitChoice->GetSelection(); cfg->m_ExportVrml.ref_units = m_VRML_RefUnitChoice->GetSelection();
cfg->m_ExportVrml.origin_mode = m_rbCoordOrigin->GetSelection();
double val = 0.0; double val = 0.0;
m_VRML_Xref->GetValue().ToDouble( &val ); m_VRML_Xref->GetValue().ToDouble( &val );
@ -131,6 +134,11 @@ public:
return m_VRML_RefUnitChoice->GetSelection(); return m_VRML_RefUnitChoice->GetSelection();
} }
int GetOriginChoice()
{
return m_rbCoordOrigin->GetSelection();
}
double GetXRef() double GetXRef()
{ {
return DoubleValueFromString( EDA_UNITS::UNSCALED, m_VRML_Xref->GetValue() ); return DoubleValueFromString( EDA_UNITS::UNSCALED, m_VRML_Xref->GetValue() );
@ -161,7 +169,7 @@ public:
return m_usePlainPCBOpt = m_cbPlainPCB->GetValue(); return m_usePlainPCBOpt = m_cbPlainPCB->GetValue();
} }
void OnUpdateUseRelativePath( wxUpdateUIEvent& event ) void OnUpdateUseRelativePath( wxUpdateUIEvent& event ) override
{ {
// Making path relative or absolute has no meaning when VRML files are not copied. // Making path relative or absolute has no meaning when VRML files are not copied.
event.Enable( m_cbCopyFiles->GetValue() ); event.Enable( m_cbCopyFiles->GetValue() );
@ -226,6 +234,15 @@ void PCB_EDIT_FRAME::OnExportVRML( wxCommandEvent& event )
aYRef *= 25.4; aYRef *= 25.4;
} }
if( dlg.GetOriginChoice() == 1 )
{
// Origin = board center:
BOARD* pcb = GetBoard();
wxPoint center = pcb->GetBoundingBox().GetCenter();
aXRef = Iu2Millimeter( center.x );
aYRef = Iu2Millimeter( center.y );
}
double scale = scaleList[dlg.GetUnits()]; // final scale export double scale = scaleList[dlg.GetUnits()]; // final scale export
bool export3DFiles = dlg.GetCopyFilesOption(); bool export3DFiles = dlg.GetCopyFilesOption();
bool useRelativePaths = dlg.GetUseRelativePathsOption(); bool useRelativePaths = dlg.GetUseRelativePathsOption();

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.9.0 Nov 1 2020) // C++ code generated with wxFormBuilder (version Oct 26 2018)
// http://www.wxformbuilder.org/ // http://www.wxformbuilder.org/
// //
// PLEASE DO *NOT* EDIT THIS FILE! // PLEASE DO *NOT* EDIT THIS FILE!
@ -38,19 +38,21 @@ DIALOG_EXPORT_3DFILE_BASE::DIALOG_EXPORT_3DFILE_BASE( wxWindow* parent, wxWindow
bSizer1->Add( bUpperSizer, 0, wxALL|wxEXPAND, 5 ); bSizer1->Add( bUpperSizer, 0, wxALL|wxEXPAND, 5 );
wxBoxSizer* bSizer12; wxBoxSizer* bSizerOptions;
bSizer12 = new wxBoxSizer( wxHORIZONTAL ); bSizerOptions = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* bSizer5; wxString m_rbCoordOriginChoices[] = { _("User defined origin"), _("Board center origin") };
bSizer5 = new wxBoxSizer( wxVERTICAL ); int m_rbCoordOriginNChoices = sizeof( m_rbCoordOriginChoices ) / sizeof( wxString );
m_rbCoordOrigin = new wxRadioBox( this, wxID_ANY, _("Coordinate origin options:"), wxDefaultPosition, wxDefaultSize, m_rbCoordOriginNChoices, m_rbCoordOriginChoices, 1, wxRA_SPECIFY_COLS );
m_rbCoordOrigin->SetSelection( 0 );
bSizerOptions->Add( m_rbCoordOrigin, 1, wxALL|wxEXPAND, 5 );
m_panel1 = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); wxBoxSizer* bSizerVrmlUnits;
wxBoxSizer* bSizer9; bSizerVrmlUnits = new wxBoxSizer( wxVERTICAL );
bSizer9 = new wxBoxSizer( wxVERTICAL );
m_staticText6 = new wxStaticText( m_panel1, wxID_ANY, _("Grid reference point:"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText6 = new wxStaticText( this, wxID_ANY, _("User defined origin:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText6->Wrap( -1 ); m_staticText6->Wrap( -1 );
bSizer9->Add( m_staticText6, 0, wxALL, 5 ); bSizerVrmlUnits->Add( m_staticText6, 0, wxALL, 5 );
wxFlexGridSizer* fgSizerOptions; wxFlexGridSizer* fgSizerOptions;
fgSizerOptions = new wxFlexGridSizer( 0, 2, 0, 0 ); fgSizerOptions = new wxFlexGridSizer( 0, 2, 0, 0 );
@ -58,21 +60,21 @@ DIALOG_EXPORT_3DFILE_BASE::DIALOG_EXPORT_3DFILE_BASE( wxWindow* parent, wxWindow
fgSizerOptions->SetFlexibleDirection( wxBOTH ); fgSizerOptions->SetFlexibleDirection( wxBOTH );
fgSizerOptions->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); fgSizerOptions->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_staticText61 = new wxStaticText( m_panel1, wxID_ANY, _("Units:"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText61 = new wxStaticText( this, wxID_ANY, _("Units:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText61->Wrap( -1 ); m_staticText61->Wrap( -1 );
fgSizerOptions->Add( m_staticText61, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); fgSizerOptions->Add( m_staticText61, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
wxString m_VRML_RefUnitChoiceChoices[] = { _("mm"), _("inch") }; wxString m_VRML_RefUnitChoiceChoices[] = { _("mm"), _("inch") };
int m_VRML_RefUnitChoiceNChoices = sizeof( m_VRML_RefUnitChoiceChoices ) / sizeof( wxString ); int m_VRML_RefUnitChoiceNChoices = sizeof( m_VRML_RefUnitChoiceChoices ) / sizeof( wxString );
m_VRML_RefUnitChoice = new wxChoice( m_panel1, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_VRML_RefUnitChoiceNChoices, m_VRML_RefUnitChoiceChoices, 0 ); m_VRML_RefUnitChoice = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_VRML_RefUnitChoiceNChoices, m_VRML_RefUnitChoiceChoices, 0 );
m_VRML_RefUnitChoice->SetSelection( 0 ); m_VRML_RefUnitChoice->SetSelection( 0 );
fgSizerOptions->Add( m_VRML_RefUnitChoice, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); fgSizerOptions->Add( m_VRML_RefUnitChoice, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
m_staticText4 = new wxStaticText( m_panel1, wxID_ANY, _("X:"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText4 = new wxStaticText( this, wxID_ANY, _("X:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText4->Wrap( -1 ); m_staticText4->Wrap( -1 );
fgSizerOptions->Add( m_staticText4, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); fgSizerOptions->Add( m_staticText4, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
m_VRML_Xref = new wxTextCtrl( m_panel1, wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0 ); m_VRML_Xref = new wxTextCtrl( this, wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0 );
#ifdef __WXGTK__ #ifdef __WXGTK__
if ( !m_VRML_Xref->HasFlag( wxTE_MULTILINE ) ) if ( !m_VRML_Xref->HasFlag( wxTE_MULTILINE ) )
{ {
@ -83,11 +85,11 @@ DIALOG_EXPORT_3DFILE_BASE::DIALOG_EXPORT_3DFILE_BASE( wxWindow* parent, wxWindow
#endif #endif
fgSizerOptions->Add( m_VRML_Xref, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 ); fgSizerOptions->Add( m_VRML_Xref, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 );
m_staticText5 = new wxStaticText( m_panel1, wxID_ANY, _("Y:"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText5 = new wxStaticText( this, wxID_ANY, _("Y:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText5->Wrap( -1 ); m_staticText5->Wrap( -1 );
fgSizerOptions->Add( m_staticText5, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); fgSizerOptions->Add( m_staticText5, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
m_VRML_Yref = new wxTextCtrl( m_panel1, wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0 ); m_VRML_Yref = new wxTextCtrl( this, wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0 );
#ifdef __WXGTK__ #ifdef __WXGTK__
if ( !m_VRML_Yref->HasFlag( wxTE_MULTILINE ) ) if ( !m_VRML_Yref->HasFlag( wxTE_MULTILINE ) )
{ {
@ -99,25 +101,19 @@ DIALOG_EXPORT_3DFILE_BASE::DIALOG_EXPORT_3DFILE_BASE( wxWindow* parent, wxWindow
fgSizerOptions->Add( m_VRML_Yref, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 ); fgSizerOptions->Add( m_VRML_Yref, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 );
bSizer9->Add( fgSizerOptions, 1, wxEXPAND, 5 ); bSizerVrmlUnits->Add( fgSizerOptions, 1, wxEXPAND, 5 );
m_panel1->SetSizer( bSizer9 ); bSizerOptions->Add( bSizerVrmlUnits, 1, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_panel1->Layout();
bSizer9->Fit( m_panel1 );
bSizer5->Add( m_panel1, 1, wxEXPAND | wxALL, 5 );
bSizer12->Add( bSizer5, 1, wxEXPAND, 5 );
wxString m_rbSelectUnitsChoices[] = { _("mm"), _("meter"), _("0.1 Inch"), _("Inch") }; wxString m_rbSelectUnitsChoices[] = { _("mm"), _("meter"), _("0.1 Inch"), _("Inch") };
int m_rbSelectUnitsNChoices = sizeof( m_rbSelectUnitsChoices ) / sizeof( wxString ); int m_rbSelectUnitsNChoices = sizeof( m_rbSelectUnitsChoices ) / sizeof( wxString );
m_rbSelectUnits = new wxRadioBox( this, wxID_ANY, _("Output Units"), wxDefaultPosition, wxDefaultSize, m_rbSelectUnitsNChoices, m_rbSelectUnitsChoices, 1, wxRA_SPECIFY_COLS ); m_rbSelectUnits = new wxRadioBox( this, wxID_ANY, _("Vrml Units for Output Files"), wxDefaultPosition, wxDefaultSize, m_rbSelectUnitsNChoices, m_rbSelectUnitsChoices, 1, wxRA_SPECIFY_COLS );
m_rbSelectUnits->SetSelection( 0 ); m_rbSelectUnits->SetSelection( 0 );
bSizer12->Add( m_rbSelectUnits, 1, wxALL|wxEXPAND, 5 ); bSizerOptions->Add( m_rbSelectUnits, 1, wxALL|wxEXPAND, 5 );
bSizer1->Add( bSizer12, 0, wxEXPAND, 5 ); bSizer1->Add( bSizerOptions, 0, wxEXPAND, 5 );
wxBoxSizer* bLowerSizer; wxBoxSizer* bLowerSizer;
bLowerSizer = new wxBoxSizer( wxHORIZONTAL ); bLowerSizer = new wxBoxSizer( wxHORIZONTAL );
@ -126,10 +122,11 @@ DIALOG_EXPORT_3DFILE_BASE::DIALOG_EXPORT_3DFILE_BASE( wxWindow* parent, wxWindow
bSizer4 = new wxBoxSizer( wxVERTICAL ); bSizer4 = new wxBoxSizer( wxVERTICAL );
m_cbCopyFiles = new wxCheckBox( this, wxID_ANY, _("Copy 3D model files to 3D model path"), wxDefaultPosition, wxDefaultSize, 0 ); m_cbCopyFiles = new wxCheckBox( this, wxID_ANY, _("Copy 3D model files to 3D model path"), wxDefaultPosition, wxDefaultSize, 0 );
m_cbCopyFiles->SetValue(true); m_cbCopyFiles->SetToolTip( _("If checked: copy footprints 3D models in a folder\nIf not checked: merge footprints 3D models in the vrml board file\n") );
bSizer4->Add( m_cbCopyFiles, 0, wxALL, 5 ); bSizer4->Add( m_cbCopyFiles, 0, wxALL, 5 );
m_cbUseRelativePaths = new wxCheckBox( this, ID_USE_ABS_PATH, _("Use relative paths to model files in board VRML file"), wxDefaultPosition, wxDefaultSize, 0 ); m_cbUseRelativePaths = new wxCheckBox( this, wxID_ANY, _("Use relative paths to model files in board VRML file"), wxDefaultPosition, wxDefaultSize, 0 );
m_cbUseRelativePaths->SetToolTip( _("Use paths for model files in board VRML file relative to the vrml file") ); m_cbUseRelativePaths->SetToolTip( _("Use paths for model files in board VRML file relative to the vrml file") );
bSizer4->Add( m_cbUseRelativePaths, 0, wxALL, 5 ); bSizer4->Add( m_cbUseRelativePaths, 0, wxALL, 5 );
@ -149,21 +146,27 @@ DIALOG_EXPORT_3DFILE_BASE::DIALOG_EXPORT_3DFILE_BASE( wxWindow* parent, wxWindow
m_staticline1 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); m_staticline1 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
bSizer1->Add( m_staticline1, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 ); bSizer1->Add( m_staticline1, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 );
m_sdbSizer1 = new wxStdDialogButtonSizer(); m_sdbSizer = new wxStdDialogButtonSizer();
m_sdbSizer1OK = new wxButton( this, wxID_OK ); m_sdbSizerOK = new wxButton( this, wxID_OK );
m_sdbSizer1->AddButton( m_sdbSizer1OK ); m_sdbSizer->AddButton( m_sdbSizerOK );
m_sdbSizer1Cancel = new wxButton( this, wxID_CANCEL ); m_sdbSizerCancel = new wxButton( this, wxID_CANCEL );
m_sdbSizer1->AddButton( m_sdbSizer1Cancel ); m_sdbSizer->AddButton( m_sdbSizerCancel );
m_sdbSizer1->Realize(); m_sdbSizer->Realize();
bSizer1->Add( m_sdbSizer1, 0, wxEXPAND|wxALL, 5 ); bSizer1->Add( m_sdbSizer, 0, wxEXPAND|wxALL, 5 );
this->SetSizer( bSizer1 ); this->SetSizer( bSizer1 );
this->Layout(); this->Layout();
bSizer1->Fit( this ); bSizer1->Fit( this );
// Connect Events
m_cbUseRelativePaths->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_EXPORT_3DFILE_BASE::OnUpdateUseRelativePath ), NULL, this );
} }
DIALOG_EXPORT_3DFILE_BASE::~DIALOG_EXPORT_3DFILE_BASE() DIALOG_EXPORT_3DFILE_BASE::~DIALOG_EXPORT_3DFILE_BASE()
{ {
// Disconnect Events
m_cbUseRelativePaths->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_EXPORT_3DFILE_BASE::OnUpdateUseRelativePath ), NULL, this );
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.9.0 Nov 1 2020) // C++ code generated with wxFormBuilder (version Oct 26 2018)
// http://www.wxformbuilder.org/ // http://www.wxformbuilder.org/
// //
// PLEASE DO *NOT* EDIT THIS FILE! // PLEASE DO *NOT* EDIT THIS FILE!
@ -20,9 +20,8 @@
#include <wx/filepicker.h> #include <wx/filepicker.h>
#include <wx/textctrl.h> #include <wx/textctrl.h>
#include <wx/sizer.h> #include <wx/sizer.h>
#include <wx/choice.h>
#include <wx/panel.h>
#include <wx/radiobox.h> #include <wx/radiobox.h>
#include <wx/choice.h>
#include <wx/checkbox.h> #include <wx/checkbox.h>
#include <wx/statline.h> #include <wx/statline.h>
#include <wx/button.h> #include <wx/button.h>
@ -30,6 +29,7 @@
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/// Class DIALOG_EXPORT_3DFILE_BASE /// Class DIALOG_EXPORT_3DFILE_BASE
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -38,16 +38,11 @@ class DIALOG_EXPORT_3DFILE_BASE : public DIALOG_SHIM
private: private:
protected: protected:
enum
{
ID_USE_ABS_PATH = 1000
};
wxStaticText* m_staticText1; wxStaticText* m_staticText1;
wxFilePickerCtrl* m_filePicker; wxFilePickerCtrl* m_filePicker;
wxStaticText* m_staticText3; wxStaticText* m_staticText3;
wxTextCtrl* m_SubdirNameCtrl; wxTextCtrl* m_SubdirNameCtrl;
wxPanel* m_panel1; wxRadioBox* m_rbCoordOrigin;
wxStaticText* m_staticText6; wxStaticText* m_staticText6;
wxStaticText* m_staticText61; wxStaticText* m_staticText61;
wxChoice* m_VRML_RefUnitChoice; wxChoice* m_VRML_RefUnitChoice;
@ -60,9 +55,13 @@ class DIALOG_EXPORT_3DFILE_BASE : public DIALOG_SHIM
wxCheckBox* m_cbUseRelativePaths; wxCheckBox* m_cbUseRelativePaths;
wxCheckBox* m_cbPlainPCB; wxCheckBox* m_cbPlainPCB;
wxStaticLine* m_staticline1; wxStaticLine* m_staticline1;
wxStdDialogButtonSizer* m_sdbSizer1; wxStdDialogButtonSizer* m_sdbSizer;
wxButton* m_sdbSizer1OK; wxButton* m_sdbSizerOK;
wxButton* m_sdbSizer1Cancel; wxButton* m_sdbSizerCancel;
// Virtual event handlers, overide them in your derived class
virtual void OnUpdateUseRelativePath( wxUpdateUIEvent& event ) { event.Skip(); }
public: public:

View File

@ -54,25 +54,21 @@
#include <exporter_vrml.h> #include <exporter_vrml.h>
static bool USE_INLINES; // true to use legacy inline{} behavior
static bool USE_DEFS; // true to reuse component definitions
static bool USE_RELPATH; // true to use relative paths in VRML inline{}
static double WORLD_SCALE = 1.0; // scaling from 0.1 in to desired VRML unit
static double BOARD_SCALE; // scaling from mm to desired VRML world scale
static const int PRECISION = 6; // legacy precision factor (now set to 6)
static wxString SUBDIR_3D; // legacy 3D subdirectory
static wxString PROJ_DIR; // project directory static wxString PROJ_DIR; // project directory
static S3D_CACHE* cache; static S3D_CACHE* cache;
VRML_COLOR colors[VRML_COLOR_LAST]; VRML_COLOR vrml_colors_list[VRML_COLOR_LAST];
static SGNODE* sgmaterial[VRML_COLOR_LAST] = { NULL }; static SGNODE* sgmaterial[VRML_COLOR_LAST] = { NULL };
MODEL_VRML::MODEL_VRML() : MODEL_VRML::MODEL_VRML() :
m_OutputPCB( (SGNODE*) NULL ) m_OutputPCB( (SGNODE*) NULL )
{ {
m_ReuseDef = true;
m_precision = 6;
m_WorldScale = 1.0;
for( unsigned i = 0; i < arrayDim( m_layer_z ); ++i ) for( unsigned i = 0; i < arrayDim( m_layer_z ); ++i )
m_layer_z[i] = 0; m_layer_z[i] = 0;
@ -82,16 +78,16 @@ MODEL_VRML::MODEL_VRML() :
m_brd_thickness = 1.6; m_brd_thickness = 1.6;
// pcb green // pcb green
colors[VRML_COLOR_PCB] = VRML_COLOR( vrml_colors_list[VRML_COLOR_PCB] = VRML_COLOR(
0.07f, 0.3f, 0.12f, 0.01f, 0.03f, 0.01f, 0.0f, 0.0f, 0.0f, 0.8f, 0.0f, 0.02f ); 0.07f, 0.3f, 0.12f, 0.01f, 0.03f, 0.01f, 0.0f, 0.0f, 0.0f, 0.8f, 0.0f, 0.02f );
// copper color // copper color
colors[VRML_COLOR_COPPER] = VRML_COLOR( vrml_colors_list[VRML_COLOR_COPPER] = VRML_COLOR(
0.72f, 0.45f, 0.2f, 0.01f, 0.05f, 0.01f, 0.0f, 0.0f, 0.0f, 0.8f, 0.0f, 0.02f ); 0.72f, 0.45f, 0.2f, 0.01f, 0.05f, 0.01f, 0.0f, 0.0f, 0.0f, 0.8f, 0.0f, 0.02f );
// silkscreen white // silkscreen white
colors[VRML_COLOR_SILK] = VRML_COLOR( vrml_colors_list[VRML_COLOR_SILK] = VRML_COLOR(
0.9f, 0.9f, 0.9f, 0.1f, 0.1f, 0.1f, 0.0f, 0.0f, 0.0f, 0.9f, 0.0f, 0.02f ); 0.9f, 0.9f, 0.9f, 0.1f, 0.1f, 0.1f, 0.0f, 0.0f, 0.0f, 0.9f, 0.0f, 0.02f );
// solder paste silver // solder paste silver
colors[VRML_COLOR_TIN] = VRML_COLOR( 0.749f, 0.756f, 0.761f, 0.749f, 0.756f, 0.761f, 0.0f, vrml_colors_list[VRML_COLOR_TIN] = VRML_COLOR( 0.749f, 0.756f, 0.761f, 0.749f, 0.756f, 0.761f, 0.0f,
0.0f, 0.0f, 0.8f, 0.0f, 0.8f ); 0.0f, 0.0f, 0.8f, 0.0f, 0.8f );
m_plainPCB = false; m_plainPCB = false;
@ -136,7 +132,7 @@ bool MODEL_VRML::SetScale( double aWorldScale )
throw( std::runtime_error( "WorldScale out of range (valid range is 0.001 to 10.0)" ) ); throw( std::runtime_error( "WorldScale out of range (valid range is 0.001 to 10.0)" ) );
m_OutputPCB.SetScale( aWorldScale * 2.54 ); m_OutputPCB.SetScale( aWorldScale * 2.54 );
WORLD_SCALE = aWorldScale * 2.54; m_WorldScale = aWorldScale * 2.54;
return true; return true;
} }
@ -175,6 +171,7 @@ bool MODEL_VRML::GetLayer3D( LAYER_NUM layer, VRML_LAYER** vlayer )
void MODEL_VRML::ExportVrmlSolderMask( BOARD* aPcb ) void MODEL_VRML::ExportVrmlSolderMask( BOARD* aPcb )
{ {
//TODO
} }
@ -182,13 +179,7 @@ void MODEL_VRML::ExportVrmlSolderMask( BOARD* aPcb )
static MODEL_VRML* model_vrml; static MODEL_VRML* model_vrml;
static void create_vrml_shell( IFSG_TRANSFORM& PcbOutput, VRML_COLOR_INDEX colorID, void MODEL_VRML::write_triangle_bag( std::ostream& aOut_file, const VRML_COLOR& aColor,
VRML_LAYER* layer, double top_z, double bottom_z );
static void create_vrml_plane( IFSG_TRANSFORM& PcbOutput, VRML_COLOR_INDEX colorID,
VRML_LAYER* layer, double aHeight, bool aTopPlane );
static void write_triangle_bag( std::ostream& aOut_file, const VRML_COLOR& aColor,
VRML_LAYER* aLayer, bool aPlane, bool aTop, VRML_LAYER* aLayer, bool aPlane, bool aTop,
double aTop_z, double aBottom_z ) double aTop_z, double aBottom_z )
{ {
@ -265,9 +256,9 @@ static void write_triangle_bag( std::ostream& aOut_file, const VRML_COLOR& aColo
case 2: case 2:
if( aPlane ) if( aPlane )
aLayer->WriteVertices( aTop_z, aOut_file, PRECISION ); aLayer->WriteVertices( aTop_z, aOut_file, m_precision );
else else
aLayer->Write3DVertices( aTop_z, aBottom_z, aOut_file, PRECISION ); aLayer->Write3DVertices( aTop_z, aBottom_z, aOut_file, m_precision );
aOut_file << "\n"; aOut_file << "\n";
break; break;
@ -292,144 +283,142 @@ static void write_triangle_bag( std::ostream& aOut_file, const VRML_COLOR& aColo
} }
static void write_layers( MODEL_VRML& aModel, BOARD* aPcb, const char* aFileName, void MODEL_VRML::writeLayers( BOARD* aPcb, const char* aFileName,
OSTREAM* aOutputFile ) OSTREAM* aOutputFile )
{ {
// VRML_LAYER board; // VRML_LAYER board;
aModel.m_board.Tesselate( &aModel.m_holes ); m_board.Tesselate( &m_holes );
double brdz = aModel.m_brd_thickness / 2.0 double brdz = m_brd_thickness / 2.0
- ( Millimeter2iu( ART_OFFSET / 2.0 ) ) * BOARD_SCALE; - ( Millimeter2iu( ART_OFFSET / 2.0 ) ) * m_BoardToVrmlScale;
if( USE_INLINES ) if( m_UseInlineModelsInBrdfile )
{ {
write_triangle_bag( *aOutputFile, aModel.GetColor( VRML_COLOR_PCB ), write_triangle_bag( *aOutputFile, GetColor( VRML_COLOR_PCB ),
&aModel.m_board, false, false, brdz, -brdz ); &m_board, false, false, brdz, -brdz );
} }
else else
{ {
create_vrml_shell( aModel.m_OutputPCB, VRML_COLOR_PCB, &aModel.m_board, brdz, -brdz ); create_vrml_shell( m_OutputPCB, VRML_COLOR_PCB, &m_board, brdz, -brdz );
} }
if( aModel.m_plainPCB ) if( m_plainPCB )
{ {
if( !USE_INLINES ) if( !m_UseInlineModelsInBrdfile )
S3D::WriteVRML( aFileName, true, aModel.m_OutputPCB.GetRawPtr(), USE_DEFS, true ); S3D::WriteVRML( aFileName, true, m_OutputPCB.GetRawPtr(), m_ReuseDef, true );
return; return;
} }
// VRML_LAYER m_top_copper; // VRML_LAYER m_top_copper;
aModel.m_top_copper.Tesselate( &aModel.m_holes ); m_top_copper.Tesselate( &m_holes );
if( USE_INLINES ) if( m_UseInlineModelsInBrdfile )
{ {
write_triangle_bag( *aOutputFile, aModel.GetColor( VRML_COLOR_COPPER ), write_triangle_bag( *aOutputFile, GetColor( VRML_COLOR_COPPER ),
&aModel.m_top_copper, true, true, &m_top_copper, true, true, GetLayerZ( F_Cu ), 0 );
aModel.GetLayerZ( F_Cu ), 0 );
} }
else else
{ {
create_vrml_plane( aModel.m_OutputPCB, VRML_COLOR_COPPER, &aModel.m_top_copper, create_vrml_plane( m_OutputPCB, VRML_COLOR_COPPER, &m_top_copper,
aModel.GetLayerZ( F_Cu ), true ); GetLayerZ( F_Cu ), true );
} }
// VRML_LAYER m_top_tin; // VRML_LAYER m_top_tin;
aModel.m_top_tin.Tesselate( &aModel.m_holes ); m_top_tin.Tesselate( &m_holes );
if( USE_INLINES ) if( m_UseInlineModelsInBrdfile )
{ {
write_triangle_bag( *aOutputFile, aModel.GetColor( VRML_COLOR_TIN ), write_triangle_bag( *aOutputFile, GetColor( VRML_COLOR_TIN ),
&aModel.m_top_tin, true, true, &m_top_tin, true, true,
aModel.GetLayerZ( F_Cu ) + Millimeter2iu( ART_OFFSET / 2.0 ) * BOARD_SCALE, GetLayerZ( F_Cu ) + Millimeter2iu( ART_OFFSET / 2.0 ) * m_BoardToVrmlScale,
0 ); 0 );
} }
else else
{ {
create_vrml_plane( aModel.m_OutputPCB, VRML_COLOR_TIN, &aModel.m_top_tin, create_vrml_plane( m_OutputPCB, VRML_COLOR_TIN, &m_top_tin,
aModel.GetLayerZ( F_Cu ) + Millimeter2iu( ART_OFFSET / 2.0 ) * BOARD_SCALE, GetLayerZ( F_Cu ) + Millimeter2iu( ART_OFFSET / 2.0 ) * m_BoardToVrmlScale,
true ); true );
} }
// VRML_LAYER m_bot_copper; // VRML_LAYER m_bot_copper;
aModel.m_bot_copper.Tesselate( &aModel.m_holes ); m_bot_copper.Tesselate( &m_holes );
if( USE_INLINES ) if( m_UseInlineModelsInBrdfile )
{ {
write_triangle_bag( *aOutputFile, aModel.GetColor( VRML_COLOR_COPPER ), write_triangle_bag( *aOutputFile, GetColor( VRML_COLOR_COPPER ),
&aModel.m_bot_copper, true, false, &m_bot_copper, true, false, GetLayerZ( B_Cu ), 0 );
aModel.GetLayerZ( B_Cu ), 0 );
} }
else else
{ {
create_vrml_plane( aModel.m_OutputPCB, VRML_COLOR_COPPER, &aModel.m_bot_copper, create_vrml_plane( m_OutputPCB, VRML_COLOR_COPPER, &m_bot_copper,
aModel.GetLayerZ( B_Cu ), false ); GetLayerZ( B_Cu ), false );
} }
// VRML_LAYER m_bot_tin; // VRML_LAYER m_bot_tin;
aModel.m_bot_tin.Tesselate( &aModel.m_holes ); m_bot_tin.Tesselate( &m_holes );
if( USE_INLINES ) if( m_UseInlineModelsInBrdfile )
{ {
write_triangle_bag( *aOutputFile, aModel.GetColor( VRML_COLOR_TIN ), write_triangle_bag( *aOutputFile, GetColor( VRML_COLOR_TIN ),
&aModel.m_bot_tin, true, false, &m_bot_tin, true, false,
aModel.GetLayerZ( B_Cu ) GetLayerZ( B_Cu )
- Millimeter2iu( ART_OFFSET / 2.0 ) * BOARD_SCALE, - Millimeter2iu( ART_OFFSET / 2.0 ) * m_BoardToVrmlScale,
0 ); 0 );
} }
else else
{ {
create_vrml_plane( aModel.m_OutputPCB, VRML_COLOR_TIN, &aModel.m_bot_tin, create_vrml_plane( m_OutputPCB, VRML_COLOR_TIN, &m_bot_tin,
aModel.GetLayerZ( B_Cu ) - Millimeter2iu( ART_OFFSET / 2.0 ) * BOARD_SCALE, GetLayerZ( B_Cu ) - Millimeter2iu( ART_OFFSET / 2.0 ) * m_BoardToVrmlScale,
false ); false );
} }
// VRML_LAYER PTH; // VRML_LAYER PTH;
aModel.m_plated_holes.Tesselate( NULL, true ); m_plated_holes.Tesselate( NULL, true );
if( USE_INLINES ) if( m_UseInlineModelsInBrdfile )
{ {
write_triangle_bag( *aOutputFile, aModel.GetColor( VRML_COLOR_TIN ), write_triangle_bag( *aOutputFile, GetColor( VRML_COLOR_TIN ),
&aModel.m_plated_holes, false, false, &m_plated_holes, false, false,
aModel.GetLayerZ( F_Cu ) + Millimeter2iu( ART_OFFSET / 2.0 ) * BOARD_SCALE, GetLayerZ( F_Cu ) + Millimeter2iu( ART_OFFSET / 2.0 ) * m_BoardToVrmlScale,
aModel.GetLayerZ( B_Cu ) - Millimeter2iu( ART_OFFSET / 2.0 ) * BOARD_SCALE ); GetLayerZ( B_Cu ) - Millimeter2iu( ART_OFFSET / 2.0 ) * m_BoardToVrmlScale );
} }
else else
{ {
create_vrml_shell( aModel.m_OutputPCB, VRML_COLOR_TIN, &aModel.m_plated_holes, create_vrml_shell( m_OutputPCB, VRML_COLOR_TIN, &m_plated_holes,
aModel.GetLayerZ( F_Cu ) + Millimeter2iu( ART_OFFSET / 2.0 ) * BOARD_SCALE, GetLayerZ( F_Cu ) + Millimeter2iu( ART_OFFSET / 2.0 ) * m_BoardToVrmlScale,
aModel.GetLayerZ( B_Cu ) - Millimeter2iu( ART_OFFSET / 2.0 ) * BOARD_SCALE ); GetLayerZ( B_Cu ) - Millimeter2iu( ART_OFFSET / 2.0 ) * m_BoardToVrmlScale );
} }
// VRML_LAYER m_top_silk; // VRML_LAYER m_top_silk;
aModel.m_top_silk.Tesselate( &aModel.m_holes ); m_top_silk.Tesselate( &m_holes );
if( USE_INLINES ) if( m_UseInlineModelsInBrdfile )
{ {
write_triangle_bag( *aOutputFile, aModel.GetColor( VRML_COLOR_SILK ), &aModel.m_top_silk, write_triangle_bag( *aOutputFile, GetColor( VRML_COLOR_SILK ), &m_top_silk,
true, true, aModel.GetLayerZ( F_SilkS ), 0 ); true, true, GetLayerZ( F_SilkS ), 0 );
} }
else else
{ {
create_vrml_plane( aModel.m_OutputPCB, VRML_COLOR_SILK, &aModel.m_top_silk, create_vrml_plane( m_OutputPCB, VRML_COLOR_SILK, &m_top_silk,
aModel.GetLayerZ( F_SilkS ), true ); GetLayerZ( F_SilkS ), true );
} }
// VRML_LAYER m_bot_silk; // VRML_LAYER m_bot_silk;
aModel.m_bot_silk.Tesselate( &aModel.m_holes ); m_bot_silk.Tesselate( &m_holes );
if( USE_INLINES ) if( m_UseInlineModelsInBrdfile )
{ {
write_triangle_bag( *aOutputFile, aModel.GetColor( VRML_COLOR_SILK ), &aModel.m_bot_silk, write_triangle_bag( *aOutputFile, GetColor( VRML_COLOR_SILK ), &m_bot_silk,
true, false, aModel.GetLayerZ( B_SilkS ), 0 ); true, false, GetLayerZ( B_SilkS ), 0 );
} }
else else
{ {
create_vrml_plane( aModel.m_OutputPCB, VRML_COLOR_SILK, &aModel.m_bot_silk, create_vrml_plane( m_OutputPCB, VRML_COLOR_SILK, &m_bot_silk,
aModel.GetLayerZ( B_SilkS ), false ); GetLayerZ( B_SilkS ), false );
} }
if( !USE_INLINES ) if( !m_UseInlineModelsInBrdfile )
S3D::WriteVRML( aFileName, true, aModel.m_OutputPCB.GetRawPtr(), true, true ); S3D::WriteVRML( aFileName, true, m_OutputPCB.GetRawPtr(), true, true );
} }
@ -438,7 +427,7 @@ void MODEL_VRML::ComputeLayer3D_Zpos( BOARD* pcb )
int copper_layers = pcb->GetCopperLayerCount(); int copper_layers = pcb->GetCopperLayerCount();
// We call it 'layer' thickness, but it's the whole board thickness! // We call it 'layer' thickness, but it's the whole board thickness!
m_brd_thickness = pcb->GetDesignSettings().GetBoardThickness() * BOARD_SCALE; m_brd_thickness = pcb->GetDesignSettings().GetBoardThickness() * m_BoardToVrmlScale;
double half_thickness = m_brd_thickness / 2; double half_thickness = m_brd_thickness / 2;
// Compute each layer's Z value, more or less like the 3d view // Compute each layer's Z value, more or less like the 3d view
@ -453,7 +442,7 @@ void MODEL_VRML::ComputeLayer3D_Zpos( BOARD* pcb )
} }
// To avoid rounding interference, we apply an epsilon to each successive layer // To avoid rounding interference, we apply an epsilon to each successive layer
double epsilon_z = Millimeter2iu( ART_OFFSET ) * BOARD_SCALE; double epsilon_z = Millimeter2iu( ART_OFFSET ) * m_BoardToVrmlScale;
SetLayerZ( B_Paste, -half_thickness - epsilon_z * 4 ); SetLayerZ( B_Paste, -half_thickness - epsilon_z * 4 );
SetLayerZ( B_Adhes, -half_thickness - epsilon_z * 3 ); SetLayerZ( B_Adhes, -half_thickness - epsilon_z * 3 );
SetLayerZ( B_SilkS, -half_thickness - epsilon_z * 2 ); SetLayerZ( B_SilkS, -half_thickness - epsilon_z * 2 );
@ -574,8 +563,8 @@ void MODEL_VRML::ExportVrmlPolygon( LAYER_NUM layer, PCB_SHAPE *aOutline,
for( int j = 0; j < outline.PointCount(); j++ ) for( int j = 0; j < outline.PointCount(); j++ )
{ {
if( !vlayer->AddVertex( seg, outline.CPoint( j ).x * BOARD_SCALE, if( !vlayer->AddVertex( seg, outline.CPoint( j ).x * m_BoardToVrmlScale,
-outline.CPoint( j ).y * BOARD_SCALE ) ) -outline.CPoint( j ).y * m_BoardToVrmlScale ) )
throw( std::runtime_error( vlayer->GetError() ) ); throw( std::runtime_error( vlayer->GetError() ) );
} }
@ -587,11 +576,11 @@ void MODEL_VRML::ExportVrmlPolygon( LAYER_NUM layer, PCB_SHAPE *aOutline,
void MODEL_VRML::ExportVrmlDrawsegment( PCB_SHAPE* drawseg ) void MODEL_VRML::ExportVrmlDrawsegment( PCB_SHAPE* drawseg )
{ {
LAYER_NUM layer = drawseg->GetLayer(); LAYER_NUM layer = drawseg->GetLayer();
double w = drawseg->GetWidth() * BOARD_SCALE; double w = drawseg->GetWidth() * m_BoardToVrmlScale;
double x = drawseg->GetStart().x * BOARD_SCALE; double x = drawseg->GetStart().x * m_BoardToVrmlScale;
double y = drawseg->GetStart().y * BOARD_SCALE; double y = drawseg->GetStart().y * m_BoardToVrmlScale;
double xf = drawseg->GetEnd().x * BOARD_SCALE; double xf = drawseg->GetEnd().x * m_BoardToVrmlScale;
double yf = drawseg->GetEnd().y * BOARD_SCALE; double yf = drawseg->GetEnd().y * m_BoardToVrmlScale;
double r = sqrt( pow( x - xf, 2 ) + pow( y - yf, 2 ) ); double r = sqrt( pow( x - xf, 2 ) + pow( y - yf, 2 ) );
// Items on the edge layer are handled elsewhere; just return // Items on the edge layer are handled elsewhere; just return
@ -602,10 +591,10 @@ void MODEL_VRML::ExportVrmlDrawsegment( PCB_SHAPE* drawseg )
{ {
case S_ARC: case S_ARC:
ExportVrmlArc( layer, ExportVrmlArc( layer,
(double) drawseg->GetCenter().x * BOARD_SCALE, (double) drawseg->GetCenter().x * m_BoardToVrmlScale,
(double) drawseg->GetCenter().y * BOARD_SCALE, (double) drawseg->GetCenter().y * m_BoardToVrmlScale,
(double) drawseg->GetArcStart().x * BOARD_SCALE, (double) drawseg->GetArcStart().x * m_BoardToVrmlScale,
(double) drawseg->GetArcStart().y * BOARD_SCALE, (double) drawseg->GetArcStart().y * m_BoardToVrmlScale,
w, drawseg->GetAngle() / 10 ); w, drawseg->GetAngle() / 10 );
break; break;
@ -630,10 +619,10 @@ void MODEL_VRML::ExportVrmlDrawsegment( PCB_SHAPE* drawseg )
std::vector<VECTOR2D> pointCtrl; std::vector<VECTOR2D> pointCtrl;
pointCtrl.emplace_back( x, y ); pointCtrl.emplace_back( x, y );
pointCtrl.emplace_back( drawseg->GetBezControl1().x * BOARD_SCALE, pointCtrl.emplace_back( drawseg->GetBezControl1().x * m_BoardToVrmlScale,
drawseg->GetBezControl1().y * BOARD_SCALE ); drawseg->GetBezControl1().y * m_BoardToVrmlScale );
pointCtrl.emplace_back( drawseg->GetBezControl2().x * BOARD_SCALE, pointCtrl.emplace_back( drawseg->GetBezControl2().x * m_BoardToVrmlScale,
drawseg->GetBezControl2().y * BOARD_SCALE ); drawseg->GetBezControl2().y * m_BoardToVrmlScale );
pointCtrl.emplace_back( xf, yf ); pointCtrl.emplace_back( xf, yf );
BEZIER_POLY converter( pointCtrl ); BEZIER_POLY converter( pointCtrl );
@ -661,17 +650,20 @@ void MODEL_VRML::ExportVrmlDrawsegment( PCB_SHAPE* drawseg )
} }
/* C++ doesn't have closures and neither continuation forms... this is /* GRText needs a callback function to return the shape of the text to plot...
* for coupling the vrml_text_callback with the common parameters */ * this is for coupling the vrml_text_callback with the vrml exporter parameters
*/
static void vrml_text_callback( int x0, int y0, int xf, int yf, void* aData ) static void vrml_text_callback( int x0, int y0, int xf, int yf, void* aData )
{ {
LAYER_NUM m_text_layer = model_vrml->m_text_layer; LAYER_NUM m_text_layer = model_vrml->m_text_layer;
int m_text_width = model_vrml->m_text_width; int m_text_width = model_vrml->m_text_width;
model_vrml->ExportVrmlLine( m_text_layer, model_vrml->ExportVrmlLine( m_text_layer,
x0 * BOARD_SCALE, y0 * BOARD_SCALE, x0 * model_vrml->m_BoardToVrmlScale,
xf * BOARD_SCALE, yf * BOARD_SCALE, y0 * model_vrml->m_BoardToVrmlScale,
m_text_width * BOARD_SCALE ); xf * model_vrml->m_BoardToVrmlScale,
yf * model_vrml->m_BoardToVrmlScale,
m_text_width * model_vrml->m_BoardToVrmlScale );
} }
@ -758,8 +750,8 @@ void MODEL_VRML::ExportVrmlBoard( BOARD* aPcb )
for( int j = 0; j < outline.PointCount(); j++ ) for( int j = 0; j < outline.PointCount(); j++ )
{ {
m_board.AddVertex( seg, (double)outline.CPoint(j).x * BOARD_SCALE, m_board.AddVertex( seg, (double)outline.CPoint(j).x * m_BoardToVrmlScale,
-((double)outline.CPoint(j).y * BOARD_SCALE ) ); -((double)outline.CPoint(j).y * m_BoardToVrmlScale ) );
} }
@ -780,8 +772,8 @@ void MODEL_VRML::ExportVrmlBoard( BOARD* aPcb )
for( int j = 0; j < hole.PointCount(); j++ ) for( int j = 0; j < hole.PointCount(); j++ )
{ {
m_holes.AddVertex( seg, (double) hole.CPoint(j).x * BOARD_SCALE, m_holes.AddVertex( seg, (double) hole.CPoint(j).x * m_BoardToVrmlScale,
-( (double) hole.CPoint(j).y * BOARD_SCALE ) ); -( (double) hole.CPoint(j).y * m_BoardToVrmlScale ) );
} }
m_holes.EnsureWinding( seg, true ); m_holes.EnsureWinding( seg, true );
@ -840,10 +832,10 @@ void MODEL_VRML::ExportVrmlVia( BOARD* aPcb, const VIA* aVia )
double x, y, r, hole; double x, y, r, hole;
PCB_LAYER_ID top_layer, bottom_layer; PCB_LAYER_ID top_layer, bottom_layer;
hole = aVia->GetDrillValue() * BOARD_SCALE / 2.0; hole = aVia->GetDrillValue() * m_BoardToVrmlScale / 2.0;
r = aVia->GetWidth() * BOARD_SCALE / 2.0; r = aVia->GetWidth() * m_BoardToVrmlScale / 2.0;
x = aVia->GetStart().x * BOARD_SCALE; x = aVia->GetStart().x * m_BoardToVrmlScale;
y = aVia->GetStart().y * BOARD_SCALE; y = aVia->GetStart().y * m_BoardToVrmlScale;
aVia->LayerPair( &top_layer, &bottom_layer ); aVia->LayerPair( &top_layer, &bottom_layer );
// do not render a buried via // do not render a buried via
@ -877,36 +869,36 @@ void MODEL_VRML::ExportVrmlTracks( BOARD* pcb )
if( arc_angle_degree < -1.0 || arc_angle_degree > 1.0 ) if( arc_angle_degree < -1.0 || arc_angle_degree > 1.0 )
{ {
ExportVrmlArc( track->GetLayer(), ExportVrmlArc( track->GetLayer(),
center.x * BOARD_SCALE, center.y * BOARD_SCALE, center.x * m_BoardToVrmlScale, center.y * m_BoardToVrmlScale,
arc->GetStart().x * BOARD_SCALE, arc->GetStart().x * m_BoardToVrmlScale,
arc->GetStart().y * BOARD_SCALE, arc->GetStart().y * m_BoardToVrmlScale,
arc->GetWidth() * BOARD_SCALE, arc_angle_degree ); arc->GetWidth() * m_BoardToVrmlScale, arc_angle_degree );
} }
else else
{ {
ExportVrmlLine( arc->GetLayer(), ExportVrmlLine( arc->GetLayer(),
arc->GetStart().x * BOARD_SCALE, arc->GetStart().x * m_BoardToVrmlScale,
arc->GetStart().y * BOARD_SCALE, arc->GetStart().y * m_BoardToVrmlScale,
arc->GetEnd().x * BOARD_SCALE, arc->GetEnd().x * m_BoardToVrmlScale,
arc->GetEnd().y * BOARD_SCALE, arc->GetEnd().y * m_BoardToVrmlScale,
arc->GetWidth() * BOARD_SCALE ); arc->GetWidth() * m_BoardToVrmlScale );
} }
} }
else else
{ {
ExportVrmlLine( track->GetLayer(), ExportVrmlLine( track->GetLayer(),
track->GetStart().x * BOARD_SCALE, track->GetStart().x * m_BoardToVrmlScale,
track->GetStart().y * BOARD_SCALE, track->GetStart().y * m_BoardToVrmlScale,
track->GetEnd().x * BOARD_SCALE, track->GetEnd().x * m_BoardToVrmlScale,
track->GetEnd().y * BOARD_SCALE, track->GetEnd().y * m_BoardToVrmlScale,
track->GetWidth() * BOARD_SCALE ); track->GetWidth() * m_BoardToVrmlScale );
} }
} }
} }
} }
void MODEL_VRML::ExportVrmlZones( BOARD* aPcb, COMMIT* aCommit ) void MODEL_VRML::ExportVrmlZones( BOARD* aPcb )
{ {
for( ZONE* zone : aPcb->Zones() ) for( ZONE* zone : aPcb->Zones() )
{ {
@ -918,16 +910,7 @@ void MODEL_VRML::ExportVrmlZones( BOARD* aPcb, COMMIT* aCommit )
continue; continue;
if( !zone->IsFilled() ) if( !zone->IsFilled() )
{ continue;
ZONE_FILLER filler( aPcb, aCommit );
zone->SetFillMode( ZONE_FILL_MODE::POLYGONS ); // use filled polygons
// If the zone fill failed, don't try adding it to the export
std::vector<ZONE*> toFill = { zone };
if( !filler.Fill( toFill ) )
continue;
}
const SHAPE_POLY_SET& poly = zone->GetFilledPolysList( layer ); const SHAPE_POLY_SET& poly = zone->GetFilledPolysList( layer );
@ -939,8 +922,8 @@ void MODEL_VRML::ExportVrmlZones( BOARD* aPcb, COMMIT* aCommit )
for( int j = 0; j < outline.PointCount(); j++ ) for( int j = 0; j < outline.PointCount(); j++ )
{ {
if( !vl->AddVertex( seg, (double) outline.CPoint( j ).x * BOARD_SCALE, if( !vl->AddVertex( seg, (double) outline.CPoint( j ).x * m_BoardToVrmlScale,
-( (double) outline.CPoint( j ).y * BOARD_SCALE ) ) ) -( (double) outline.CPoint( j ).y * m_BoardToVrmlScale ) ) )
{ {
throw( std::runtime_error( vl->GetError() ) ); throw( std::runtime_error( vl->GetError() ) );
} }
@ -953,7 +936,7 @@ void MODEL_VRML::ExportVrmlZones( BOARD* aPcb, COMMIT* aCommit )
} }
static void export_vrml_fp_text( FP_TEXT* item ) void MODEL_VRML::ExportVrmlFpText( FP_TEXT* item )
{ {
if( item->IsVisible() ) if( item->IsVisible() )
{ {
@ -978,11 +961,11 @@ static void export_vrml_fp_text( FP_TEXT* item )
void MODEL_VRML::ExportVrmlFpShape( FP_SHAPE* aOutline, FOOTPRINT* aFootprint ) void MODEL_VRML::ExportVrmlFpShape( FP_SHAPE* aOutline, FOOTPRINT* aFootprint )
{ {
LAYER_NUM layer = aOutline->GetLayer(); LAYER_NUM layer = aOutline->GetLayer();
double x = aOutline->GetStart().x * BOARD_SCALE; double x = aOutline->GetStart().x * m_BoardToVrmlScale;
double y = aOutline->GetStart().y * BOARD_SCALE; double y = aOutline->GetStart().y * m_BoardToVrmlScale;
double xf = aOutline->GetEnd().x * BOARD_SCALE; double xf = aOutline->GetEnd().x * m_BoardToVrmlScale;
double yf = aOutline->GetEnd().y * BOARD_SCALE; double yf = aOutline->GetEnd().y * m_BoardToVrmlScale;
double w = aOutline->GetWidth() * BOARD_SCALE; double w = aOutline->GetWidth() * m_BoardToVrmlScale;
switch( aOutline->GetShape() ) switch( aOutline->GetShape() )
{ {
@ -1009,10 +992,10 @@ void MODEL_VRML::ExportVrmlFpShape( FP_SHAPE* aOutline, FOOTPRINT* aFootprint )
std::vector<VECTOR2D> pointCtrl; std::vector<VECTOR2D> pointCtrl;
pointCtrl.emplace_back( x, y ); pointCtrl.emplace_back( x, y );
pointCtrl.emplace_back( aOutline->GetBezControl1().x * BOARD_SCALE, pointCtrl.emplace_back( aOutline->GetBezControl1().x * m_BoardToVrmlScale,
aOutline->GetBezControl1().y * BOARD_SCALE ); aOutline->GetBezControl1().y * m_BoardToVrmlScale );
pointCtrl.emplace_back( aOutline->GetBezControl2().x * BOARD_SCALE, pointCtrl.emplace_back( aOutline->GetBezControl2().x * m_BoardToVrmlScale,
aOutline->GetBezControl2().y * BOARD_SCALE ); aOutline->GetBezControl2().y * m_BoardToVrmlScale );
pointCtrl.emplace_back( xf, yf ); pointCtrl.emplace_back( xf, yf );
BEZIER_POLY converter( pointCtrl ); BEZIER_POLY converter( pointCtrl );
@ -1044,15 +1027,15 @@ void MODEL_VRML::ExportVrmlPadshape( VRML_LAYER* aTinLayer, PAD* aPad )
{ {
// The (maybe offset) pad position // The (maybe offset) pad position
wxPoint pad_pos = aPad->ShapePos(); wxPoint pad_pos = aPad->ShapePos();
double pad_x = pad_pos.x * BOARD_SCALE; double pad_x = pad_pos.x * m_BoardToVrmlScale;
double pad_y = pad_pos.y * BOARD_SCALE; double pad_y = pad_pos.y * m_BoardToVrmlScale;
wxSize pad_delta = aPad->GetDelta(); wxSize pad_delta = aPad->GetDelta();
double pad_dx = pad_delta.x * BOARD_SCALE / 2.0; double pad_dx = pad_delta.x * m_BoardToVrmlScale / 2.0;
double pad_dy = pad_delta.y * BOARD_SCALE / 2.0; double pad_dy = pad_delta.y * m_BoardToVrmlScale / 2.0;
double pad_w = aPad->GetSize().x * BOARD_SCALE / 2.0; double pad_w = aPad->GetSize().x * m_BoardToVrmlScale / 2.0;
double pad_h = aPad->GetSize().y * BOARD_SCALE / 2.0; double pad_h = aPad->GetSize().y * m_BoardToVrmlScale / 2.0;
switch( aPad->GetShape() ) switch( aPad->GetShape() )
{ {
@ -1085,7 +1068,7 @@ void MODEL_VRML::ExportVrmlPadshape( VRML_LAYER* aTinLayer, PAD* aPad )
cornerList.reserve( poly.PointCount() ); cornerList.reserve( poly.PointCount() );
for( int ii = 0; ii < poly.PointCount(); ++ii ) for( int ii = 0; ii < poly.PointCount(); ++ii )
cornerList.emplace_back( cornerList.emplace_back(
poly.CPoint( ii ).x * BOARD_SCALE, -poly.CPoint( ii ).y * BOARD_SCALE ); poly.CPoint( ii ).x * m_BoardToVrmlScale, -poly.CPoint( ii ).y * m_BoardToVrmlScale );
// Close polygon // Close polygon
cornerList.push_back( cornerList[0] ); cornerList.push_back( cornerList[0] );
@ -1108,7 +1091,7 @@ void MODEL_VRML::ExportVrmlPadshape( VRML_LAYER* aTinLayer, PAD* aPad )
for( int ii = 0; ii < poly.PointCount(); ++ii ) for( int ii = 0; ii < poly.PointCount(); ++ii )
cornerList.emplace_back( cornerList.emplace_back(
poly.CPoint( ii ).x * BOARD_SCALE, -poly.CPoint( ii ).y * BOARD_SCALE ); poly.CPoint( ii ).x * m_BoardToVrmlScale, -poly.CPoint( ii ).y * m_BoardToVrmlScale );
// Close polygon // Close polygon
cornerList.push_back( cornerList[0] ); cornerList.push_back( cornerList[0] );
@ -1175,11 +1158,11 @@ void MODEL_VRML::ExportVrmlPadshape( VRML_LAYER* aTinLayer, PAD* aPad )
void MODEL_VRML::ExportVrmlPad( BOARD* aPcb, PAD* aPad ) void MODEL_VRML::ExportVrmlPad( BOARD* aPcb, PAD* aPad )
{ {
double hole_drill_w = (double) aPad->GetDrillSize().x * BOARD_SCALE / 2.0; double hole_drill_w = (double) aPad->GetDrillSize().x * m_BoardToVrmlScale / 2.0;
double hole_drill_h = (double) aPad->GetDrillSize().y * BOARD_SCALE / 2.0; double hole_drill_h = (double) aPad->GetDrillSize().y * m_BoardToVrmlScale / 2.0;
double hole_drill = std::min( hole_drill_w, hole_drill_h ); double hole_drill = std::min( hole_drill_w, hole_drill_h );
double hole_x = aPad->GetPosition().x * BOARD_SCALE; double hole_x = aPad->GetPosition().x * m_BoardToVrmlScale;
double hole_y = aPad->GetPosition().y * BOARD_SCALE; double hole_y = aPad->GetPosition().y * m_BoardToVrmlScale;
// Export the hole on the edge layer // Export the hole on the edge layer
if( hole_drill > 0 ) if( hole_drill > 0 )
@ -1297,10 +1280,10 @@ void MODEL_VRML::ExportVrmlFootprint( BOARD* aPcb, FOOTPRINT* aFootprint,
{ {
// Reference and value // Reference and value
if( aFootprint->Reference().IsVisible() ) if( aFootprint->Reference().IsVisible() )
export_vrml_fp_text( &aFootprint->Reference() ); ExportVrmlFpText( &aFootprint->Reference() );
if( aFootprint->Value().IsVisible() ) if( aFootprint->Value().IsVisible() )
export_vrml_fp_text( &aFootprint->Value() ); ExportVrmlFpText( &aFootprint->Value() );
// Export footprint graphics // Export footprint graphics
@ -1309,7 +1292,7 @@ void MODEL_VRML::ExportVrmlFootprint( BOARD* aPcb, FOOTPRINT* aFootprint,
switch( item->Type() ) switch( item->Type() )
{ {
case PCB_FP_TEXT_T: case PCB_FP_TEXT_T:
export_vrml_fp_text( static_cast<FP_TEXT*>( item ) ); ExportVrmlFpText( static_cast<FP_TEXT*>( item ) );
break; break;
case PCB_FP_SHAPE_T: case PCB_FP_SHAPE_T:
@ -1332,7 +1315,7 @@ void MODEL_VRML::ExportVrmlFootprint( BOARD* aPcb, FOOTPRINT* aFootprint,
auto sM = aFootprint->Models().begin(); auto sM = aFootprint->Models().begin();
auto eM = aFootprint->Models().end(); auto eM = aFootprint->Models().end();
wxFileName subdir( SUBDIR_3D, "" ); wxFileName subdir( m_Subdir3DFpModels, "" );
while( sM != eM ) while( sM != eM )
{ {
@ -1390,15 +1373,15 @@ void MODEL_VRML::ExportVrmlFootprint( BOARD* aPcb, FOOTPRINT* aFootprint,
RotatePoint( &offsetx, &offsety, aFootprint->GetOrientation() ); RotatePoint( &offsetx, &offsety, aFootprint->GetOrientation() );
SGPOINT trans; SGPOINT trans;
trans.x = ( offsetx + aFootprint->GetPosition().x ) * BOARD_SCALE + m_tx; trans.x = ( offsetx + aFootprint->GetPosition().x ) * m_BoardToVrmlScale + m_tx;
trans.y = -( offsety + aFootprint->GetPosition().y) * BOARD_SCALE - m_ty; trans.y = -( offsety + aFootprint->GetPosition().y) * m_BoardToVrmlScale - m_ty;
trans.z = (offsetz * BOARD_SCALE ) + GetLayerZ( aFootprint->GetLayer() ); trans.z = (offsetz * m_BoardToVrmlScale ) + GetLayerZ( aFootprint->GetLayer() );
if( USE_INLINES ) if( m_UseInlineModelsInBrdfile )
{ {
wxFileName srcFile = cache->GetResolver()->ResolvePath( sM->m_Filename ); wxFileName srcFile = cache->GetResolver()->ResolvePath( sM->m_Filename );
wxFileName dstFile; wxFileName dstFile;
dstFile.SetPath( SUBDIR_3D ); dstFile.SetPath( m_Subdir3DFpModels );
dstFile.SetName( srcFile.GetName() ); dstFile.SetName( srcFile.GetName() );
dstFile.SetExt( "wrl" ); dstFile.SetExt( "wrl" );
@ -1425,7 +1408,7 @@ void MODEL_VRML::ExportVrmlFootprint( BOARD* aPcb, FOOTPRINT* aFootprint,
} }
else else
{ {
if( !S3D::WriteVRML( dstFile.GetFullPath().ToUTF8(), true, mod3d, USE_DEFS, true ) ) if( !S3D::WriteVRML( dstFile.GetFullPath().ToUTF8(), true, mod3d, m_ReuseDef, true ) )
continue; continue;
} }
} }
@ -1439,7 +1422,7 @@ void MODEL_VRML::ExportVrmlFootprint( BOARD* aPcb, FOOTPRINT* aFootprint,
(*aOutputFile) << rot[0] << " " << rot[1] << " " << rot[2] << " " << rot[3] << "\n"; (*aOutputFile) << rot[0] << " " << rot[1] << " " << rot[2] << " " << rot[3] << "\n";
} }
(*aOutputFile) << " translation " << std::setprecision( PRECISION ); (*aOutputFile) << " translation " << std::setprecision( m_precision );
(*aOutputFile) << trans.x << " "; (*aOutputFile) << trans.x << " ";
(*aOutputFile) << trans.y << " "; (*aOutputFile) << trans.y << " ";
(*aOutputFile) << trans.z << "\n"; (*aOutputFile) << trans.z << "\n";
@ -1451,7 +1434,7 @@ void MODEL_VRML::ExportVrmlFootprint( BOARD* aPcb, FOOTPRINT* aFootprint,
(*aOutputFile) << " children [\n Inline {\n url \""; (*aOutputFile) << " children [\n Inline {\n url \"";
if( USE_RELPATH ) if( m_UseRelPathIn3DModelFilename )
{ {
wxFileName tmp = dstFile; wxFileName tmp = dstFile;
tmp.SetExt( "" ); tmp.SetExt( "" );
@ -1500,28 +1483,25 @@ bool PCB_EDIT_FRAME::ExportVRML_File( const wxString& aFullFileName, double aMMt
{ {
BOARD* pcb = GetBoard(); BOARD* pcb = GetBoard();
bool ok = true; bool ok = true;
BOARD_COMMIT commit( this ); // We may need to modify the board (for instance to
// fill zones), so make sure we can revert.
USE_INLINES = aExport3DFiles;
USE_DEFS = true;
USE_RELPATH = aUseRelativePaths;
cache = Prj().Get3DCacheManager(); cache = Prj().Get3DCacheManager();
PROJ_DIR = Prj().GetProjectPath(); PROJ_DIR = Prj().GetProjectPath();
SUBDIR_3D = a3D_Subdir;
MODEL_VRML model3d; MODEL_VRML model3d;
model_vrml = &model3d; model_vrml = &model3d;
model3d.SetScale( aMMtoWRMLunit ); model3d.SetScale( aMMtoWRMLunit );
model3d.m_UseInlineModelsInBrdfile = aExport3DFiles;
model3d.m_Subdir3DFpModels = a3D_Subdir;
model3d.m_UseRelPathIn3DModelFilename = aUseRelativePaths;
if( USE_INLINES ) if( model3d.m_UseInlineModelsInBrdfile )
{ {
BOARD_SCALE = MM_PER_IU / 2.54; model3d.m_BoardToVrmlScale = MM_PER_IU / 2.54;
model3d.SetOffset( -aXRef / 2.54, aYRef / 2.54 ); model3d.SetOffset( -aXRef / 2.54, aYRef / 2.54 );
} }
else else
{ {
BOARD_SCALE = MM_PER_IU; model3d.m_BoardToVrmlScale = MM_PER_IU;
model3d.SetOffset( -aXRef, aYRef ); model3d.SetOffset( -aXRef, aYRef );
} }
@ -1549,64 +1529,22 @@ bool PCB_EDIT_FRAME::ExportVRML_File( const wxString& aFullFileName, double aMMt
// Export zone fills // Export zone fills
if( !aUsePlainPCB ) if( !aUsePlainPCB )
model3d.ExportVrmlZones( pcb, &commit ); model3d.ExportVrmlZones( pcb );
if( USE_INLINES ) if( model3d.m_UseInlineModelsInBrdfile )
{ {
// check if the 3D Subdir exists - create if not // Copy fp 3D models in a folder, and link these files in
wxFileName subdir( SUBDIR_3D, "" ); // the board .vrml file
model3d.ExportFp3DModelsAsLinkedFile( pcb, aFullFileName );
if( ! subdir.DirExists() )
{
if( !wxDir::Make( subdir.GetFullPath() ) )
throw( std::runtime_error( "Could not create 3D model subdirectory" ) );
}
OPEN_OSTREAM( output_file, TO_UTF8( aFullFileName ) );
if( output_file.fail() )
{
std::ostringstream ostr;
ostr << "Could not open file '" << TO_UTF8( aFullFileName ) << "'";
throw( std::runtime_error( ostr.str().c_str() ) );
}
output_file.imbue( std::locale::classic() );
// Begin with the usual VRML boilerplate
wxString fn = aFullFileName;
fn.Replace( "\\" , "/" );
output_file << "#VRML V2.0 utf8\n";
output_file << "WorldInfo {\n";
output_file << " title \"" << TO_UTF8( fn ) << " - Generated by Pcbnew\"\n";
output_file << "}\n";
output_file << "Transform {\n";
output_file << " scale " << std::setprecision( PRECISION );
output_file << WORLD_SCALE << " ";
output_file << WORLD_SCALE << " ";
output_file << WORLD_SCALE << "\n";
output_file << " children [\n";
// Export footprints
for( FOOTPRINT* footprint : pcb->Footprints() )
model3d.ExportVrmlFootprint( pcb, footprint, &output_file );
// write out the board and all layers
write_layers( model3d, pcb, TO_UTF8( aFullFileName ), &output_file );
// Close the outer 'transform' node
output_file << "]\n}\n";
CLOSE_STREAM( output_file );
} }
else else
{ {
// Export footprints // merge footprints in the .vrml board file
for( FOOTPRINT* footprint : pcb->Footprints() ) for( FOOTPRINT* footprint : pcb->Footprints() )
model3d.ExportVrmlFootprint( pcb, footprint, NULL ); model3d.ExportVrmlFootprint( pcb, footprint, NULL );
// write out the board and all layers // write out the board and all layers
write_layers( model3d, pcb, TO_UTF8( aFullFileName ), NULL ); model3d.writeLayers( pcb, TO_UTF8( aFullFileName ), NULL );
} }
} }
catch( const std::exception& e ) catch( const std::exception& e )
@ -1618,10 +1556,57 @@ bool PCB_EDIT_FRAME::ExportVRML_File( const wxString& aFullFileName, double aMMt
ok = false; ok = false;
} }
commit.Revert();
return ok; return ok;
} }
void MODEL_VRML::ExportFp3DModelsAsLinkedFile( BOARD* aPcb, const wxString& aFullFileName )
{
// check if the 3D Subdir exists - create if not
wxFileName subdir( m_Subdir3DFpModels, "" );
if( ! subdir.DirExists() )
{
if( !wxDir::Make( subdir.GetFullPath() ) )
throw( std::runtime_error( "Could not create 3D model subdirectory" ) );
}
OPEN_OSTREAM( output_file, TO_UTF8( aFullFileName ) );
if( output_file.fail() )
{
std::ostringstream ostr;
ostr << "Could not open file '" << TO_UTF8( aFullFileName ) << "'";
throw( std::runtime_error( ostr.str().c_str() ) );
}
output_file.imbue( std::locale::classic() );
// Begin with the usual VRML boilerplate
wxString fn = aFullFileName;
fn.Replace( "\\" , "/" );
output_file << "#VRML V2.0 utf8\n";
output_file << "WorldInfo {\n";
output_file << " title \"" << TO_UTF8( fn ) << " - Generated by Pcbnew\"\n";
output_file << "}\n";
output_file << "Transform {\n";
output_file << " scale " << std::setprecision( m_precision );
output_file << m_WorldScale << " ";
output_file << m_WorldScale << " ";
output_file << m_WorldScale << "\n";
output_file << " children [\n";
// Export footprints
for( FOOTPRINT* footprint : aPcb->Footprints() )
ExportVrmlFootprint( aPcb, footprint, &output_file );
// write out the board and all layers
writeLayers( aPcb, TO_UTF8( aFullFileName ), &output_file );
// Close the outer 'transform' node
output_file << "]\n}\n";
CLOSE_STREAM( output_file );
}
static SGNODE* getSGColor( VRML_COLOR_INDEX colorIdx ) static SGNODE* getSGColor( VRML_COLOR_INDEX colorIdx )
{ {
@ -1634,7 +1619,7 @@ static SGNODE* getSGColor( VRML_COLOR_INDEX colorIdx )
return sgmaterial[colorIdx]; return sgmaterial[colorIdx];
IFSG_APPEARANCE vcolor( (SGNODE*) NULL ); IFSG_APPEARANCE vcolor( (SGNODE*) NULL );
VRML_COLOR* cp = &colors[colorIdx]; VRML_COLOR* cp = &vrml_colors_list[colorIdx];
vcolor.SetSpecular( cp->spec_red, cp->spec_grn, cp->spec_blu ); vcolor.SetSpecular( cp->spec_red, cp->spec_grn, cp->spec_blu );
vcolor.SetDiffuse( cp->diffuse_red, cp->diffuse_grn, cp->diffuse_blu ); vcolor.SetDiffuse( cp->diffuse_red, cp->diffuse_grn, cp->diffuse_blu );
@ -1650,8 +1635,8 @@ static SGNODE* getSGColor( VRML_COLOR_INDEX colorIdx )
} }
static void create_vrml_plane( IFSG_TRANSFORM& PcbOutput, VRML_COLOR_INDEX colorID, void MODEL_VRML::create_vrml_plane( IFSG_TRANSFORM& PcbOutput, VRML_COLOR_INDEX colorID,
VRML_LAYER* layer, double top_z, bool aTopPlane ) VRML_LAYER* layer, double top_z, bool aTopPlane )
{ {
std::vector< double > vertices; std::vector< double > vertices;
std::vector< int > idxPlane; std::vector< int > idxPlane;
@ -1708,8 +1693,8 @@ static void create_vrml_plane( IFSG_TRANSFORM& PcbOutput, VRML_COLOR_INDEX color
} }
static void create_vrml_shell( IFSG_TRANSFORM& PcbOutput, VRML_COLOR_INDEX colorID, void MODEL_VRML::create_vrml_shell( IFSG_TRANSFORM& PcbOutput, VRML_COLOR_INDEX colorID,
VRML_LAYER* layer, double top_z, double bottom_z ) VRML_LAYER* layer, double top_z, double bottom_z )
{ {
std::vector< double > vertices; std::vector< double > vertices;
std::vector< int > idxPlane; std::vector< int > idxPlane;

View File

@ -34,13 +34,29 @@ class VRML_WRITER
{ {
public: public:
/**
* Exports the board and its footprint shapes 3D (vrml files only) as a
* vrml file
* @param aFullFileName is the full filename of the board vrml file to create
* @param aMMtoWRMLunit is the convert factor from mm to the desired vrml file
* @param aExport3DFiles = true to copy 3D fp vrml models to a folder,
* and use " { inline fp_3d_model_filename }" keyword in vrml board file
* false to include them in the vrml board file
* @param aUseRelativePaths = true to use fp 3D relative paths,
* false to use absolute paths
* @param aUsePlainPCB = true to create a body board shape only,
* false to create a full board shape with tracks, vias ...
* @param a3D_Subdir is the folder to copy 3D fp models
* @param aXRef = X position of board (in mm)
* @param aYRef = Y position of board (in mm)
*/
bool ExportVRML_File( const wxString& aFullFileName, double aMMtoWRMLunit, bool ExportVRML_File( const wxString& aFullFileName, double aMMtoWRMLunit,
bool aExport3DFiles, bool aUseRelativePaths, bool aExport3DFiles, bool aUseRelativePaths,
bool aUsePlainPCB, const wxString& a3D_Subdir, bool aUsePlainPCB, const wxString& a3D_Subdir,
double aXRef, double aYRef ) double aXRef, double aYRef )
{ {
return ExportVRML(aFullFileName, aMMtoWRMLunit, return ExportVRML( aFullFileName, aMMtoWRMLunit,
aExport3DFiles, aUseRelativePaths, aExport3DFiles, aUseRelativePaths,
aUsePlainPCB, a3D_Subdir, aXRef, aYRef); aUsePlainPCB, a3D_Subdir, aXRef, aYRef);
} }
}; };

View File

@ -101,7 +101,7 @@ struct VRML_COLOR
}; };
extern VRML_COLOR colors[VRML_COLOR_LAST]; extern VRML_COLOR vrml_colors_list[VRML_COLOR_LAST];
// Handle the board ans its board items to convert them to a VRML representation: // Handle the board ans its board items to convert them to a VRML representation:
@ -113,6 +113,8 @@ private:
int m_iMaxSeg; // max. sides to a small circle int m_iMaxSeg; // max. sides to a small circle
double m_arcMinLen, m_arcMaxLen; // min and max lengths of an arc chord double m_arcMinLen, m_arcMaxLen; // min and max lengths of an arc chord
int m_precision; // precision factor when exportin fp shapes
// to separate files
public: public:
IFSG_TRANSFORM m_OutputPCB; IFSG_TRANSFORM m_OutputPCB;
@ -130,6 +132,28 @@ public:
bool m_plainPCB; bool m_plainPCB;
/* true to use VRML inline{} syntax for footprint 3D models, like:
* Inline { url "F:/tmp/pic_programmer/shapes3D/DIP-18_W7.62mm_Socket.wrl" }
* false to merge VRML 3D modeles in the .wrl board file
*/
bool m_UseInlineModelsInBrdfile;
// 3D subdirectory to copy footprint vrml 3D models when not merged in board file
wxString m_Subdir3DFpModels;
// true to use relative paths in VRML inline{} for footprint 3D models
// used only if m_UseInlineModelsInBrdfile = true
bool m_UseRelPathIn3DModelFilename;
// true to reuse component definitions
bool m_ReuseDef;
// scaling from 0.1 inch to desired VRML unit
double m_WorldScale = 1.0;
// scaling from mm to desired VRML world scale
double m_BoardToVrmlScale;
double m_minLineWidth; // minimum width of a VRML line segment double m_minLineWidth; // minimum width of a VRML line segment
double m_tx; // global translation along X double m_tx; // global translation along X
@ -145,7 +169,7 @@ public:
VRML_COLOR& GetColor( VRML_COLOR_INDEX aIndex ) VRML_COLOR& GetColor( VRML_COLOR_INDEX aIndex )
{ {
return colors[aIndex]; return vrml_colors_list[aIndex];
} }
void SetOffset( double aXoff, double aYoff ); void SetOffset( double aXoff, double aYoff );
@ -172,7 +196,7 @@ public:
// Build and exports the board outlines (board body) // Build and exports the board outlines (board body)
void ExportVrmlBoard( BOARD* aPcb ); void ExportVrmlBoard( BOARD* aPcb );
void ExportVrmlZones( BOARD* aPcb, COMMIT* aCommit ); void ExportVrmlZones( BOARD* aPcb );
void ExportVrmlTracks( BOARD* pcb ); void ExportVrmlTracks( BOARD* pcb );
@ -182,6 +206,10 @@ public:
void ExportVrmlPcbtext( PCB_TEXT* text ); void ExportVrmlPcbtext( PCB_TEXT* text );
void ExportVrmlFpText( FP_TEXT* item );
void ExportFp3DModelsAsLinkedFile( BOARD* aPcb, const wxString& aFullFileName );
void ExportRoundPadstack( BOARD* pcb, void ExportRoundPadstack( BOARD* pcb,
double x, double y, double r, double x, double y, double r,
LAYER_NUM bottom_layer, LAYER_NUM top_layer, LAYER_NUM bottom_layer, LAYER_NUM top_layer,
@ -215,6 +243,8 @@ public:
void ExportVrmlPolygon( LAYER_NUM layer, PCB_SHAPE *aOutline, void ExportVrmlPolygon( LAYER_NUM layer, PCB_SHAPE *aOutline,
double aOrientation, wxPoint aPos ); double aOrientation, wxPoint aPos );
void writeLayers( BOARD* aPcb, const char* aFileName, OSTREAM* aOutputFile );
// select the VRML layer object to draw on // select the VRML layer object to draw on
// return true if a layer has been selected. // return true if a layer has been selected.
bool GetLayer3D( LAYER_NUM layer, VRML_LAYER** vlayer ); bool GetLayer3D( LAYER_NUM layer, VRML_LAYER** vlayer );
@ -222,4 +252,15 @@ public:
// Build the Z position of 3D layers // Build the Z position of 3D layers
void ComputeLayer3D_Zpos(BOARD* pcb ); void ComputeLayer3D_Zpos(BOARD* pcb );
private:
void write_triangle_bag( std::ostream& aOut_file, const VRML_COLOR& aColor,
VRML_LAYER* aLayer, bool aPlane, bool aTop,
double aTop_z, double aBottom_z );
void create_vrml_shell( IFSG_TRANSFORM& PcbOutput, VRML_COLOR_INDEX colorID,
VRML_LAYER* layer, double top_z, double bottom_z );
void create_vrml_plane( IFSG_TRANSFORM& PcbOutput, VRML_COLOR_INDEX colorID,
VRML_LAYER* layer, double aHeight, bool aTopPlane );
}; };

View File

@ -312,6 +312,9 @@ PCBNEW_SETTINGS::PCBNEW_SETTINGS()
m_params.emplace_back( new PARAM<double>( "export_vrml.ref_y", m_params.emplace_back( new PARAM<double>( "export_vrml.ref_y",
&m_ExportVrml.ref_y, 0 ) ); &m_ExportVrml.ref_y, 0 ) );
m_params.emplace_back( new PARAM<int>( "export_vrml.origin_mode",
&m_ExportVrml.origin_mode, 0 ) );
m_params.emplace_back( new PARAM<int>( "zones.hatching_style", m_params.emplace_back( new PARAM<int>( "zones.hatching_style",
&m_Zones.hatching_style, 0 ) ); &m_Zones.hatching_style, 0 ) );
@ -647,6 +650,7 @@ bool PCBNEW_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
ret &= fromLegacy<int>( aCfg, "VrmlRefUnits", "export_vrml.ref_units" ); ret &= fromLegacy<int>( aCfg, "VrmlRefUnits", "export_vrml.ref_units" );
ret &= fromLegacy<double>( aCfg, "VrmlRefX", "export_vrml.ref_x" ); ret &= fromLegacy<double>( aCfg, "VrmlRefX", "export_vrml.ref_x" );
ret &= fromLegacy<double>( aCfg, "VrmlRefY", "export_vrml.ref_y" ); ret &= fromLegacy<double>( aCfg, "VrmlRefY", "export_vrml.ref_y" );
ret &= fromLegacy<int> ( aCfg, "VrmlOriginMode", "export_vrml.origin_mode" );
ret &= fromLegacy<int>( aCfg, "Zone_Ouline_Hatch_Opt", "zones.hatching_style" ); ret &= fromLegacy<int>( aCfg, "Zone_Ouline_Hatch_Opt", "zones.hatching_style" );
ret &= fromLegacyString( aCfg, "Zone_Filter_Opt", "zones.net_filter" ); ret &= fromLegacyString( aCfg, "Zone_Filter_Opt", "zones.net_filter" );

View File

@ -128,6 +128,7 @@ public:
int ref_units; int ref_units;
double ref_x; double ref_x;
double ref_y; double ref_y;
int origin_mode;
}; };
struct DIALOG_FOOTPRINT_WIZARD_LIST struct DIALOG_FOOTPRINT_WIZARD_LIST