From d193334a102bf105121205db7a2716ef30a15519 Mon Sep 17 00:00:00 2001 From: Marek Roszko <mark.roszko@gmail.com> Date: Thu, 24 Aug 2023 20:24:51 -0400 Subject: [PATCH] Add vrml export to cli Roughcut as the vrml exporter needs some loving Fixes https://gitlab.com/kicad/code/kicad/-/issues/15472 Fixes https://gitlab.com/kicad/code/kicad/-/issues/13952 --- common/jobs/job_export_pcb_3d.h | 22 ++- kicad/cli/command_pcb_export_3d.cpp | 195 +++++++++++++++++--------- kicad/kicad_cli.cpp | 4 +- pcbnew/dialogs/dialog_export_vrml.cpp | 6 +- pcbnew/exporters/exporter_vrml.cpp | 13 +- pcbnew/pcbnew_jobs_handler.cpp | 98 +++++++++---- 6 files changed, 232 insertions(+), 106 deletions(-) diff --git a/common/jobs/job_export_pcb_3d.h b/common/jobs/job_export_pcb_3d.h index f70deb4eb1..b94aa579ed 100644 --- a/common/jobs/job_export_pcb_3d.h +++ b/common/jobs/job_export_pcb_3d.h @@ -32,6 +32,7 @@ public: m_overwrite( false ), m_useGridOrigin( false ), m_useDrillOrigin( false ), + m_hasUserOrigin( false ), m_boardOnly( false ), m_includeUnspecified( false ), m_includeDNP( false ), @@ -44,7 +45,10 @@ public: m_BoardOutlinesChainingEpsilon( 0.01 ), // 0.01 mm is a good value m_exportTracks( false ), // Extremely time consuming if true m_exportZones( false ), // Extremely time consuming if true - m_format( JOB_EXPORT_PCB_3D::FORMAT::UNKNOWN ) + m_format( JOB_EXPORT_PCB_3D::FORMAT::UNKNOWN ), + m_vrmlUnits( JOB_EXPORT_PCB_3D::VRML_UNITS::METERS ), + m_vrmlModelDir( wxEmptyString ), + m_vrmlRelativePaths( false ) { } @@ -52,12 +56,22 @@ public: { UNKNOWN, // defefer to arg STEP, - GLB + GLB, + VRML + }; + + enum class VRML_UNITS + { + INCHES, + MILLIMETERS, + METERS, + TENTHS // inches }; bool m_overwrite; bool m_useGridOrigin; bool m_useDrillOrigin; + bool m_hasUserOrigin; bool m_boardOnly; bool m_includeUnspecified; bool m_includeDNP; @@ -70,6 +84,10 @@ public: bool m_exportTracks; bool m_exportZones; JOB_EXPORT_PCB_3D::FORMAT m_format; + + VRML_UNITS m_vrmlUnits; + wxString m_vrmlModelDir; + bool m_vrmlRelativePaths; }; #endif diff --git a/kicad/cli/command_pcb_export_3d.cpp b/kicad/cli/command_pcb_export_3d.cpp index 693613006f..b91d81b676 100644 --- a/kicad/cli/command_pcb_export_3d.cpp +++ b/kicad/cli/command_pcb_export_3d.cpp @@ -41,6 +41,9 @@ #define ARG_INCLUDE_TRACKS "--include-tracks" #define ARG_INCLUDE_ZONES "--include-zones" #define ARG_FORMAT "--format" +#define ARG_VRML_UNITS "--units" +#define ARG_VRML_MODELS_DIR "--models-dir" +#define ARG_VRML_MODELS_RELATIVE "--models-relative" #define REGEX_QUANTITY "([\\s]*[+-]?[\\d]*[.]?[\\d]*)" #define REGEX_DELIMITER "(?:[\\s]*x)" @@ -58,59 +61,85 @@ CLI::PCB_EXPORT_3D_COMMAND::PCB_EXPORT_3D_COMMAND( const std::string& aName, .help( UTF8STDSTR( _( "Output file format, options: step, glb (binary glTF)" ) ) ); } - m_argParser.add_argument( ARG_DRILL_ORIGIN ) - .help( UTF8STDSTR( _( "Use Drill Origin for output origin" ) ) ) - .implicit_value( true ) - .default_value( false ); - - m_argParser.add_argument( ARG_GRID_ORIGIN ) - .help( UTF8STDSTR( _( "Use Grid Origin for output origin" ) ) ) - .implicit_value( true ) - .default_value( false ); - - m_argParser.add_argument( ARG_NO_UNSPECIFIED ) - .help( UTF8STDSTR( _( "Exclude 3D models for components with 'Unspecified' footprint type" ) ) ) - .implicit_value( true ) - .default_value( false ); - - m_argParser.add_argument( ARG_NO_DNP ) - .help( UTF8STDSTR( _( "Exclude 3D models for components with 'Do not populate' attribute" ) ) ) - .implicit_value( true ) - .default_value( false ); - - m_argParser.add_argument( "--subst-models" ) - .help( UTF8STDSTR( _( "Substitute STEP or IGS models with the same name in place of VRML models" ) ) ) - .implicit_value( true ) - .default_value( false ); - m_argParser.add_argument( ARG_FORCE, "-f" ) .help( UTF8STDSTR( _( "Overwrite output file" ) ) ) .implicit_value( true ) .default_value( false ); - m_argParser.add_argument( ARG_BOARD_ONLY ) - .help( UTF8STDSTR( _( "Only generate a board with no components" ) ) ) - .implicit_value( true ) - .default_value( false ); + if( m_format == JOB_EXPORT_PCB_3D::FORMAT::STEP || m_format == JOB_EXPORT_PCB_3D::FORMAT::GLB ) + { + m_argParser.add_argument( ARG_GRID_ORIGIN ) + .help( UTF8STDSTR( _( "Use Grid Origin for output origin" ) ) ) + .implicit_value( true ) + .default_value( false ); - m_argParser.add_argument( ARG_INCLUDE_TRACKS ) - .help( UTF8STDSTR( _( "Export tracks (extremely time consuming)" ) ) ) - .implicit_value( true ) - .default_value( false ); + m_argParser.add_argument( ARG_DRILL_ORIGIN ) + .help( UTF8STDSTR( _( "Use Drill Origin for output origin" ) ) ) + .implicit_value( true ) + .default_value( false ); - m_argParser.add_argument( ARG_INCLUDE_ZONES ) - .help( UTF8STDSTR( _( "Export zones (extremely time consuming)" ) ) ) - .implicit_value( true ) - .default_value( false ); + m_argParser.add_argument( ARG_NO_UNSPECIFIED ) + .help( UTF8STDSTR( _( + "Exclude 3D models for components with 'Unspecified' footprint type" ) ) ) + .implicit_value( true ) + .default_value( false ); - m_argParser.add_argument( ARG_MIN_DISTANCE ) - .default_value( std::string( "0.01mm" ) ) - .help( UTF8STDSTR( _( "Minimum distance between points to treat them as separate ones" ) ) ); + m_argParser.add_argument( ARG_NO_DNP ) + .help( UTF8STDSTR( + _( "Exclude 3D models for components with 'Do not populate' attribute" ) ) ) + .implicit_value( true ) + .default_value( false ); + + m_argParser.add_argument( "--subst-models" ) + .help( UTF8STDSTR( _( "Substitute STEP or IGS models with the same name in place " + "of VRML models" ) ) ) + .implicit_value( true ) + .default_value( false ); + + m_argParser.add_argument( ARG_BOARD_ONLY ) + .help( UTF8STDSTR( _( "Only generate a board with no components" ) ) ) + .implicit_value( true ) + .default_value( false ); + + m_argParser.add_argument( ARG_INCLUDE_TRACKS ) + .help( UTF8STDSTR( _( "Export tracks (extremely time consuming)" ) ) ) + .implicit_value( true ) + .default_value( false ); + + m_argParser.add_argument( ARG_INCLUDE_ZONES ) + .help( UTF8STDSTR( _( "Export zones (extremely time consuming)" ) ) ) + .implicit_value( true ) + .default_value( false ); + + m_argParser.add_argument( ARG_MIN_DISTANCE ) + .default_value( std::string( "0.01mm" ) ) + .help( UTF8STDSTR( + _( "Minimum distance between points to treat them as separate ones" ) ) ); + } m_argParser.add_argument( ARG_USER_ORIGIN ) .default_value( std::string() ) .help( UTF8STDSTR( _( "User-specified output origin ex. 1x1in, 1x1inch, 25.4x25.4mm (default unit mm)" ) ) ); + if( m_format == JOB_EXPORT_PCB_3D::FORMAT::VRML ) + { + m_argParser.add_argument( ARG_VRML_UNITS ) + .default_value( std::string( "in" ) ) + .help( UTF8STDSTR( + _( "Output units; ascii or csv format only; valid options: mm, m, in, tenths" ) ) ); + + m_argParser.add_argument( ARG_VRML_MODELS_DIR ) + .default_value( std::string( "" ) ) + .help( UTF8STDSTR( + _( "Name of folder to create and store 3d models in, if not specified or " + "empty, the models will be embedded in main exported vrml file" ) ) ); + + m_argParser.add_argument( ARG_VRML_MODELS_RELATIVE ) + .help( UTF8STDSTR( _( "Used with --models-dir to output relative paths in the resulting file" ) ) ) + .implicit_value( true ) + .default_value( false ); + } + m_argParser.add_argument( "-o", ARG_OUTPUT ) .default_value( std::string() ) .help( UTF8STDSTR( _( "Output file name" ) ) ); @@ -122,17 +151,21 @@ int CLI::PCB_EXPORT_3D_COMMAND::doPerform( KIWAY& aKiway ) { std::unique_ptr<JOB_EXPORT_PCB_3D> step( new JOB_EXPORT_PCB_3D( true ) ); - step->m_useDrillOrigin = m_argParser.get<bool>( ARG_DRILL_ORIGIN ); - step->m_useGridOrigin = m_argParser.get<bool>( ARG_GRID_ORIGIN ); - step->m_includeUnspecified = !m_argParser.get<bool>( ARG_NO_UNSPECIFIED ); - step->m_includeDNP = !m_argParser.get<bool>( ARG_NO_DNP ); - step->m_substModels = m_argParser.get<bool>( ARG_SUBST_MODELS ); + if( m_format == JOB_EXPORT_PCB_3D::FORMAT::STEP || m_format == JOB_EXPORT_PCB_3D::FORMAT::GLB ) + { + step->m_useDrillOrigin = m_argParser.get<bool>( ARG_DRILL_ORIGIN ); + step->m_useGridOrigin = m_argParser.get<bool>( ARG_GRID_ORIGIN ); + step->m_includeUnspecified = !m_argParser.get<bool>( ARG_NO_UNSPECIFIED ); + step->m_includeDNP = !m_argParser.get<bool>( ARG_NO_DNP ); + step->m_substModels = m_argParser.get<bool>( ARG_SUBST_MODELS ); + step->m_exportTracks = m_argParser.get<bool>( ARG_INCLUDE_TRACKS ); + step->m_exportZones = m_argParser.get<bool>( ARG_INCLUDE_ZONES ); + step->m_boardOnly = m_argParser.get<bool>( ARG_BOARD_ONLY ); + } + step->m_overwrite = m_argParser.get<bool>( ARG_FORCE ); step->m_filename = FROM_UTF8( m_argParser.get<std::string>( ARG_INPUT ).c_str() ); step->m_outputFile = FROM_UTF8( m_argParser.get<std::string>( ARG_OUTPUT ).c_str() ); - step->m_boardOnly = m_argParser.get<bool>( ARG_BOARD_ONLY ); - step->m_exportTracks = m_argParser.get<bool>( ARG_INCLUDE_TRACKS ); - step->m_exportZones = m_argParser.get<bool>( ARG_INCLUDE_ZONES ); step->m_format = m_format; if( step->m_format == JOB_EXPORT_PCB_3D::FORMAT::UNKNOWN ) @@ -150,6 +183,29 @@ int CLI::PCB_EXPORT_3D_COMMAND::doPerform( KIWAY& aKiway ) } } + if( step->m_format == JOB_EXPORT_PCB_3D::FORMAT::VRML ) + { + wxString units = FROM_UTF8( m_argParser.get<std::string>( ARG_VRML_UNITS ).c_str() ); + + if( units == wxS( "in" ) ) + step->m_vrmlUnits = JOB_EXPORT_PCB_3D::VRML_UNITS::INCHES; + else if( units == wxS( "mm" ) ) + step->m_vrmlUnits = JOB_EXPORT_PCB_3D::VRML_UNITS::MILLIMETERS; + else if( units == wxS( "m" ) ) + step->m_vrmlUnits = JOB_EXPORT_PCB_3D::VRML_UNITS::METERS; + else if( units == wxS( "tenths" ) ) + step->m_vrmlUnits = JOB_EXPORT_PCB_3D::VRML_UNITS::TENTHS; + else + { + wxFprintf( stderr, _( "Invalid units specified\n" ) ); + return EXIT_CODES::ERR_ARGS; + } + + step->m_vrmlModelDir = FROM_UTF8( m_argParser.get<std::string>( ARG_VRML_MODELS_DIR ).c_str() ); + + step->m_vrmlRelativePaths = m_argParser.get<bool>( ARG_VRML_MODELS_RELATIVE ); + } + wxString userOrigin = FROM_UTF8( m_argParser.get<std::string>( ARG_USER_ORIGIN ).c_str() ); LOCALE_IO dummy; // Switch to "C" locale @@ -192,31 +248,36 @@ int CLI::PCB_EXPORT_3D_COMMAND::doPerform( KIWAY& aKiway ) return CLI::EXIT_CODES::ERR_ARGS; } } + + step->m_hasUserOrigin = true; } - wxString minDistance = FROM_UTF8( m_argParser.get<std::string>( ARG_MIN_DISTANCE ).c_str() ); - - if( !minDistance.IsEmpty() ) + if( m_format == JOB_EXPORT_PCB_3D::FORMAT::STEP || m_format == JOB_EXPORT_PCB_3D::FORMAT::GLB ) { - std::regex re_pattern( REGEX_QUANTITY REGEX_UNIT, - std::regex_constants::icase ); - std::smatch sm; - std::string str( minDistance.ToUTF8() ); - std::regex_search( str, sm, re_pattern ); - step->m_BoardOutlinesChainingEpsilon = atof( sm.str( 1 ).c_str() ); + wxString minDistance = + FROM_UTF8( m_argParser.get<std::string>( ARG_MIN_DISTANCE ).c_str() ); - std::string tunit( sm[2] ); - - if( tunit.size() > 0 ) // No unit accepted ( default = mm ) + if( !minDistance.IsEmpty() ) { - if( !tunit.compare( "in" ) || !tunit.compare( "inch" ) ) + std::regex re_pattern( REGEX_QUANTITY REGEX_UNIT, std::regex_constants::icase ); + std::smatch sm; + std::string str( minDistance.ToUTF8() ); + std::regex_search( str, sm, re_pattern ); + step->m_BoardOutlinesChainingEpsilon = atof( sm.str( 1 ).c_str() ); + + std::string tunit( sm[2] ); + + if( tunit.size() > 0 ) // No unit accepted ( default = mm ) { - step->m_BoardOutlinesChainingEpsilon *= 25.4; - } - else if( tunit.compare( "mm" ) ) - { - std::cout << m_argParser; - return CLI::EXIT_CODES::ERR_ARGS; + if( !tunit.compare( "in" ) || !tunit.compare( "inch" ) ) + { + step->m_BoardOutlinesChainingEpsilon *= 25.4; + } + else if( tunit.compare( "mm" ) ) + { + std::cout << m_argParser; + return CLI::EXIT_CODES::ERR_ARGS; + } } } } diff --git a/kicad/kicad_cli.cpp b/kicad/kicad_cli.cpp index fef598aa67..f8f4fff4eb 100644 --- a/kicad/kicad_cli.cpp +++ b/kicad/kicad_cli.cpp @@ -132,6 +132,7 @@ static CLI::PCB_EXPORT_DRILL_COMMAND exportPcbDrillCmd{}; static CLI::PCB_EXPORT_DXF_COMMAND exportPcbDxfCmd{}; static CLI::PCB_EXPORT_3D_COMMAND exportPcbGlbCmd{ "glb", JOB_EXPORT_PCB_3D::FORMAT::GLB }; static CLI::PCB_EXPORT_3D_COMMAND exportPcbStepCmd{ "step", JOB_EXPORT_PCB_3D::FORMAT::STEP }; +static CLI::PCB_EXPORT_3D_COMMAND exportPcbVrmlCmd{ "vrml", JOB_EXPORT_PCB_3D::FORMAT::VRML }; static CLI::PCB_EXPORT_SVG_COMMAND exportPcbSvgCmd{}; static CLI::PCB_EXPORT_PDF_COMMAND exportPcbPdfCmd{}; static CLI::PCB_EXPORT_POS_COMMAND exportPcbPosCmd{}; @@ -192,7 +193,8 @@ static std::vector<COMMAND_ENTRY> commandStack = { &exportPcbPdfCmd, &exportPcbPosCmd, &exportPcbStepCmd, - &exportPcbSvgCmd + &exportPcbSvgCmd, + &exportPcbVrmlCmd } } } diff --git a/pcbnew/dialogs/dialog_export_vrml.cpp b/pcbnew/dialogs/dialog_export_vrml.cpp index 54bd605c59..8a687053cf 100644 --- a/pcbnew/dialogs/dialog_export_vrml.cpp +++ b/pcbnew/dialogs/dialog_export_vrml.cpp @@ -231,9 +231,9 @@ void PCB_EDIT_FRAME::OnExportVRML( wxCommandEvent& event ) { // Origin = board center: BOARD* pcb = GetBoard(); - VECTOR2I center = pcb->GetBoundingBox().GetCenter(); - aXRef = pcbIUScale.IUTomm( center.x ); - aYRef = pcbIUScale.IUTomm( center.y ); + BOX2I bbox = pcb->ComputeBoundingBox( true ); + aXRef = pcbIUScale.IUTomm( bbox.GetCenter().x ); + aYRef = pcbIUScale.IUTomm( bbox.GetCenter().y ); } double scale = scaleList[dlg.GetUnits()]; // final scale export diff --git a/pcbnew/exporters/exporter_vrml.cpp b/pcbnew/exporters/exporter_vrml.cpp index e11bba99bd..503f5bee78 100644 --- a/pcbnew/exporters/exporter_vrml.cpp +++ b/pcbnew/exporters/exporter_vrml.cpp @@ -1025,7 +1025,6 @@ void EXPORTER_PCB_VRML::ExportVrmlFootprint( FOOTPRINT* aFootprint, std::ostream auto sM = aFootprint->Models().begin(); auto eM = aFootprint->Models().end(); - wxFileName subdir( m_Subdir3DFpModels, wxT( "" ) ); while( sM != eM ) { @@ -1245,7 +1244,11 @@ bool EXPORTER_PCB_VRML::ExportVRML_File( PROJECT* aProject, wxString *aMessages, SetScale( aMMtoWRMLunit ); m_UseInlineModelsInBrdfile = aExport3DFiles; - m_Subdir3DFpModels = a3D_Subdir; + + wxFileName subdir( a3D_Subdir, wxT( "" ) ); + // convert the subdir path to a absolute full one with the output file as the cwd + m_Subdir3DFpModels = subdir.GetAbsolutePath( wxFileName( aFullFileName ).GetPath() ); + m_UseRelPathIn3DModelFilename = aUseRelativePaths; m_Cache3Dmodels = aProject->Get3DCacheManager(); @@ -1329,11 +1332,9 @@ bool PCB_EDIT_FRAME::ExportVRML_File( const wxString& aFullFileName, double aMMt void EXPORTER_PCB_VRML::ExportFp3DModelsAsLinkedFile( const wxString& aFullFileName ) { // check if the 3D Subdir exists - create if not - wxFileName subdir( m_Subdir3DFpModels, wxT( "" ) ); - - if( ! subdir.DirExists() ) + if( !wxDir::Exists( m_Subdir3DFpModels ) ) { - if( !wxDir::Make( subdir.GetFullPath() ) ) + if( !wxDir::Make( m_Subdir3DFpModels ) ) throw( std::runtime_error( "Could not create 3D model subdirectory" ) ); } diff --git a/pcbnew/pcbnew_jobs_handler.cpp b/pcbnew/pcbnew_jobs_handler.cpp index 6a6ad4dad8..b403f1227e 100644 --- a/pcbnew/pcbnew_jobs_handler.cpp +++ b/pcbnew/pcbnew_jobs_handler.cpp @@ -59,6 +59,7 @@ #include <plugins/kicad/pcb_plugin.h> #include <reporter.h> #include <wildcards_and_files_ext.h> +#include <export_vrml.h> #include "pcbnew_scripting_helpers.h" @@ -96,36 +97,79 @@ int PCBNEW_JOBS_HANDLER::JobExportStep( JOB* aJob ) BOARD* brd = LoadBoard( aStepJob->m_filename ); - EXPORTER_STEP_PARAMS params; - params.m_exportTracks = aStepJob->m_exportTracks; - params.m_exportZones = aStepJob->m_exportZones; - params.m_includeUnspecified = aStepJob->m_includeUnspecified; - params.m_includeDNP = aStepJob->m_includeDNP; - params.m_BoardOutlinesChainingEpsilon = aStepJob->m_BoardOutlinesChainingEpsilon; - params.m_overwrite = aStepJob->m_overwrite; - params.m_substModels = aStepJob->m_substModels; - params.m_origin = VECTOR2D( aStepJob->m_xOrigin, aStepJob->m_yOrigin ); - params.m_useDrillOrigin = aStepJob->m_useDrillOrigin; - params.m_useGridOrigin = aStepJob->m_useGridOrigin; - params.m_boardOnly = aStepJob->m_boardOnly; - - switch( aStepJob->m_format ) + if( aStepJob->m_format == JOB_EXPORT_PCB_3D::FORMAT::VRML ) { - case JOB_EXPORT_PCB_3D::FORMAT::STEP: - params.m_format = EXPORTER_STEP_PARAMS::FORMAT::STEP; - break; - case JOB_EXPORT_PCB_3D::FORMAT::GLB: - params.m_format = EXPORTER_STEP_PARAMS::FORMAT::GLB; - break; - default: return CLI::EXIT_CODES::ERR_UNKNOWN; // should have gotten here + double scale = 0.0; + switch ( aStepJob->m_vrmlUnits ) + { + case JOB_EXPORT_PCB_3D::VRML_UNITS::MILLIMETERS: scale = 1.0; break; + case JOB_EXPORT_PCB_3D::VRML_UNITS::METERS: scale = 0.001; break; + case JOB_EXPORT_PCB_3D::VRML_UNITS::TENTHS: scale = 10.0 / 25.4; break; + case JOB_EXPORT_PCB_3D::VRML_UNITS::INCHES: scale = 1.0 / 25.4; break; + } + + EXPORTER_VRML vrmlExporter( brd ); + wxString messages; + + double originX = pcbIUScale.IUTomm( aStepJob->m_xOrigin ); + double originY = pcbIUScale.IUTomm( aStepJob->m_yOrigin ); + + if( !aStepJob->m_hasUserOrigin ) + { + BOX2I bbox = brd->ComputeBoundingBox( true ); + originX = pcbIUScale.IUTomm( bbox.GetCenter().x ); + originY = pcbIUScale.IUTomm( bbox.GetCenter().y ); + } + + bool success = vrmlExporter.ExportVRML_File( + brd->GetProject(), &messages, aStepJob->m_outputFile, scale, + !aStepJob->m_vrmlModelDir.IsEmpty(), aStepJob->m_vrmlRelativePaths, + aStepJob->m_vrmlModelDir, originX, originY ); + + if ( success ) + { + m_reporter->Report( wxString::Format( _( "Successfully exported VRML to %s" ), aStepJob->m_outputFile ), + RPT_SEVERITY_INFO ); + } + else + { + m_reporter->Report( _( "Error exporting VRML" ), RPT_SEVERITY_ERROR ); + return CLI::EXIT_CODES::ERR_UNKNOWN; + } } - - EXPORTER_STEP stepExporter( brd, params ); - stepExporter.m_outputFile = aStepJob->m_outputFile; - - if( !stepExporter.Export() ) + else { - return CLI::EXIT_CODES::ERR_UNKNOWN; + EXPORTER_STEP_PARAMS params; + params.m_exportTracks = aStepJob->m_exportTracks; + params.m_exportZones = aStepJob->m_exportZones; + params.m_includeUnspecified = aStepJob->m_includeUnspecified; + params.m_includeDNP = aStepJob->m_includeDNP; + params.m_BoardOutlinesChainingEpsilon = aStepJob->m_BoardOutlinesChainingEpsilon; + params.m_overwrite = aStepJob->m_overwrite; + params.m_substModels = aStepJob->m_substModels; + params.m_origin = VECTOR2D( aStepJob->m_xOrigin, aStepJob->m_yOrigin ); + params.m_useDrillOrigin = aStepJob->m_useDrillOrigin; + params.m_useGridOrigin = aStepJob->m_useGridOrigin; + params.m_boardOnly = aStepJob->m_boardOnly; + + switch( aStepJob->m_format ) + { + case JOB_EXPORT_PCB_3D::FORMAT::STEP: + params.m_format = EXPORTER_STEP_PARAMS::FORMAT::STEP; + break; + case JOB_EXPORT_PCB_3D::FORMAT::GLB: + params.m_format = EXPORTER_STEP_PARAMS::FORMAT::GLB; + break; + default: return CLI::EXIT_CODES::ERR_UNKNOWN; // should have gotten here + } + + EXPORTER_STEP stepExporter( brd, params ); + stepExporter.m_outputFile = aStepJob->m_outputFile; + + if( !stepExporter.Export() ) + { + return CLI::EXIT_CODES::ERR_UNKNOWN; + } } return CLI::EXIT_CODES::OK;