diff --git a/common/jobs/job_export_pcb_pos.h b/common/jobs/job_export_pcb_pos.h new file mode 100644 index 0000000000..4ca4f73dcc --- /dev/null +++ b/common/jobs/job_export_pcb_pos.h @@ -0,0 +1,78 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2022 Mark Roszko + * Copyright (C) 1992-2022 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 3 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, see . + */ + +#ifndef JOB_EXPORT_PCB_POS_H +#define JOB_EXPORT_PCB_POS_H + +#include +#include +#include "job.h" + +class JOB_EXPORT_PCB_POS : public JOB +{ +public: + JOB_EXPORT_PCB_POS( bool aIsCli ) : + JOB( "pos", aIsCli ), m_filename(), + m_outputFile(), + m_excludeFootprintsWithTh( true ), + m_useDrillPlaceFileOrigin( true ), + m_smdOnly( false ) + { + } + + wxString m_filename; + wxString m_outputFile; + + bool m_useDrillPlaceFileOrigin; + bool m_smdOnly; + bool m_excludeFootprintsWithTh; + bool m_negateBottomX; + + enum class SIDE + { + FRONT, + BACK, + BOTH + }; + + SIDE m_side; + + enum class UNITS + { + INCHES, + MILLIMETERS + }; + + UNITS m_units; + + + enum class FORMAT + { + ASCII, + CSV, + GERBER + }; + + FORMAT m_format; + + bool m_gerberBoardEdge; +}; + +#endif \ No newline at end of file diff --git a/kicad/CMakeLists.txt b/kicad/CMakeLists.txt index 561165b82d..6fe6d60211 100644 --- a/kicad/CMakeLists.txt +++ b/kicad/CMakeLists.txt @@ -21,6 +21,7 @@ set( KICAD_SRCS cli/command_export_pcb_dxf.cpp cli/command_export_pcb_gerber.cpp cli/command_export_pcb_pdf.cpp + cli/command_export_pcb_pos.cpp cli/command_export_pcb_step.cpp cli/command_export_pcb_svg.cpp cli/command_pcb.cpp diff --git a/kicad/cli/command_export_pcb_pos.cpp b/kicad/cli/command_export_pcb_pos.cpp new file mode 100644 index 0000000000..13b4ff28b9 --- /dev/null +++ b/kicad/cli/command_export_pcb_pos.cpp @@ -0,0 +1,172 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2022 Mark Roszko + * Copyright (C) 1992-2022 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 3 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, see . + */ + +#include "command_export_pcb_pos.h" +#include +#include "jobs/job_export_pcb_pos.h" +#include +#include +#include + +#include + +#include + +#define ARG_SIDE "--side" +#define ARG_FORMAT "--format" +#define ARG_UNITS "--units" +#define ARG_NEGATE_BOTTOM_X "--bottom-negate-x" +#define ARG_USE_DRILL_FILE_ORIGIN "--use-drill-file-origin" +#define ARG_SMD_ONLY "--smd-only" +#define ARG_EXCLUDE_FOOTPRINTS_TH "--exclude-fp-th" +#define ARG_GERBER_BOARD_EDGE "--gerber-board-edge" + + +CLI::EXPORT_PCB_POS_COMMAND::EXPORT_PCB_POS_COMMAND() : EXPORT_PCB_BASE_COMMAND( "pos" ) +{ + m_argParser.add_argument( ARG_SIDE ) + .default_value( std::string( "both" ) ) + .help( "valid options: front,back,both" ); + + m_argParser.add_argument( ARG_FORMAT ) + .default_value( std::string( "ascii" ) ) + .help( "valid options: ascii,csv,gerber" ); + + m_argParser.add_argument( ARG_UNITS ) + .default_value( std::string( "in" ) ) + .help( "output units, valid options are in or mm (ascii or csv only)" ); + + m_argParser.add_argument( ARG_NEGATE_BOTTOM_X ) + .help( "Use negative X coordinates for footprints on bottom layer (ascii or csv only)" ) + .implicit_value( true ) + .default_value( false ); + + m_argParser.add_argument( ARG_USE_DRILL_FILE_ORIGIN ) + .help( "Use drill/place file origin (ascii or csv only)" ) + .implicit_value( true ) + .default_value( false ); + + m_argParser.add_argument( ARG_SMD_ONLY ) + .help( "Include only SMD footprints (ascii or csv only)" ) + .implicit_value( true ) + .default_value( false ); + + m_argParser.add_argument( ARG_EXCLUDE_FOOTPRINTS_TH ) + .help( "Exclue all footprints with through-hole pads (ascii or csv only)" ) + .implicit_value( true ) + .default_value( false ); + + m_argParser.add_argument( ARG_GERBER_BOARD_EDGE ) + .help( "Include board edge layer (gerber only)" ) + .implicit_value( true ) + .default_value( false ); +} + + +int CLI::EXPORT_PCB_POS_COMMAND::Perform( KIWAY& aKiway ) +{ + int baseExit = EXPORT_PCB_BASE_COMMAND::Perform( aKiway ); + if( baseExit != EXIT_CODES::OK ) + return baseExit; + + std::unique_ptr aPosJob( new JOB_EXPORT_PCB_POS( true ) ); + + aPosJob->m_filename = FROM_UTF8( m_argParser.get( ARG_INPUT ).c_str() ); + aPosJob->m_outputFile = FROM_UTF8( m_argParser.get( ARG_OUTPUT ).c_str() ); + + if( !wxFile::Exists( aPosJob->m_filename ) ) + { + wxFprintf( stderr, _( "Board file does not exist or is not accessible\n" ) ); + return EXIT_CODES::ERR_INVALID_INPUT_FILE; + } + + aPosJob->m_negateBottomX = m_argParser.get( ARG_NEGATE_BOTTOM_X ); + aPosJob->m_smdOnly = m_argParser.get( ARG_SMD_ONLY ); + aPosJob->m_excludeFootprintsWithTh = m_argParser.get( ARG_EXCLUDE_FOOTPRINTS_TH ); + aPosJob->m_useDrillPlaceFileOrigin = m_argParser.get( ARG_USE_DRILL_FILE_ORIGIN ); + aPosJob->m_useDrillPlaceFileOrigin = m_argParser.get( ARG_GERBER_BOARD_EDGE ); + + wxString format = FROM_UTF8( m_argParser.get( ARG_FORMAT ).c_str() ); + if( format == wxS( "ascii" ) ) + { + aPosJob->m_format = JOB_EXPORT_PCB_POS::FORMAT::ASCII; + } + else if( format == wxS( "csv" ) ) + { + aPosJob->m_format = JOB_EXPORT_PCB_POS::FORMAT::CSV; + } + else if( format == wxS( "gerber" ) ) + { + aPosJob->m_format = JOB_EXPORT_PCB_POS::FORMAT::GERBER; + } + else + { + wxFprintf( stderr, _( "Invalid format\n" ) ); + return EXIT_CODES::ERR_ARGS; + } + + wxString units = FROM_UTF8( m_argParser.get( ARG_UNITS ).c_str() ); + + if( units == wxS( "mm" ) ) + { + aPosJob->m_units = JOB_EXPORT_PCB_POS::UNITS::MILLIMETERS; + } + else if( units == wxS( "in" ) ) + { + aPosJob->m_units = JOB_EXPORT_PCB_POS::UNITS::INCHES; + } + else + { + wxFprintf( stderr, _( "Invalid units specified\n" ) ); + return EXIT_CODES::ERR_ARGS; + } + + wxString side = FROM_UTF8( m_argParser.get( ARG_SIDE ).c_str() ); + + if( units == wxS( "both" ) ) + { + if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::GERBER ) + { + wxFprintf( stderr, _( "\"both\" not supported for gerber format\n" ) ); + return EXIT_CODES::ERR_ARGS; + } + + aPosJob->m_side = JOB_EXPORT_PCB_POS::SIDE::BOTH; + } + else if( units == wxS( "front" ) ) + { + aPosJob->m_side = JOB_EXPORT_PCB_POS::SIDE::FRONT; + } + else if( units == wxS( "back" ) ) + { + aPosJob->m_side = JOB_EXPORT_PCB_POS::SIDE::BACK; + } + else + { + wxFprintf( stderr, _( "Invalid side specified\n" ) ); + return EXIT_CODES::ERR_ARGS; + } + + + LOCALE_IO dummy; + int exitCode = aKiway.ProcessJob( KIWAY::FACE_PCB, aPosJob.get() ); + + return exitCode; +} \ No newline at end of file diff --git a/kicad/cli/command_export_pcb_pos.h b/kicad/cli/command_export_pcb_pos.h new file mode 100644 index 0000000000..a61afb394a --- /dev/null +++ b/kicad/cli/command_export_pcb_pos.h @@ -0,0 +1,37 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2022 Mark Roszko + * Copyright (C) 1992-2022 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 3 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, see . + */ + +#ifndef COMMAND_EXPORT_PCB_POS_H +#define COMMAND_EXPORT_PCB_POS_H + +#include "command_export_pcb_base.h" + +namespace CLI +{ +class EXPORT_PCB_POS_COMMAND : public EXPORT_PCB_BASE_COMMAND +{ +public: + EXPORT_PCB_POS_COMMAND(); + + int Perform( KIWAY& aKiway ) override; +}; +} // namespace CLI + +#endif \ No newline at end of file diff --git a/kicad/kicad_cli.cpp b/kicad/kicad_cli.cpp index 34a2a252f6..2ee5efcc08 100644 --- a/kicad/kicad_cli.cpp +++ b/kicad/kicad_cli.cpp @@ -52,6 +52,7 @@ #include "cli/command_export_pcb_dxf.h" #include "cli/command_export_pcb_gerber.h" #include "cli/command_export_pcb_pdf.h" +#include "cli/command_export_pcb_pos.h" #include "cli/command_export_pcb_svg.h" #include "cli/command_export_pcb_step.h" #include "cli/command_export_sch_pdf.h" @@ -110,6 +111,7 @@ static CLI::EXPORT_PCB_DXF_COMMAND exportPcbDxfCmd{}; static CLI::EXPORT_PCB_STEP_COMMAND exportPcbStepCmd{}; static CLI::EXPORT_PCB_SVG_COMMAND exportPcbSvgCmd{}; static CLI::EXPORT_PCB_PDF_COMMAND exportPcbPdfCmd{}; +static CLI::EXPORT_PCB_POS_COMMAND exportPcbPosCmd{}; static CLI::EXPORT_PCB_GERBER_COMMAND exportPcbGerberCmd{}; static CLI::EXPORT_PCB_COMMAND exportPcbCmd{}; static CLI::PCB_COMMAND pcbCmd{}; @@ -128,6 +130,7 @@ static std::vector commandStack = { &exportPcbDxfCmd, &exportPcbGerberCmd, &exportPcbPdfCmd, + &exportPcbPosCmd, &exportPcbStepCmd, &exportPcbSvgCmd } diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 87d7fa2e47..a069305cfa 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -224,7 +224,7 @@ set( PCBNEW_EXPORTERS exporters/export_gencad.cpp exporters/export_idf.cpp exporters/exporter_vrml.cpp - exporters/export_footprints_placefile.cpp + exporters/place_file_exporter.cpp exporters/gen_drill_report_files.cpp exporters/gendrill_Excellon_writer.cpp exporters/gendrill_file_writer_base.cpp diff --git a/pcbnew/dialogs/dialog_gen_footprint_position.cpp b/pcbnew/dialogs/dialog_gen_footprint_position.cpp index 48f5c37184..d60fa63a58 100644 --- a/pcbnew/dialogs/dialog_gen_footprint_position.cpp +++ b/pcbnew/dialogs/dialog_gen_footprint_position.cpp @@ -39,7 +39,7 @@ #include #include "widgets/wx_html_report_panel.h" #include -#include +#include #include "gerber_placefile_writer.h" #include diff --git a/pcbnew/exporters/export_footprints_placefile.cpp b/pcbnew/exporters/place_file_exporter.cpp similarity index 99% rename from pcbnew/exporters/export_footprints_placefile.cpp rename to pcbnew/exporters/place_file_exporter.cpp index a4d5ebc6f5..0a43fa9194 100644 --- a/pcbnew/exporters/export_footprints_placefile.cpp +++ b/pcbnew/exporters/place_file_exporter.cpp @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include diff --git a/pcbnew/exporters/export_footprints_placefile.h b/pcbnew/exporters/place_file_exporter.h similarity index 100% rename from pcbnew/exporters/export_footprints_placefile.h rename to pcbnew/exporters/place_file_exporter.h diff --git a/pcbnew/pcbnew_jobs_handler.cpp b/pcbnew/pcbnew_jobs_handler.cpp index d18469f58c..b8dffdff28 100644 --- a/pcbnew/pcbnew_jobs_handler.cpp +++ b/pcbnew/pcbnew_jobs_handler.cpp @@ -24,12 +24,15 @@ #include #include #include +#include #include #include #include #include #include #include +#include +#include "gerber_placefile_writer.h" #include #include #include @@ -38,6 +41,7 @@ #include #include #include +#include #include "pcbnew_scripting_helpers.h" @@ -368,5 +372,76 @@ int PCBNEW_JOBS_HANDLER::JobExportDrill( JOB* aJob ) aDrillJob->m_generateMap, nullptr ); } + return CLI::EXIT_CODES::OK; +} + + +int PCBNEW_JOBS_HANDLER::JobExportPos( JOB* aJob ) +{ + JOB_EXPORT_PCB_POS* aPosJob = dynamic_cast( aJob ); + + if( aPosJob == nullptr ) + return CLI::EXIT_CODES::ERR_UNKNOWN; + + if( aJob->IsCli() ) + wxPrintf( _( "Loading board\n" ) ); + + BOARD* brd = LoadBoard( aPosJob->m_filename ); + + if( aPosJob->m_outputFile.IsEmpty() ) + { + wxFileName fn = brd->GetFileName(); + fn.SetName( fn.GetName() ); + + if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::ASCII ) + fn.SetExt( FootprintPlaceFileExtension ); + else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::CSV ) + fn.SetExt( CsvFileExtension ); + else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::GERBER ) + fn.SetExt( GerberFileExtension ); + + aPosJob->m_outputFile = fn.GetFullName(); + } + + FILE* file = nullptr; + file = wxFopen( aPosJob->m_outputFile, wxS( "wt" ) ); + + if( file == nullptr ) + return CLI::EXIT_CODES::ERR_INVALID_OUTPUT_CONFLICT; + + if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::ASCII || aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::CSV ) + { + std::string data; + + bool frontSide = aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::FRONT + || aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH; + + bool backSide = aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BACK + || aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH; + + PLACE_FILE_EXPORTER exporter( brd, aPosJob->m_units == JOB_EXPORT_PCB_POS::UNITS::MILLIMETERS, + aPosJob->m_smdOnly, aPosJob->m_excludeFootprintsWithTh, + frontSide, backSide, + aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::CSV, + aPosJob->m_useDrillPlaceFileOrigin, + aPosJob->m_negateBottomX ); + data = exporter.GenPositionData(); + + fputs( data.c_str(), file ); + fclose( file ); + } + else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::GERBER ) + { + PLACEFILE_GERBER_WRITER exporter( brd ); + + PCB_LAYER_ID gbrLayer; + if( aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::FRONT ) + gbrLayer = F_Cu; + else if( aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BACK ) + gbrLayer = B_Cu; + + exporter.CreatePlaceFile( aPosJob->m_outputFile, gbrLayer, aPosJob->m_gerberBoardEdge ); + } + return CLI::EXIT_CODES::OK; } \ No newline at end of file diff --git a/pcbnew/pcbnew_jobs_handler.h b/pcbnew/pcbnew_jobs_handler.h index 2c4aecf3e2..6af19b4afe 100644 --- a/pcbnew/pcbnew_jobs_handler.h +++ b/pcbnew/pcbnew_jobs_handler.h @@ -33,6 +33,7 @@ public: int JobExportPdf( JOB* aJob ); int JobExportGerber( JOB* aJob ); int JobExportDrill( JOB* aJob ); + int JobExportPos( JOB* aJob ); }; #endif \ No newline at end of file diff --git a/pcbnew/python/swig/pcbnew.i b/pcbnew/python/swig/pcbnew.i index cd7f468f86..33f02893fe 100644 --- a/pcbnew/python/swig/pcbnew.i +++ b/pcbnew/python/swig/pcbnew.i @@ -70,7 +70,7 @@ class BASE_SET {}; #include #include #include -#include +#include #include #include #include @@ -115,7 +115,7 @@ HANDLE_EXCEPTIONS(PLUGIN::FootprintDelete) %include %include %include -%include +%include %include %include %include