From 7fb048c6ec35655f44f62ed3cadd3d591fafb0f6 Mon Sep 17 00:00:00 2001 From: Ethan Chien Date: Sun, 28 Apr 2024 20:49:46 +0800 Subject: [PATCH 1/3] Add JOB_PCB_CONVERT --- common/CMakeLists.txt | 2 + common/jobs/job_pcb_convert.cpp | 30 +++ common/jobs/job_pcb_convert.h | 57 ++++++ common/jobs/job_sch_convert.cpp | 30 +++ common/jobs/job_sch_convert.h | 55 ++++++ kicad/CMakeLists.txt | 2 + kicad/cli/command_pcb_convert.cpp | 305 ++++++++++++++++++++++++++++++ kicad/cli/command_pcb_convert.h | 45 +++++ kicad/cli/command_sch_convert.cpp | 29 +++ kicad/cli/command_sch_convert.h | 44 +++++ pcbnew/pcbnew_jobs_handler.cpp | 57 ++++++ pcbnew/pcbnew_jobs_handler.h | 1 + 12 files changed, 657 insertions(+) create mode 100644 common/jobs/job_pcb_convert.cpp create mode 100644 common/jobs/job_pcb_convert.h create mode 100644 common/jobs/job_sch_convert.cpp create mode 100644 common/jobs/job_sch_convert.h create mode 100644 kicad/cli/command_pcb_convert.cpp create mode 100644 kicad/cli/command_pcb_convert.h create mode 100644 kicad/cli/command_sch_convert.cpp create mode 100644 kicad/cli/command_sch_convert.h diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 9d99b2672f..d441feb4a5 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -80,6 +80,8 @@ set( KICOMMON_SRCS jobs/job_sch_erc.cpp jobs/job_sym_export_svg.cpp jobs/job_sym_upgrade.cpp + jobs/job_pcb_convert.cpp + jobs/job_sch_convert.cpp kicad_curl/kicad_curl.cpp kicad_curl/kicad_curl_easy.cpp diff --git a/common/jobs/job_pcb_convert.cpp b/common/jobs/job_pcb_convert.cpp new file mode 100644 index 0000000000..98cf72b9b6 --- /dev/null +++ b/common/jobs/job_pcb_convert.cpp @@ -0,0 +1,30 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2023 Ethan Chien + * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "job_pcb_convert.h" +#include "job.h" + +JOB_PCB_CONVERT::JOB_PCB_CONVERT( bool aIsCli ) : JOB( "convert", aIsCli ) +{ +} diff --git a/common/jobs/job_pcb_convert.h b/common/jobs/job_pcb_convert.h new file mode 100644 index 0000000000..4f84058ecb --- /dev/null +++ b/common/jobs/job_pcb_convert.h @@ -0,0 +1,57 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 Ethan Chien + * Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef JOB_PCB_CONVERT_H +#define JOB_PCB_CONVERT_H + +#include +#include +#include "job.h" + +class KICOMMON_API JOB_PCB_CONVERT : public JOB +{ +public: + JOB_PCB_CONVERT( bool aIsCli ); + + wxString m_filename; + wxString m_outputFile; + + enum class From + { + ALTIUM_CIRCUIT_MAKER, + ALTIUM_CIRCUIT_STUDIO, + ALTIUM_DESIGNER + }; + + enum class To + { + KICAD + }; + + + From m_from; + To m_to; +}; + +#endif \ No newline at end of file diff --git a/common/jobs/job_sch_convert.cpp b/common/jobs/job_sch_convert.cpp new file mode 100644 index 0000000000..b281211559 --- /dev/null +++ b/common/jobs/job_sch_convert.cpp @@ -0,0 +1,30 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2023 Ethan Chien + * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "job_sch_convert.h" +#include "job.h" + +JOB_SCH_CONVERT::JOB_SCH_CONVERT( bool aIsCli ) : JOB( "convert", aIsCli ) +{ +} diff --git a/common/jobs/job_sch_convert.h b/common/jobs/job_sch_convert.h new file mode 100644 index 0000000000..01b5f98baf --- /dev/null +++ b/common/jobs/job_sch_convert.h @@ -0,0 +1,55 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 Ethan Chien + * Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef JOB_SCH_CONVERT_H +#define JOB_SCH_CONVERT_H + +#include +#include +#include "job.h" + + +class KICOMMON_API JOB_SCH_CONVERT : public JOB +{ +public: + JOB_SCH_CONVERT( bool aIsCli ); + wxString m_filename; + wxString m_outputFile; + + enum class From + { + ALTIUM + }; + + enum class To + { + KICAD + }; + + + From m_from; + To m_to; +}; + +#endif \ No newline at end of file diff --git a/kicad/CMakeLists.txt b/kicad/CMakeLists.txt index e34422c9a2..c476682845 100644 --- a/kicad/CMakeLists.txt +++ b/kicad/CMakeLists.txt @@ -62,6 +62,8 @@ set( KICAD_CLI_SRCS cli/command_sym_export_svg.cpp cli/command_sym_upgrade.cpp cli/command_version.cpp + cli/command_pcb_convert.cpp + cli/command_sch_convert.cpp ) if( WIN32 ) diff --git a/kicad/cli/command_pcb_convert.cpp b/kicad/cli/command_pcb_convert.cpp new file mode 100644 index 0000000000..6c3226974d --- /dev/null +++ b/kicad/cli/command_pcb_convert.cpp @@ -0,0 +1,305 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2023 Ethan Chien + * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "command_pcb_convert.h" +#include +#include "jobs/job_pcb_render.h" +#include +#include +#include +#include +#include + +#include +#include +#include "../../3d-viewer/3d_viewer/eda_3d_viewer_settings.h" +#include + +#define ARG_BACKGROUND "--background" +#define ARG_QUALITY "--quality" + +#define ARG_WIDTH "--width" +#define ARG_WIDTH_SHORT "-w" + +#define ARG_HEIGHT "--height" +#define ARG_HEIGHT_SHORT "-h" + +#define ARG_SIDE "--side" +#define ARG_PRESET "--preset" +#define ARG_PAN "--pan" +#define ARG_PIVOT "--pivot" +#define ARG_ROTATE "--rotate" +#define ARG_ZOOM "--zoom" +#define ARG_PERSPECTIVE "--perspective" +#define ARG_FLOOR "--floor" + +template +static wxString enumString() +{ + wxString str; + auto names = magic_enum::enum_names(); + + for( size_t i = 0; i < names.size(); i++ ) + { + std::string name = { names[i].begin(), names[i].end() }; + + if( i > 0 ) + str << ", "; + + std::transform( name.begin(), name.end(), name.begin(), + []( unsigned char c ) + { + return std::tolower( c ); + } ); + + str << name; + } + + return str; +} + + +template +static std::vector enumChoices() +{ + std::vector out; + + for( auto& strView : magic_enum::enum_names() ) + { + std::string name = { strView.begin(), strView.end() }; + + std::transform( name.begin(), name.end(), name.begin(), + []( unsigned char c ) + { + return std::tolower( c ); + } ); + + out.emplace_back( name ); + } + + return out; +} + + +template +static std::optional strToEnum( std::string& aInput ) +{ + return magic_enum::enum_cast( aInput, magic_enum::case_insensitive ); +} + + +template +static bool getToEnum( const std::string& aInput, T& aOutput ) +{ + // If not specified, leave at default + if( aInput.empty() ) + return true; + + if( auto opt = magic_enum::enum_cast( aInput, magic_enum::case_insensitive ) ) + { + aOutput = *opt; + return true; + } + + return false; +} + + +static bool getToVector3( const std::string& aInput, VECTOR3D& aOutput ) +{ + // If not specified, leave at default + if( aInput.empty() ) + return true; + + // Remove potential quotes + wxString wxStr = From_UTF8( aInput ); + + if( wxStr[0] == '\'' ) + wxStr = wxStr.AfterFirst( '\'' ); + + if( wxStr[wxStr.length() - 1] == '\'' ) + wxStr = wxStr.BeforeLast( '\'' ); + + wxArrayString arr = wxSplit( wxStr, ',', 0 ); + + if( arr.size() != 3 ) + return false; + + VECTOR3D vec; + bool success = true; + success &= arr[0].Trim().ToCDouble( &vec.x ); + success &= arr[1].Trim().ToCDouble( &vec.y ); + success &= arr[2].Trim().ToCDouble( &vec.z ); + + if( !success ) + return false; + + aOutput = vec; + return true; +} + + +CLI::COMMAND_PCB_CONVERT::COMMAND_PCB_CONVERT() : COMMAND( "pcb_convert" ) +{ + addCommonArgs( true, true, false, false ); + addDefineArg(); + + m_argParser.add_description( + UTF8STDSTR( _( "Renders the PCB in 3D view to PNG or JPEG image" ) ) ); + + m_argParser.add_argument( ARG_WIDTH, ARG_WIDTH_SHORT ) + .default_value( 1600 ) + .scan<'i', int>() + .metavar( "WIDTH" ) + .help( UTF8STDSTR( _( "Image width" ) ) ); + + m_argParser.add_argument( ARG_HEIGHT, ARG_HEIGHT_SHORT ) + .default_value( 900 ) + .scan<'i', int>() + .metavar( "HEIGHT" ) + .help( UTF8STDSTR( _( "Image height" ) ) ); + + m_argParser.add_argument( ARG_SIDE ) + .default_value( std::string( "top" ) ) + .add_choices( enumChoices() ) + .metavar( "SIDE" ) + .help( UTF8STDSTR( wxString::Format( _( "Render from side. Options: %s" ), + enumString() ) ) ); + + m_argParser.add_argument( ARG_BACKGROUND ) + .default_value( std::string( "" ) ) + .help( UTF8STDSTR( _( "Image background. Options: transparent, opaque. Default: " + "transparent for PNG, opaque for JPEG" ) ) ) + .metavar( "BG" ); + + m_argParser.add_argument( ARG_QUALITY ) + .default_value( std::string( "basic" ) ) + .add_choices( enumChoices() ) + .metavar( "QUALITY" ) + .help( UTF8STDSTR( wxString::Format( _( "Render quality. Options: %s" ), + enumString() ) ) ); + + m_argParser.add_argument( ARG_PRESET ) + .default_value( std::string( wxString( FOLLOW_PLOT_SETTINGS ) ) ) + .metavar( "PRESET" ) + .help( UTF8STDSTR( wxString::Format( _( "Color preset. Options: %s, %s, %s, ..." ), + FOLLOW_PCB, FOLLOW_PLOT_SETTINGS, + LEGACY_PRESET_FLAG ) ) ); + + m_argParser.add_argument( ARG_FLOOR ) + .flag() + .help( UTF8STDSTR( _( "Enables floor, shadows and post-processing, even if disabled in " + "quality preset" ) ) ); + + m_argParser.add_argument( ARG_PERSPECTIVE ) + .flag() + .help( UTF8STDSTR( _( "Use perspective projection instead of orthogonal" ) ) ); + + m_argParser.add_argument( ARG_ZOOM ) + .default_value( 1.0 ) + .scan<'g', double>() + .metavar( "ZOOM" ) + .help( UTF8STDSTR( _( "Camera zoom" ) ) ); + + m_argParser.add_argument( ARG_PAN ) + .default_value( std::string( "" ) ) + .metavar( "VECTOR" ) + .help( UTF8STDSTR( _( "Pan camera, format 'X,Y,Z' e.g.: '3,0,0'" ) ) ); + + m_argParser.add_argument( ARG_PIVOT ) + .default_value( std::string( "" ) ) + .metavar( "PIVOT" ) + .help( UTF8STDSTR( _( + "Set pivot point relative to the board center in centimeters, format 'X,Y,Z' " + "e.g.: '-10,2,0'" ) ) ); + + m_argParser.add_argument( ARG_ROTATE ) + .default_value( std::string( "" ) ) + .metavar( "ANGLES" ) + .help( UTF8STDSTR( + _( "Rotate board, format 'X,Y,Z' e.g.: '-45,0,45' for isometric view" ) ) ); +} + + +int CLI::COMMAND_PCB_CONVERT::doPerform( KIWAY& aKiway ) +{ + std::unique_ptr renderJob( new JOB_PCB_RENDER( true ) ); + + renderJob->m_outputFile = m_argOutput; + renderJob->m_filename = m_argInput; + renderJob->SetVarOverrides( m_argDefineVars ); + + renderJob->m_colorPreset = m_argParser.get( ARG_PRESET ); + renderJob->m_width = m_argParser.get( ARG_WIDTH ); + renderJob->m_height = m_argParser.get( ARG_HEIGHT ); + renderJob->m_zoom = m_argParser.get( ARG_ZOOM ); + renderJob->m_perspective = m_argParser.get( ARG_PERSPECTIVE ); + renderJob->m_floor = m_argParser.get( ARG_FLOOR ); + + getToEnum( m_argParser.get( ARG_QUALITY ), renderJob->m_quality ); + getToEnum( m_argParser.get( ARG_SIDE ), renderJob->m_side ); + + if( !getToEnum( m_argParser.get( ARG_BACKGROUND ), renderJob->m_bgStyle ) ) + { + wxFprintf( stderr, _( "Invalid background\n" ) ); + return EXIT_CODES::ERR_ARGS; + } + + if( !getToVector3( m_argParser.get( ARG_ROTATE ), renderJob->m_rotation ) ) + { + wxFprintf( stderr, _( "Invalid rotation format\n" ) ); + return EXIT_CODES::ERR_ARGS; + } + + if( !getToVector3( m_argParser.get( ARG_PAN ), renderJob->m_pan ) ) + { + wxFprintf( stderr, _( "Invalid pan format\n" ) ); + return EXIT_CODES::ERR_ARGS; + } + + if( !getToVector3( m_argParser.get( ARG_PIVOT ), renderJob->m_pivot ) ) + { + wxFprintf( stderr, _( "Invalid pivot format\n" ) ); + return EXIT_CODES::ERR_ARGS; + } + + if( m_argOutput.Lower().EndsWith( wxS( ".png" ) ) ) + { + renderJob->m_format = JOB_PCB_RENDER::FORMAT::PNG; + } + else if( m_argOutput.Lower().EndsWith( wxS( ".jpg" ) ) + || m_argOutput.Lower().EndsWith( wxS( ".jpeg" ) ) ) + { + renderJob->m_format = JOB_PCB_RENDER::FORMAT::JPEG; + } + else + { + wxFprintf( stderr, _( "Invalid image format\n" ) ); + return EXIT_CODES::ERR_ARGS; + } + + int exitCode = aKiway.ProcessJob( KIWAY::FACE_PCB, renderJob.get() ); + + return exitCode; +} diff --git a/kicad/cli/command_pcb_convert.h b/kicad/cli/command_pcb_convert.h new file mode 100644 index 0000000000..06205179b9 --- /dev/null +++ b/kicad/cli/command_pcb_convert.h @@ -0,0 +1,45 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 Ethan Chien + * Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef COMMAND_PCB_CONVERT_H +#define COMMAND_PCB_CONVERT_H + +#include "command.h" + +namespace CLI +{ + +class COMMAND_PCB_CONVERT : public COMMAND +{ +public: + COMMAND_PCB_CONVERT(); + +protected: + int doPerform( KIWAY& aKiway ) override; +}; + +} // namespace CLI + + +#endif \ No newline at end of file diff --git a/kicad/cli/command_sch_convert.cpp b/kicad/cli/command_sch_convert.cpp new file mode 100644 index 0000000000..3a4a88adf7 --- /dev/null +++ b/kicad/cli/command_sch_convert.cpp @@ -0,0 +1,29 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2023 Ethan Chien + * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "command_sch_convert.h" + +CLI::COMMAND_SCH_CONVERT::COMMAND_SCH_CONVERT() : COMMAND( "convert" ) +{ +} diff --git a/kicad/cli/command_sch_convert.h b/kicad/cli/command_sch_convert.h new file mode 100644 index 0000000000..e09f20ce01 --- /dev/null +++ b/kicad/cli/command_sch_convert.h @@ -0,0 +1,44 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 Ethan Chien + * Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef COMMAND_SCH_CONVERT_H +#define COMMAND_SCH_CONVERT_H +#include "command.h" + + +namespace CLI +{ + +class COMMAND_SCH_CONVERT : public COMMAND +{ +public: + COMMAND_SCH_CONVERT(); + +private: +}; + +} // namespace CLI + + +#endif \ No newline at end of file diff --git a/pcbnew/pcbnew_jobs_handler.cpp b/pcbnew/pcbnew_jobs_handler.cpp index 13260e3a7b..ee7c0a3dd3 100644 --- a/pcbnew/pcbnew_jobs_handler.cpp +++ b/pcbnew/pcbnew_jobs_handler.cpp @@ -18,6 +18,7 @@ * with this program. If not, see . */ +#include #include #include "pcbnew_jobs_handler.h" #include @@ -39,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -73,6 +75,9 @@ #include #include #include +#include +#include +#include #include "pcbnew_scripting_helpers.h" @@ -106,6 +111,8 @@ PCBNEW_JOBS_HANDLER::PCBNEW_JOBS_HANDLER( KIWAY* aKiway ) : Register( "drc", std::bind( &PCBNEW_JOBS_HANDLER::JobExportDrc, this, std::placeholders::_1 ) ); Register( "ipc2581", std::bind( &PCBNEW_JOBS_HANDLER::JobExportIpc2581, this, std::placeholders::_1 ) ); + Register( "convert", + std::bind( &PCBNEW_JOBS_HANDLER::JobExportConvert, this, std::placeholders::_1 ) ); } @@ -1428,6 +1435,56 @@ int PCBNEW_JOBS_HANDLER::JobExportIpc2581( JOB* aJob ) return CLI::EXIT_CODES::SUCCESS; } +int PCBNEW_JOBS_HANDLER::JobExportConvert( JOB* aJob ) +{ + auto aConvertJob = dynamic_cast( aJob ); + + if( aConvertJob == nullptr ) + return CLI::EXIT_CODES::ERR_UNKNOWN; + + if( aJob->IsCli() ) + m_reporter->Report( _( "Loading board\n" ), RPT_SEVERITY_INFO ); + + BOARD* brd{}; + + static const auto mapFromToPCBType = std::map{ + { JOB_PCB_CONVERT::From::ALTIUM_CIRCUIT_MAKER, + PCB_IO_MGR::PCB_FILE_T::ALTIUM_CIRCUIT_MAKER }, + { JOB_PCB_CONVERT::From::ALTIUM_CIRCUIT_STUDIO, + PCB_IO_MGR::PCB_FILE_T::ALTIUM_CIRCUIT_STUDIO }, + { JOB_PCB_CONVERT::From::ALTIUM_DESIGNER, PCB_IO_MGR::PCB_FILE_T::ALTIUM_DESIGNER }, + }; + + if( auto it = mapFromToPCBType.find( aConvertJob->m_from ); it == mapFromToPCBType.end() ) + { + if( aConvertJob == nullptr ) + return CLI::EXIT_CODES::ERR_UNKNOWN; + } + else + { + } + + switch( aConvertJob->m_from ) + { + case JOB_PCB_CONVERT::From::ALTIUM_CIRCUIT_MAKER: + brd = LoadBoard( aConvertJob->m_filename, PCB_IO_MGR::PCB_FILE_T::ALTIUM_CIRCUIT_MAKER, + true ); + break; + case JOB_PCB_CONVERT::From::ALTIUM_CIRCUIT_STUDIO: break; + case JOB_PCB_CONVERT::From::ALTIUM_DESIGNER: break; + } + + + bool success = true; + + if( success ) + m_reporter->Report( _( "Successfully convered board" ) + wxS( "\n" ), RPT_SEVERITY_INFO ); + else + m_reporter->Report( _( "Error converting board" ) + wxS( "\n" ), RPT_SEVERITY_ERROR ); + + return CLI::EXIT_CODES::OK; +} + DS_PROXY_VIEW_ITEM* PCBNEW_JOBS_HANDLER::getDrawingSheetProxyView( BOARD* aBrd ) { diff --git a/pcbnew/pcbnew_jobs_handler.h b/pcbnew/pcbnew_jobs_handler.h index 39e50eda71..25ce7769b2 100644 --- a/pcbnew/pcbnew_jobs_handler.h +++ b/pcbnew/pcbnew_jobs_handler.h @@ -48,6 +48,7 @@ public: int JobExportFpSvg( JOB* aJob ); int JobExportDrc( JOB* aJob ); int JobExportIpc2581( JOB* aJob ); + int JobExportConvert( JOB* aJob ); private: void populateGerberPlotOptionsFromJob( PCB_PLOT_PARAMS& aPlotOpts, From 1a3079a4b2e90e66f85915db2af3b45e45970ec4 Mon Sep 17 00:00:00 2001 From: Ethan Chien Date: Mon, 29 Apr 2024 15:40:52 +0800 Subject: [PATCH 2/3] Add pcb convert cmd in kicad-cli --- common/jobs/job_pcb_convert.h | 6 +- kicad/cli/command_pcb_convert.cpp | 211 ++++-------------------------- kicad/kicad_cli.cpp | 5 + pcbnew/pcbnew_jobs_handler.cpp | 63 +++++---- 4 files changed, 71 insertions(+), 214 deletions(-) diff --git a/common/jobs/job_pcb_convert.h b/common/jobs/job_pcb_convert.h index 4f84058ecb..06e1f83a51 100644 --- a/common/jobs/job_pcb_convert.h +++ b/common/jobs/job_pcb_convert.h @@ -46,12 +46,12 @@ public: enum class To { - KICAD + KICAD_SEXP }; From m_from; - To m_to; + To m_to ; }; -#endif \ No newline at end of file +#endif diff --git a/kicad/cli/command_pcb_convert.cpp b/kicad/cli/command_pcb_convert.cpp index 6c3226974d..7c5fd63a48 100644 --- a/kicad/cli/command_pcb_convert.cpp +++ b/kicad/cli/command_pcb_convert.cpp @@ -23,6 +23,9 @@ */ #include "command_pcb_convert.h" +#include "jobs/job_pcb_convert.h" + + #include #include "jobs/job_pcb_render.h" #include @@ -33,26 +36,10 @@ #include #include -#include "../../3d-viewer/3d_viewer/eda_3d_viewer_settings.h" #include -#define ARG_BACKGROUND "--background" -#define ARG_QUALITY "--quality" - -#define ARG_WIDTH "--width" -#define ARG_WIDTH_SHORT "-w" - -#define ARG_HEIGHT "--height" -#define ARG_HEIGHT_SHORT "-h" - -#define ARG_SIDE "--side" -#define ARG_PRESET "--preset" -#define ARG_PAN "--pan" -#define ARG_PIVOT "--pivot" -#define ARG_ROTATE "--rotate" -#define ARG_ZOOM "--zoom" -#define ARG_PERSPECTIVE "--perspective" -#define ARG_FLOOR "--floor" +#define ARG_FROM "--from" +#define ARG_TO "--to" template static wxString enumString() @@ -102,13 +89,6 @@ static std::vector enumChoices() } -template -static std::optional strToEnum( std::string& aInput ) -{ - return magic_enum::enum_cast( aInput, magic_enum::case_insensitive ); -} - - template static bool getToEnum( const std::string& aInput, T& aOutput ) { @@ -125,181 +105,42 @@ static bool getToEnum( const std::string& aInput, T& aOutput ) return false; } - -static bool getToVector3( const std::string& aInput, VECTOR3D& aOutput ) -{ - // If not specified, leave at default - if( aInput.empty() ) - return true; - - // Remove potential quotes - wxString wxStr = From_UTF8( aInput ); - - if( wxStr[0] == '\'' ) - wxStr = wxStr.AfterFirst( '\'' ); - - if( wxStr[wxStr.length() - 1] == '\'' ) - wxStr = wxStr.BeforeLast( '\'' ); - - wxArrayString arr = wxSplit( wxStr, ',', 0 ); - - if( arr.size() != 3 ) - return false; - - VECTOR3D vec; - bool success = true; - success &= arr[0].Trim().ToCDouble( &vec.x ); - success &= arr[1].Trim().ToCDouble( &vec.y ); - success &= arr[2].Trim().ToCDouble( &vec.z ); - - if( !success ) - return false; - - aOutput = vec; - return true; -} - - -CLI::COMMAND_PCB_CONVERT::COMMAND_PCB_CONVERT() : COMMAND( "pcb_convert" ) +CLI::COMMAND_PCB_CONVERT::COMMAND_PCB_CONVERT() : COMMAND( "convert" ) { addCommonArgs( true, true, false, false ); addDefineArg(); m_argParser.add_description( - UTF8STDSTR( _( "Renders the PCB in 3D view to PNG or JPEG image" ) ) ); + UTF8STDSTR( _( "Convert a vendor's PCB documentation to another vendor's PCB documentation" ) ) ); - m_argParser.add_argument( ARG_WIDTH, ARG_WIDTH_SHORT ) - .default_value( 1600 ) - .scan<'i', int>() - .metavar( "WIDTH" ) - .help( UTF8STDSTR( _( "Image width" ) ) ); - m_argParser.add_argument( ARG_HEIGHT, ARG_HEIGHT_SHORT ) - .default_value( 900 ) - .scan<'i', int>() - .metavar( "HEIGHT" ) - .help( UTF8STDSTR( _( "Image height" ) ) ); + m_argParser.add_argument( ARG_FROM ) + .default_value( std::string( "altium_designer" ) ) + .add_choices( enumChoices() ) + .metavar( "FROM" ) + .help( UTF8STDSTR( wxString::Format( _( "Accepted PCB format. Options: %s" ), + enumString() ) ) ); - m_argParser.add_argument( ARG_SIDE ) - .default_value( std::string( "top" ) ) - .add_choices( enumChoices() ) - .metavar( "SIDE" ) - .help( UTF8STDSTR( wxString::Format( _( "Render from side. Options: %s" ), - enumString() ) ) ); - m_argParser.add_argument( ARG_BACKGROUND ) - .default_value( std::string( "" ) ) - .help( UTF8STDSTR( _( "Image background. Options: transparent, opaque. Default: " - "transparent for PNG, opaque for JPEG" ) ) ) - .metavar( "BG" ); + m_argParser.add_argument( ARG_TO ) + .default_value( std::string( "kicad_sexp" ) ) + .add_choices( enumChoices() ) + .metavar( "TO" ) + .help( UTF8STDSTR( wxString::Format( _( "Converted format. Options: %s" ), + enumString() ) ) ); - m_argParser.add_argument( ARG_QUALITY ) - .default_value( std::string( "basic" ) ) - .add_choices( enumChoices() ) - .metavar( "QUALITY" ) - .help( UTF8STDSTR( wxString::Format( _( "Render quality. Options: %s" ), - enumString() ) ) ); - - m_argParser.add_argument( ARG_PRESET ) - .default_value( std::string( wxString( FOLLOW_PLOT_SETTINGS ) ) ) - .metavar( "PRESET" ) - .help( UTF8STDSTR( wxString::Format( _( "Color preset. Options: %s, %s, %s, ..." ), - FOLLOW_PCB, FOLLOW_PLOT_SETTINGS, - LEGACY_PRESET_FLAG ) ) ); - - m_argParser.add_argument( ARG_FLOOR ) - .flag() - .help( UTF8STDSTR( _( "Enables floor, shadows and post-processing, even if disabled in " - "quality preset" ) ) ); - - m_argParser.add_argument( ARG_PERSPECTIVE ) - .flag() - .help( UTF8STDSTR( _( "Use perspective projection instead of orthogonal" ) ) ); - - m_argParser.add_argument( ARG_ZOOM ) - .default_value( 1.0 ) - .scan<'g', double>() - .metavar( "ZOOM" ) - .help( UTF8STDSTR( _( "Camera zoom" ) ) ); - - m_argParser.add_argument( ARG_PAN ) - .default_value( std::string( "" ) ) - .metavar( "VECTOR" ) - .help( UTF8STDSTR( _( "Pan camera, format 'X,Y,Z' e.g.: '3,0,0'" ) ) ); - - m_argParser.add_argument( ARG_PIVOT ) - .default_value( std::string( "" ) ) - .metavar( "PIVOT" ) - .help( UTF8STDSTR( _( - "Set pivot point relative to the board center in centimeters, format 'X,Y,Z' " - "e.g.: '-10,2,0'" ) ) ); - - m_argParser.add_argument( ARG_ROTATE ) - .default_value( std::string( "" ) ) - .metavar( "ANGLES" ) - .help( UTF8STDSTR( - _( "Rotate board, format 'X,Y,Z' e.g.: '-45,0,45' for isometric view" ) ) ); } int CLI::COMMAND_PCB_CONVERT::doPerform( KIWAY& aKiway ) { - std::unique_ptr renderJob( new JOB_PCB_RENDER( true ) ); - - renderJob->m_outputFile = m_argOutput; - renderJob->m_filename = m_argInput; - renderJob->SetVarOverrides( m_argDefineVars ); - - renderJob->m_colorPreset = m_argParser.get( ARG_PRESET ); - renderJob->m_width = m_argParser.get( ARG_WIDTH ); - renderJob->m_height = m_argParser.get( ARG_HEIGHT ); - renderJob->m_zoom = m_argParser.get( ARG_ZOOM ); - renderJob->m_perspective = m_argParser.get( ARG_PERSPECTIVE ); - renderJob->m_floor = m_argParser.get( ARG_FLOOR ); - - getToEnum( m_argParser.get( ARG_QUALITY ), renderJob->m_quality ); - getToEnum( m_argParser.get( ARG_SIDE ), renderJob->m_side ); - - if( !getToEnum( m_argParser.get( ARG_BACKGROUND ), renderJob->m_bgStyle ) ) - { - wxFprintf( stderr, _( "Invalid background\n" ) ); - return EXIT_CODES::ERR_ARGS; - } - - if( !getToVector3( m_argParser.get( ARG_ROTATE ), renderJob->m_rotation ) ) - { - wxFprintf( stderr, _( "Invalid rotation format\n" ) ); - return EXIT_CODES::ERR_ARGS; - } - - if( !getToVector3( m_argParser.get( ARG_PAN ), renderJob->m_pan ) ) - { - wxFprintf( stderr, _( "Invalid pan format\n" ) ); - return EXIT_CODES::ERR_ARGS; - } - - if( !getToVector3( m_argParser.get( ARG_PIVOT ), renderJob->m_pivot ) ) - { - wxFprintf( stderr, _( "Invalid pivot format\n" ) ); - return EXIT_CODES::ERR_ARGS; - } - - if( m_argOutput.Lower().EndsWith( wxS( ".png" ) ) ) - { - renderJob->m_format = JOB_PCB_RENDER::FORMAT::PNG; - } - else if( m_argOutput.Lower().EndsWith( wxS( ".jpg" ) ) - || m_argOutput.Lower().EndsWith( wxS( ".jpeg" ) ) ) - { - renderJob->m_format = JOB_PCB_RENDER::FORMAT::JPEG; - } - else - { - wxFprintf( stderr, _( "Invalid image format\n" ) ); - return EXIT_CODES::ERR_ARGS; - } - - int exitCode = aKiway.ProcessJob( KIWAY::FACE_PCB, renderJob.get() ); + std::unique_ptr convertJob( new JOB_PCB_CONVERT( true ) ); + convertJob->m_outputFile = m_argOutput; + convertJob->m_filename = m_argInput; + convertJob->SetVarOverrides( m_argDefineVars ); + getToEnum( m_argParser.get( ARG_FROM ), convertJob->m_from ); + getToEnum( m_argParser.get( ARG_TO ), convertJob->m_to ); + int exitCode = aKiway.ProcessJob( KIWAY::FACE_PCB, convertJob.get() ); return exitCode; } diff --git a/kicad/kicad_cli.cpp b/kicad/kicad_cli.cpp index a6a27be7f2..d0dedd0cb4 100644 --- a/kicad/kicad_cli.cpp +++ b/kicad/kicad_cli.cpp @@ -50,6 +50,7 @@ #include "cli/command_pcb_export.h" #include "cli/command_pcb_drc.h" #include "cli/command_pcb_render.h" +#include "cli/command_pcb_convert.h" #include "cli/command_pcb_export_3d.h" #include "cli/command_pcb_export_drill.h" #include "cli/command_pcb_export_dxf.h" @@ -108,6 +109,7 @@ struct COMMAND_ENTRY static CLI::PCB_COMMAND pcbCmd{}; static CLI::PCB_DRC_COMMAND pcbDrcCmd{}; static CLI::PCB_RENDER_COMMAND pcbRenderCmd{}; +static CLI::COMMAND_PCB_CONVERT pcbConvertCmd{}; static CLI::PCB_EXPORT_DRILL_COMMAND exportPcbDrillCmd{}; static CLI::PCB_EXPORT_DXF_COMMAND exportPcbDxfCmd{}; static CLI::PCB_EXPORT_3D_COMMAND exportPcbGlbCmd{ "glb", UTF8STDSTR( _( "Export GLB (binary GLTF)" ) ), JOB_EXPORT_PCB_3D::FORMAT::GLB }; @@ -168,6 +170,9 @@ static std::vector commandStack = { { &pcbRenderCmd }, + { + &pcbConvertCmd + }, { &exportPcbCmd, { diff --git a/pcbnew/pcbnew_jobs_handler.cpp b/pcbnew/pcbnew_jobs_handler.cpp index ee7c0a3dd3..66d8b0aecc 100644 --- a/pcbnew/pcbnew_jobs_handler.cpp +++ b/pcbnew/pcbnew_jobs_handler.cpp @@ -1437,7 +1437,7 @@ int PCBNEW_JOBS_HANDLER::JobExportIpc2581( JOB* aJob ) int PCBNEW_JOBS_HANDLER::JobExportConvert( JOB* aJob ) { - auto aConvertJob = dynamic_cast( aJob ); + JOB_PCB_CONVERT* aConvertJob = dynamic_cast( aJob ); if( aConvertJob == nullptr ) return CLI::EXIT_CODES::ERR_UNKNOWN; @@ -1445,9 +1445,7 @@ int PCBNEW_JOBS_HANDLER::JobExportConvert( JOB* aJob ) if( aJob->IsCli() ) m_reporter->Report( _( "Loading board\n" ), RPT_SEVERITY_INFO ); - BOARD* brd{}; - - static const auto mapFromToPCBType = std::map{ + static const auto converFromPCBType = std::map{ { JOB_PCB_CONVERT::From::ALTIUM_CIRCUIT_MAKER, PCB_IO_MGR::PCB_FILE_T::ALTIUM_CIRCUIT_MAKER }, { JOB_PCB_CONVERT::From::ALTIUM_CIRCUIT_STUDIO, @@ -1455,34 +1453,47 @@ int PCBNEW_JOBS_HANDLER::JobExportConvert( JOB* aJob ) { JOB_PCB_CONVERT::From::ALTIUM_DESIGNER, PCB_IO_MGR::PCB_FILE_T::ALTIUM_DESIGNER }, }; - if( auto it = mapFromToPCBType.find( aConvertJob->m_from ); it == mapFromToPCBType.end() ) + static const auto convertToPCBTYPE = std::map{ + { JOB_PCB_CONVERT::To::KICAD_SEXP, + PCB_IO_MGR::PCB_FILE_T::KICAD_SEXP } + }; + + if( auto from_type = converFromPCBType.find( aConvertJob->m_from ); from_type == converFromPCBType.end() ) { - if( aConvertJob == nullptr ) - return CLI::EXIT_CODES::ERR_UNKNOWN; + return CLI::EXIT_CODES::ERR_ARGS; } else { + + if (auto to_type = convertToPCBTYPE.find( aConvertJob->m_to ); to_type == convertToPCBTYPE.end() ) + { + return CLI::EXIT_CODES::ERR_ARGS; + } + else + { + BOARD* brd = LoadBoard( aConvertJob->m_filename, from_type->second, + true ); + try + { + IO_RELEASER pi( PCB_IO_MGR::PluginFind( to_type->second ) ); + pi->SetProgressReporter( m_progressReporter ); + pi->SaveBoard( aConvertJob->m_outputFile, brd ); + } + catch( const IO_ERROR& ioe ) + { + m_reporter->Report( wxString::Format( _( "Error converting pcb file '%s'.\n%s" ), + aConvertJob->m_filename, ioe.What() ), + RPT_SEVERITY_ERROR ); + + return CLI::EXIT_CODES::ERR_UNKNOWN; + } + + m_reporter->Report( _( "Successfully convered board" ) + wxS( "\n" ), RPT_SEVERITY_INFO ); + return CLI::EXIT_CODES::OK; + } + } - switch( aConvertJob->m_from ) - { - case JOB_PCB_CONVERT::From::ALTIUM_CIRCUIT_MAKER: - brd = LoadBoard( aConvertJob->m_filename, PCB_IO_MGR::PCB_FILE_T::ALTIUM_CIRCUIT_MAKER, - true ); - break; - case JOB_PCB_CONVERT::From::ALTIUM_CIRCUIT_STUDIO: break; - case JOB_PCB_CONVERT::From::ALTIUM_DESIGNER: break; - } - - - bool success = true; - - if( success ) - m_reporter->Report( _( "Successfully convered board" ) + wxS( "\n" ), RPT_SEVERITY_INFO ); - else - m_reporter->Report( _( "Error converting board" ) + wxS( "\n" ), RPT_SEVERITY_ERROR ); - - return CLI::EXIT_CODES::OK; } From 0d2e83633320d21e54e06e09d7fe1abb03c6c335 Mon Sep 17 00:00:00 2001 From: Ethan Chien Date: Mon, 29 Apr 2024 18:42:59 +0800 Subject: [PATCH 3/3] Add sch convert cmd in kicad-cli --- common/jobs/job_sch_convert.h | 4 +- eeschema/eeschema_jobs_handler.cpp | 66 +++++++++++++++++++++ eeschema/eeschema_jobs_handler.h | 1 + kicad/cli/command_pcb_convert.cpp | 72 ++--------------------- kicad/cli/command_pcb_convert.h | 4 +- kicad/cli/command_sch_convert.cpp | 56 +++++++++++++++++- kicad/cli/command_sch_convert.h | 7 ++- kicad/cli/command_utils.h | 94 ++++++++++++++++++++++++++++++ kicad/kicad_cli.cpp | 7 ++- pcbnew/pcbnew_jobs_handler.cpp | 3 +- 10 files changed, 236 insertions(+), 78 deletions(-) create mode 100644 kicad/cli/command_utils.h diff --git a/common/jobs/job_sch_convert.h b/common/jobs/job_sch_convert.h index 01b5f98baf..406908ec62 100644 --- a/common/jobs/job_sch_convert.h +++ b/common/jobs/job_sch_convert.h @@ -39,12 +39,12 @@ public: enum class From { - ALTIUM + SCH_ALTIUM }; enum class To { - KICAD + SCH_KICAD }; diff --git a/eeschema/eeschema_jobs_handler.cpp b/eeschema/eeschema_jobs_handler.cpp index 66ba7d4141..f140b45f81 100644 --- a/eeschema/eeschema_jobs_handler.cpp +++ b/eeschema/eeschema_jobs_handler.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -85,6 +86,8 @@ EESCHEMA_JOBS_HANDLER::EESCHEMA_JOBS_HANDLER( KIWAY* aKiway ) : std::bind( &EESCHEMA_JOBS_HANDLER::JobSymExportSvg, this, std::placeholders::_1 ) ); Register( "erc", std::bind( &EESCHEMA_JOBS_HANDLER::JobSchErc, this, std::placeholders::_1 ) ); + Register( "convert", + std::bind( &EESCHEMA_JOBS_HANDLER::JobSchConvert, this, std::placeholders::_1 ) ); } @@ -1054,3 +1057,66 @@ DS_PROXY_VIEW_ITEM* EESCHEMA_JOBS_HANDLER::getDrawingSheetProxyView( SCHEMATIC* return drawingSheet; } + +int EESCHEMA_JOBS_HANDLER::JobSchConvert( JOB* aJob ) +{ + JOB_SCH_CONVERT* aConvertJob = dynamic_cast( aJob ); + + if( !aConvertJob ) + return CLI::EXIT_CODES::ERR_UNKNOWN; + + if( aJob->IsCli() ) + m_reporter->Report( _( "Loading schematic\n" ), RPT_SEVERITY_INFO ); + + static const auto convertFromSCH = std::map { + {JOB_SCH_CONVERT::From::SCH_ALTIUM, SCH_IO_MGR::SCH_FILE_T::SCH_ALTIUM} + }; + + static const auto convertToSCH = std::map { + {JOB_SCH_CONVERT::To::SCH_KICAD, SCH_IO_MGR::SCH_FILE_T::SCH_KICAD} + }; + + if( auto from_type = convertFromSCH.find( aConvertJob->m_from ); from_type == convertFromSCH.end() ) + { + return CLI::EXIT_CODES::ERR_ARGS; + } + else + { + + if (auto to_type = convertToSCH.find( aConvertJob->m_to ); to_type == convertToSCH.end() ) + { + return CLI::EXIT_CODES::ERR_ARGS; + } + else + { + try + { + SCHEMATIC* sch = EESCHEMA_HELPERS::LoadSchematic( aConvertJob->m_filename, from_type->second, true ); + + if(!sch || !sch->IsValid()) + { + m_reporter->Report( _( "Failed to load schematic file." ) ); + return CLI::EXIT_CODES::ERR_INVALID_INPUT_FILE; + } + + IO_RELEASER pi( SCH_IO_MGR::FindPlugin( to_type->second ) ); + pi->SetProgressReporter( m_progressReporter ); + pi->SaveSchematicFile( aConvertJob->m_outputFile, &sch->Root() ,sch ); + } + catch( const IO_ERROR& ioe ) + { + m_reporter->Report( wxString::Format( _( "Error converting schematic file '%s'.\n%s" ), + aConvertJob->m_filename, ioe.What() ), + RPT_SEVERITY_ERROR ); + + return CLI::EXIT_CODES::ERR_UNKNOWN; + } + + m_reporter->Report( _( "Successfully converted schematic file" ) + wxS( "\n" ), RPT_SEVERITY_INFO ); + return CLI::EXIT_CODES::OK; + } + + } +} + + diff --git a/eeschema/eeschema_jobs_handler.h b/eeschema/eeschema_jobs_handler.h index f06ab85974..f343b9a107 100644 --- a/eeschema/eeschema_jobs_handler.h +++ b/eeschema/eeschema_jobs_handler.h @@ -43,6 +43,7 @@ public: int JobExportNetlist( JOB* aJob ); int JobExportPlot( JOB* aJob ); int JobSchErc( JOB* aJob ); + int JobSchConvert( JOB* aJob ); int JobSymUpgrade( JOB* aJob ); int JobSymExportSvg( JOB* aJob ); diff --git a/kicad/cli/command_pcb_convert.cpp b/kicad/cli/command_pcb_convert.cpp index 7c5fd63a48..4d14642b75 100644 --- a/kicad/cli/command_pcb_convert.cpp +++ b/kicad/cli/command_pcb_convert.cpp @@ -27,7 +27,7 @@ #include -#include "jobs/job_pcb_render.h" +#include "command_utils.h" #include #include #include @@ -36,82 +36,18 @@ #include #include -#include #define ARG_FROM "--from" #define ARG_TO "--to" -template -static wxString enumString() -{ - wxString str; - auto names = magic_enum::enum_names(); - for( size_t i = 0; i < names.size(); i++ ) - { - std::string name = { names[i].begin(), names[i].end() }; - - if( i > 0 ) - str << ", "; - - std::transform( name.begin(), name.end(), name.begin(), - []( unsigned char c ) - { - return std::tolower( c ); - } ); - - str << name; - } - - return str; -} - - -template -static std::vector enumChoices() -{ - std::vector out; - - for( auto& strView : magic_enum::enum_names() ) - { - std::string name = { strView.begin(), strView.end() }; - - std::transform( name.begin(), name.end(), name.begin(), - []( unsigned char c ) - { - return std::tolower( c ); - } ); - - out.emplace_back( name ); - } - - return out; -} - - -template -static bool getToEnum( const std::string& aInput, T& aOutput ) -{ - // If not specified, leave at default - if( aInput.empty() ) - return true; - - if( auto opt = magic_enum::enum_cast( aInput, magic_enum::case_insensitive ) ) - { - aOutput = *opt; - return true; - } - - return false; -} - -CLI::COMMAND_PCB_CONVERT::COMMAND_PCB_CONVERT() : COMMAND( "convert" ) +CLI::PCB_CONVERT_COMMAND::PCB_CONVERT_COMMAND() : COMMAND( "convert" ) { addCommonArgs( true, true, false, false ); addDefineArg(); m_argParser.add_description( - UTF8STDSTR( _( "Convert a vendor's PCB documentation to another vendor's PCB documentation" ) ) ); + UTF8STDSTR( _( "Convert a vendor's PCB document to another vendor's PCB document" ) ) ); m_argParser.add_argument( ARG_FROM ) @@ -132,7 +68,7 @@ CLI::COMMAND_PCB_CONVERT::COMMAND_PCB_CONVERT() : COMMAND( "convert" ) } -int CLI::COMMAND_PCB_CONVERT::doPerform( KIWAY& aKiway ) +int CLI::PCB_CONVERT_COMMAND::doPerform( KIWAY& aKiway ) { std::unique_ptr convertJob( new JOB_PCB_CONVERT( true ) ); diff --git a/kicad/cli/command_pcb_convert.h b/kicad/cli/command_pcb_convert.h index 06205179b9..9b5cd6c110 100644 --- a/kicad/cli/command_pcb_convert.h +++ b/kicad/cli/command_pcb_convert.h @@ -30,10 +30,10 @@ namespace CLI { -class COMMAND_PCB_CONVERT : public COMMAND +class PCB_CONVERT_COMMAND : public COMMAND { public: - COMMAND_PCB_CONVERT(); + PCB_CONVERT_COMMAND(); protected: int doPerform( KIWAY& aKiway ) override; diff --git a/kicad/cli/command_sch_convert.cpp b/kicad/cli/command_sch_convert.cpp index 3a4a88adf7..be38e2e844 100644 --- a/kicad/cli/command_sch_convert.cpp +++ b/kicad/cli/command_sch_convert.cpp @@ -23,7 +23,61 @@ */ #include "command_sch_convert.h" +#include "command_utils.h" -CLI::COMMAND_SCH_CONVERT::COMMAND_SCH_CONVERT() : COMMAND( "convert" ) +#include "jobs/job_sch_convert.h" + + +#include +#include "command_utils.h" +#include +#include +#include +#include +#include + +#include +#include + +#define ARG_FROM "--from" +#define ARG_TO "--to" + + +CLI::SCH_CONVERT_COMMAND::SCH_CONVERT_COMMAND() : COMMAND( "convert" ) { + addCommonArgs( true, true, false, false ); + addDefineArg(); + + m_argParser.add_description( UTF8STDSTR( + _( "Convert a vendor's schematic document to another vendor's schematic document" ) ) ); + + + m_argParser.add_argument( ARG_FROM ) + .default_value( std::string( "sch_altium" ) ) + .add_choices( enumChoices() ) + .metavar( "FROM" ) + .help( UTF8STDSTR( wxString::Format( _( "Accepted PCB format. Options: %s" ), + enumString() ) ) ); + + + m_argParser.add_argument( ARG_TO ) + .default_value( std::string( "sch_kicad" ) ) + .add_choices( enumChoices() ) + .metavar( "TO" ) + .help( UTF8STDSTR( wxString::Format( _( "Converted format. Options: %s" ), + enumString() ) ) ); +} + + +int CLI::SCH_CONVERT_COMMAND::doPerform( KIWAY& aKiway ) +{ + std::unique_ptr convertJob( new JOB_SCH_CONVERT( true ) ); + + convertJob->m_outputFile = m_argOutput; + convertJob->m_filename = m_argInput; + convertJob->SetVarOverrides( m_argDefineVars ); + getToEnum( m_argParser.get( ARG_FROM ), convertJob->m_from ); + getToEnum( m_argParser.get( ARG_TO ), convertJob->m_to ); + int exitCode = aKiway.ProcessJob( KIWAY::FACE_SCH, convertJob.get() ); + return exitCode; } diff --git a/kicad/cli/command_sch_convert.h b/kicad/cli/command_sch_convert.h index e09f20ce01..2ab9b79df9 100644 --- a/kicad/cli/command_sch_convert.h +++ b/kicad/cli/command_sch_convert.h @@ -30,12 +30,13 @@ namespace CLI { -class COMMAND_SCH_CONVERT : public COMMAND +class SCH_CONVERT_COMMAND : public COMMAND { public: - COMMAND_SCH_CONVERT(); + SCH_CONVERT_COMMAND(); -private: +protected: + int doPerform( KIWAY& aKiway ) override; }; } // namespace CLI diff --git a/kicad/cli/command_utils.h b/kicad/cli/command_utils.h new file mode 100644 index 0000000000..4ef65b2d38 --- /dev/null +++ b/kicad/cli/command_utils.h @@ -0,0 +1,94 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 Ethan Chien + * Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef COMMAND_UTILS_H +#define COMMAND_UTILS_H +#include +#include + +template +inline wxString enumString() +{ + wxString str; + auto names = magic_enum::enum_names(); + + for( size_t i = 0; i < names.size(); i++ ) + { + std::string name = { names[i].begin(), names[i].end() }; + + if( i > 0 ) + str << ", "; + + std::transform( name.begin(), name.end(), name.begin(), + []( unsigned char c ) + { + return std::tolower( c ); + } ); + + str << name; + } + + return str; +} + + +template +inline std::vector enumChoices() +{ + std::vector out; + + for( auto& strView : magic_enum::enum_names() ) + { + std::string name = { strView.begin(), strView.end() }; + + std::transform( name.begin(), name.end(), name.begin(), + []( unsigned char c ) + { + return std::tolower( c ); + } ); + + out.emplace_back( name ); + } + + return out; +} + + +template +inline bool getToEnum( const std::string& aInput, T& aOutput ) +{ + // If not specified, leave at default + if( aInput.empty() ) + return true; + + if( auto opt = magic_enum::enum_cast( aInput, magic_enum::case_insensitive ) ) + { + aOutput = *opt; + return true; + } + + return false; +} + +#endif diff --git a/kicad/kicad_cli.cpp b/kicad/kicad_cli.cpp index d0dedd0cb4..114e8b8e36 100644 --- a/kicad/kicad_cli.cpp +++ b/kicad/kicad_cli.cpp @@ -71,6 +71,7 @@ #include "cli/command_sch.h" #include "cli/command_sch_erc.h" #include "cli/command_sch_export.h" +#include "cli/command_sch_convert.h" #include "cli/command_sym.h" #include "cli/command_sym_export.h" #include "cli/command_sym_export_svg.h" @@ -109,7 +110,7 @@ struct COMMAND_ENTRY static CLI::PCB_COMMAND pcbCmd{}; static CLI::PCB_DRC_COMMAND pcbDrcCmd{}; static CLI::PCB_RENDER_COMMAND pcbRenderCmd{}; -static CLI::COMMAND_PCB_CONVERT pcbConvertCmd{}; +static CLI::PCB_CONVERT_COMMAND pcbConvertCmd{}; static CLI::PCB_EXPORT_DRILL_COMMAND exportPcbDrillCmd{}; static CLI::PCB_EXPORT_DXF_COMMAND exportPcbDxfCmd{}; static CLI::PCB_EXPORT_3D_COMMAND exportPcbGlbCmd{ "glb", UTF8STDSTR( _( "Export GLB (binary GLTF)" ) ), JOB_EXPORT_PCB_3D::FORMAT::GLB }; @@ -127,6 +128,7 @@ static CLI::PCB_EXPORT_COMMAND exportPcbCmd{}; static CLI::SCH_EXPORT_COMMAND exportSchCmd{}; static CLI::SCH_COMMAND schCmd{}; static CLI::SCH_ERC_COMMAND schErcCmd{}; +static CLI::SCH_CONVERT_COMMAND schConvertCmd{}; static CLI::SCH_EXPORT_BOM_COMMAND exportSchBomCmd{}; static CLI::SCH_EXPORT_PYTHONBOM_COMMAND exportSchPythonBomCmd{}; static CLI::SCH_EXPORT_NETLIST_COMMAND exportSchNetlistCmd{}; @@ -199,6 +201,9 @@ static std::vector commandStack = { { &schErcCmd }, + { + &schConvertCmd + }, { &exportSchCmd, { diff --git a/pcbnew/pcbnew_jobs_handler.cpp b/pcbnew/pcbnew_jobs_handler.cpp index 66d8b0aecc..d0fcfa32a5 100644 --- a/pcbnew/pcbnew_jobs_handler.cpp +++ b/pcbnew/pcbnew_jobs_handler.cpp @@ -1488,7 +1488,8 @@ int PCBNEW_JOBS_HANDLER::JobExportConvert( JOB* aJob ) return CLI::EXIT_CODES::ERR_UNKNOWN; } - m_reporter->Report( _( "Successfully convered board" ) + wxS( "\n" ), RPT_SEVERITY_INFO ); + m_reporter->Report( _( "Successfully converted board" ) + wxS( "\n" ), + RPT_SEVERITY_INFO ); return CLI::EXIT_CODES::OK; }