From 50164e996870166aafd7e23e960196cf417fe739 Mon Sep 17 00:00:00 2001 From: jean-pierre charras <jp.charras@wanadoo.fr> Date: Sat, 19 Aug 2017 18:28:11 +0200 Subject: [PATCH] Add Gerber job file writer in Pcbnew, and a basic reader in Gerbview. Currently disabled Fix also very minor issues in Gerbview --- bitmaps_png/CMakeLists.txt | 1 + bitmaps_png/cpp_26/gerber_job_file.cpp | 146 ++++ bitmaps_png/sources/gerber_job_file.svg | 818 +++++++++++++++++++++ common/gbr_metadata.cpp | 35 + common/pcb_plot_params.keywords | 1 + common/wildcards_and_files_ext.cpp | 3 +- gerbview/CMakeLists.txt | 2 +- gerbview/events_called_functions.cpp | 4 + gerbview/files.cpp | 18 + gerbview/gerbview_config.cpp | 4 - gerbview/gerbview_frame.cpp | 17 +- gerbview/gerbview_frame.h | 20 + gerbview/gerbview_id.h | 15 +- gerbview/job_file_reader.cpp | 245 ++++++ gerbview/menubar.cpp | 81 +- gerbview/readgerb.cpp | 10 +- include/bitmaps.h | 1 + include/plot_auxiliary_data.h | 9 + include/wildcards_and_files_ext.h | 1 + kicad/tree_project_frame.cpp | 12 +- pcbnew/CMakeLists.txt | 1 + pcbnew/dialogs/dialog_plot.cpp | 37 +- pcbnew/dialogs/dialog_plot_base.cpp | 7 +- pcbnew/dialogs/dialog_plot_base.fbp | 88 +++ pcbnew/dialogs/dialog_plot_base.h | 3 +- pcbnew/exporters/gerber_jobfile_writer.cpp | 388 ++++++++++ pcbnew/exporters/gerber_jobfile_writer.h | 125 ++++ pcbnew/pcb_plot_params.cpp | 18 +- pcbnew/pcb_plot_params.h | 6 + pcbnew/pcbplot.cpp | 96 +++ 30 files changed, 2134 insertions(+), 78 deletions(-) create mode 100644 bitmaps_png/cpp_26/gerber_job_file.cpp create mode 100644 bitmaps_png/sources/gerber_job_file.svg create mode 100644 gerbview/job_file_reader.cpp create mode 100644 pcbnew/exporters/gerber_jobfile_writer.cpp create mode 100644 pcbnew/exporters/gerber_jobfile_writer.h diff --git a/bitmaps_png/CMakeLists.txt b/bitmaps_png/CMakeLists.txt index 40003dcccc..a646f19eee 100644 --- a/bitmaps_png/CMakeLists.txt +++ b/bitmaps_png/CMakeLists.txt @@ -238,6 +238,7 @@ set( BMAPS_MID gbr_select_mode1 gbr_select_mode2 gerber_file + gerber_job_file gerbview_show_negative_objects gerbview_drill_file gerbview_clear_layers diff --git a/bitmaps_png/cpp_26/gerber_job_file.cpp b/bitmaps_png/cpp_26/gerber_job_file.cpp new file mode 100644 index 0000000000..c63a07c7eb --- /dev/null +++ b/bitmaps_png/cpp_26/gerber_job_file.cpp @@ -0,0 +1,146 @@ + +/* Do not modify this file, it was automatically generated by the + * PNG2cpp CMake script, using a *.png file as input. + */ + +#include <bitmaps.h> + +static const unsigned char png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1a, 0x08, 0x06, 0x00, 0x00, 0x00, 0xa9, 0x4a, 0x4c, + 0xce, 0x00, 0x00, 0x08, 0x14, 0x49, 0x44, 0x41, 0x54, 0x48, 0xc7, 0xad, 0x56, 0x69, 0x6c, 0x53, + 0xe9, 0x15, 0x35, 0x23, 0xa6, 0xaa, 0xda, 0x8a, 0xf9, 0x53, 0xca, 0x08, 0x5a, 0x44, 0x01, 0x01, + 0x1a, 0x60, 0x40, 0x45, 0x2c, 0x65, 0xdf, 0x09, 0x61, 0x11, 0xbb, 0x10, 0xc3, 0xbe, 0xa9, 0x02, + 0x04, 0xc3, 0x0f, 0x98, 0x16, 0x04, 0x65, 0x08, 0x59, 0x86, 0x84, 0x6c, 0x10, 0xb2, 0x2f, 0x64, + 0x71, 0x20, 0x21, 0x8b, 0x1d, 0x12, 0x48, 0x1c, 0x27, 0x71, 0x56, 0xc7, 0xf6, 0xb3, 0x1d, 0xe3, + 0x2d, 0x89, 0x63, 0x27, 0x4e, 0xf2, 0xfc, 0xbc, 0xc7, 0x8e, 0xf7, 0xed, 0xf6, 0x1a, 0x01, 0x22, + 0x4c, 0xa7, 0x6a, 0xa5, 0x3e, 0xe9, 0xca, 0x7e, 0xcf, 0xcf, 0xf7, 0x7c, 0xf7, 0xdc, 0xf3, 0x9d, + 0xfb, 0xd1, 0x68, 0x9f, 0x5d, 0xa7, 0x4f, 0x9f, 0x3e, 0x7c, 0xee, 0xdc, 0xb9, 0x98, 0x43, 0x87, + 0x0e, 0xed, 0xde, 0xb3, 0x67, 0xcf, 0xef, 0xc3, 0xcf, 0x2e, 0x5e, 0xbc, 0xf8, 0xe5, 0xb1, 0x63, + 0xc7, 0xfe, 0x79, 0xf8, 0xf0, 0xe1, 0x5d, 0x78, 0x3b, 0x89, 0xf6, 0xff, 0xb8, 0xb2, 0xb3, 0xb3, + 0xe9, 0x81, 0x40, 0xe0, 0xe5, 0xd0, 0xd0, 0x10, 0x83, 0xcd, 0x66, 0x33, 0x93, 0x92, 0x92, 0xe8, + 0x17, 0x2e, 0x5c, 0x28, 0x2b, 0x2d, 0x2d, 0x65, 0x0b, 0x44, 0xe2, 0xa6, 0x2a, 0x76, 0x87, 0x92, + 0x23, 0xe9, 0x1f, 0xe0, 0xf6, 0x0e, 0xa9, 0xdb, 0xa4, 0x1a, 0x2e, 0x5b, 0xa4, 0xbe, 0xdd, 0xd3, + 0xd3, 0xf3, 0xdb, 0xff, 0x09, 0x64, 0xdb, 0xb6, 0x6d, 0xd3, 0x3b, 0x3b, 0x3b, 0xab, 0x83, 0xc1, + 0x60, 0xf4, 0xa9, 0x53, 0xa7, 0xca, 0x32, 0x32, 0x32, 0xf2, 0x48, 0x92, 0xcc, 0x31, 0x1a, 0x8d, + 0x5c, 0xa2, 0x4f, 0x63, 0x6d, 0x93, 0x0f, 0x07, 0x98, 0x6f, 0x8d, 0xde, 0x8c, 0x36, 0xd2, 0xf9, + 0x53, 0x9d, 0xca, 0x92, 0xd6, 0xae, 0xeb, 0xaf, 0x14, 0x92, 0x64, 0x13, 0xa1, 0xb4, 0xd6, 0x75, + 0x29, 0xa2, 0xff, 0x6b, 0xa0, 0x03, 0x07, 0x0e, 0xec, 0x1d, 0x1e, 0x1e, 0xae, 0x1c, 0x1b, 0x1b, + 0x8b, 0xb9, 0x73, 0xe7, 0xce, 0xb3, 0xb8, 0xb8, 0xb8, 0xbc, 0xe3, 0xc7, 0x8f, 0xb3, 0x1b, 0xba, + 0x04, 0xae, 0x57, 0x52, 0x8b, 0xb7, 0x90, 0xb0, 0x8e, 0xd1, 0x25, 0xe3, 0x26, 0x46, 0x9f, 0xcf, + 0x58, 0xdb, 0xe7, 0x35, 0x57, 0x4a, 0xac, 0xa6, 0xd4, 0x86, 0xbe, 0xd1, 0x18, 0xc6, 0x5b, 0x75, + 0x45, 0xbb, 0x72, 0xbc, 0xec, 0x4d, 0x47, 0xdb, 0x2f, 0x52, 0x8b, 0x2b, 0xdf, 0x8e, 0x91, 0x18, + 0x8e, 0x13, 0x27, 0x4e, 0xbc, 0x8e, 0x8d, 0x8d, 0x6d, 0xbd, 0x7c, 0xf9, 0x72, 0xd3, 0xc6, 0x8d, + 0x1b, 0x85, 0x5b, 0xb7, 0x6e, 0x25, 0x52, 0xb2, 0x0a, 0x8c, 0x15, 0xbc, 0x41, 0x7f, 0x42, 0x5d, + 0xaf, 0x35, 0xea, 0x25, 0xdf, 0x9a, 0x58, 0x27, 0x37, 0xff, 0x54, 0xc9, 0x33, 0x3d, 0xae, 0x93, + 0x18, 0x32, 0x58, 0x32, 0x7d, 0x26, 0x4b, 0x66, 0xcc, 0x6e, 0x56, 0x19, 0xca, 0xc5, 0x66, 0xaa, + 0xba, 0x43, 0xea, 0x2d, 0x78, 0x51, 0x23, 0x39, 0x72, 0xe4, 0xc8, 0x8e, 0x9f, 0x01, 0x61, 0xe2, + 0x4c, 0x00, 0x60, 0x62, 0x54, 0xda, 0x6c, 0xb6, 0x2e, 0xfc, 0xec, 0xd4, 0xe9, 0x74, 0x3c, 0xb9, + 0x5c, 0x2e, 0x92, 0xc9, 0x64, 0xe2, 0x66, 0x81, 0xd4, 0x5f, 0x22, 0xf7, 0xdb, 0x6a, 0x94, 0x4e, + 0xf3, 0x2b, 0xac, 0xe2, 0x75, 0xaf, 0xd3, 0xd0, 0xa2, 0xf1, 0xe8, 0x39, 0x6a, 0x97, 0xbe, 0x93, + 0x0c, 0x91, 0xdd, 0x64, 0x80, 0x2a, 0x69, 0x55, 0x91, 0xcd, 0x1a, 0x2f, 0xc9, 0x90, 0x98, 0xf5, + 0x95, 0xac, 0x0e, 0x1f, 0xb2, 0x70, 0xeb, 0x67, 0x40, 0x8f, 0x1e, 0x3d, 0xca, 0xc2, 0xe4, 0x65, + 0x7c, 0x3e, 0xbf, 0xbe, 0xb2, 0xb2, 0x92, 0xa8, 0xa9, 0xa9, 0xe1, 0x15, 0x15, 0x15, 0x09, 0xbb, + 0xbb, 0xbb, 0x45, 0x95, 0xd5, 0x0c, 0x55, 0x0d, 0x5f, 0xe5, 0xa7, 0xf7, 0xd8, 0xcd, 0xa5, 0x7c, + 0xca, 0xdc, 0xa8, 0x72, 0x53, 0x6f, 0x14, 0x76, 0xea, 0xf5, 0x5b, 0xa3, 0xbe, 0x51, 0x6e, 0xa6, + 0x08, 0x0a, 0x46, 0xba, 0x87, 0xdd, 0xba, 0xf2, 0x2e, 0xd5, 0x28, 0xbb, 0x6f, 0x4c, 0xc5, 0xd5, + 0x81, 0xb6, 0x8a, 0x23, 0xf1, 0xfe, 0x18, 0x9b, 0x28, 0xde, 0xbb, 0x77, 0xef, 0xa6, 0x7f, 0x0b, + 0xd4, 0xda, 0xda, 0xda, 0x5c, 0x5c, 0x5c, 0x4c, 0x60, 0x08, 0x58, 0x2c, 0x16, 0x91, 0x9f, 0x9f, + 0x2f, 0x62, 0xd6, 0xb1, 0x46, 0x2a, 0xb8, 0x6a, 0x1f, 0x5d, 0x64, 0x35, 0x96, 0xf0, 0x74, 0x06, + 0xa6, 0x58, 0xa7, 0x67, 0xf7, 0xda, 0x75, 0x0c, 0x62, 0x84, 0xac, 0x97, 0x19, 0x48, 0x99, 0x09, + 0x74, 0xfc, 0x21, 0x87, 0xae, 0x49, 0x4a, 0x92, 0xcd, 0x32, 0x72, 0x58, 0x6e, 0x01, 0x75, 0x6d, + 0x97, 0xd2, 0x51, 0xf5, 0x8a, 0x33, 0x24, 0x91, 0x48, 0x18, 0x97, 0x2e, 0x5d, 0xca, 0xda, 0xbe, + 0x7d, 0xfb, 0x82, 0x09, 0x40, 0x74, 0x3a, 0xbd, 0xfb, 0xc1, 0x83, 0x07, 0xa2, 0x70, 0x24, 0x24, + 0x24, 0x88, 0x1a, 0x1a, 0x1a, 0x44, 0x79, 0x05, 0x25, 0x5a, 0x46, 0xb7, 0xca, 0x97, 0xcd, 0x19, + 0x34, 0xbe, 0xe9, 0x75, 0xea, 0x0b, 0x5b, 0x94, 0x64, 0xe7, 0xa0, 0x83, 0x6a, 0x94, 0x51, 0xba, + 0x6e, 0xb5, 0xd5, 0xa0, 0xb2, 0x81, 0x4e, 0x42, 0x3a, 0x0c, 0xbc, 0x7e, 0xca, 0xc0, 0x57, 0xe9, + 0x75, 0xda, 0x71, 0x18, 0xae, 0xe7, 0xca, 0xc6, 0x53, 0x33, 0x8a, 0x75, 0x98, 0x33, 0xce, 0xeb, + 0xf5, 0xd2, 0x1b, 0x1b, 0x1b, 0xab, 0x4e, 0x9e, 0x3c, 0x79, 0xe5, 0x53, 0x20, 0xfe, 0x07, 0xa0, + 0x70, 0x20, 0x8d, 0xa2, 0xec, 0xec, 0x5c, 0x45, 0x75, 0x13, 0xdf, 0x97, 0xdf, 0xa1, 0x35, 0xd7, + 0xf7, 0xda, 0xf5, 0xc5, 0x2d, 0x0a, 0xb2, 0xb5, 0xcf, 0x4a, 0xb2, 0x24, 0x5a, 0xaa, 0x67, 0xc4, + 0xae, 0x1f, 0x1a, 0x0b, 0x18, 0x35, 0x66, 0xb7, 0x49, 0xaa, 0x35, 0x99, 0xe5, 0xc3, 0x46, 0xa3, + 0xc1, 0x05, 0xd4, 0xab, 0x66, 0x9e, 0x3b, 0x25, 0xed, 0x99, 0x02, 0x73, 0x46, 0x85, 0x03, 0xf7, + 0x24, 0xfd, 0xea, 0xd5, 0xab, 0xc9, 0x1f, 0x81, 0x9e, 0x3f, 0x7f, 0x4e, 0x7c, 0x0e, 0x54, 0x52, + 0x52, 0xd2, 0x53, 0x5a, 0xd1, 0xe0, 0x2e, 0xe7, 0x0e, 0x39, 0x9b, 0x07, 0xdc, 0x86, 0x12, 0x8e, + 0x9c, 0xec, 0xa1, 0x3c, 0x54, 0xbb, 0x7c, 0xc4, 0x20, 0x1f, 0xb5, 0x99, 0x06, 0x4d, 0x4e, 0xcb, + 0x88, 0xd5, 0x65, 0xd5, 0xe8, 0xad, 0x63, 0xa4, 0xcd, 0x65, 0x32, 0x3a, 0xfd, 0x96, 0x82, 0x12, + 0x86, 0x5f, 0x22, 0x51, 0x64, 0xbd, 0x07, 0x8a, 0xc3, 0x5e, 0x57, 0xef, 0xda, 0xb5, 0x6b, 0x19, + 0x2d, 0x3e, 0x3e, 0x3e, 0x0b, 0x4b, 0xac, 0x2a, 0x2b, 0x2b, 0x9b, 0x00, 0x84, 0x96, 0x43, 0xae, + 0x58, 0xb1, 0xc2, 0xbb, 0x62, 0xc5, 0x4a, 0x77, 0xe1, 0xcb, 0x06, 0x5f, 0x39, 0x31, 0x6c, 0x29, + 0x66, 0xf7, 0x50, 0xe8, 0x04, 0x86, 0x16, 0x91, 0xca, 0x24, 0xd7, 0x9a, 0x2c, 0xc3, 0x16, 0xa7, + 0x8d, 0xb2, 0x7b, 0xc6, 0x47, 0x4c, 0x63, 0x0e, 0x9b, 0x2f, 0x64, 0x15, 0x2a, 0x06, 0x3c, 0x09, + 0x49, 0xd9, 0xf6, 0x4f, 0xaa, 0x29, 0xba, 0x76, 0xed, 0xda, 0xd3, 0x77, 0x3d, 0x0a, 0x03, 0x8d, + 0x8f, 0x8f, 0xbf, 0x89, 0x89, 0x89, 0x21, 0x66, 0xce, 0x9c, 0xa9, 0x99, 0x3a, 0x75, 0xaa, 0x68, + 0xfa, 0xf4, 0xe9, 0xa2, 0xc5, 0x8b, 0x17, 0xdb, 0x9b, 0x9a, 0x9a, 0x60, 0xf7, 0xee, 0xdd, 0xde, + 0xb8, 0xf8, 0x64, 0xb2, 0x94, 0xc9, 0xf1, 0xde, 0x4f, 0xcd, 0x77, 0x70, 0x7a, 0x06, 0xcc, 0xdd, + 0x0a, 0xad, 0x59, 0x3e, 0xa8, 0x1f, 0x1b, 0x35, 0xdb, 0xc7, 0xcd, 0x2e, 0xaf, 0x53, 0x6f, 0x73, + 0xb8, 0x65, 0xaa, 0x41, 0x5f, 0x52, 0x72, 0x6e, 0x40, 0x2e, 0x55, 0x3c, 0xf9, 0x50, 0x0d, 0x97, + 0xcb, 0xad, 0xde, 0xb1, 0x63, 0xc7, 0x5f, 0x3e, 0x02, 0xa1, 0xaf, 0xb1, 0x30, 0xb1, 0x75, 0xe7, + 0xce, 0x9d, 0xa1, 0x69, 0xd3, 0xa6, 0x39, 0x10, 0xcc, 0xba, 0x7a, 0xf5, 0x6a, 0xbf, 0x42, 0xa1, + 0x80, 0x1b, 0x37, 0x6e, 0x04, 0x67, 0xcd, 0x9a, 0xe5, 0x8a, 0x88, 0x88, 0x74, 0x1d, 0x3f, 0x7e, + 0x22, 0xb4, 0x71, 0xd3, 0xe6, 0x50, 0x15, 0xab, 0xdd, 0xd5, 0x37, 0xa2, 0xc7, 0x4a, 0x6c, 0xce, + 0x1e, 0xa5, 0xda, 0xf7, 0xa2, 0xe2, 0x75, 0x30, 0x39, 0x29, 0x27, 0xf0, 0x30, 0x3e, 0xd5, 0xfa, + 0x69, 0x35, 0x57, 0xae, 0x5c, 0x49, 0xfb, 0x28, 0xef, 0x30, 0xd0, 0xe8, 0xe8, 0x28, 0x67, 0xc1, + 0x82, 0x05, 0x4e, 0x14, 0x04, 0xe4, 0xe5, 0xe5, 0x41, 0x6e, 0x6e, 0x2e, 0xf4, 0xf7, 0xf7, 0x83, + 0xd9, 0x6c, 0x06, 0xac, 0x16, 0x04, 0x02, 0x01, 0x20, 0xb5, 0xa0, 0x56, 0xab, 0x61, 0xeb, 0xd6, + 0x6d, 0x81, 0x9b, 0x3f, 0x44, 0xd9, 0x1f, 0x26, 0x64, 0xb9, 0x1f, 0x25, 0xe6, 0xba, 0xd3, 0x9e, + 0x3e, 0x73, 0x77, 0xf0, 0x44, 0xa1, 0x86, 0xa6, 0x8e, 0xe0, 0xcd, 0xbf, 0xff, 0x68, 0x44, 0x9f, + 0xfc, 0xb4, 0x9a, 0x25, 0x1f, 0x81, 0xd0, 0xcf, 0x72, 0x4c, 0x26, 0x53, 0xe7, 0xe6, 0xcd, 0x9b, + 0x25, 0x68, 0x3b, 0x01, 0x8d, 0x46, 0x03, 0x14, 0x45, 0x01, 0x1a, 0x29, 0x84, 0x2b, 0x0a, 0x7f, + 0x47, 0xef, 0x03, 0x7c, 0x07, 0xf0, 0x5d, 0x38, 0x7a, 0xf4, 0x28, 0x85, 0x8e, 0x21, 0x40, 0xaa, + 0x45, 0xa9, 0xa9, 0xa9, 0x04, 0x93, 0x59, 0xab, 0x2c, 0x2a, 0x29, 0x1f, 0x7b, 0xdb, 0xd7, 0x0f, + 0x8f, 0xd3, 0x0a, 0xfc, 0xaf, 0xd3, 0x4e, 0x6a, 0x2c, 0xfc, 0x64, 0xce, 0x84, 0x6a, 0xc2, 0x57, + 0x54, 0x54, 0xd4, 0x73, 0xa7, 0xd3, 0xd9, 0xb5, 0x72, 0xe5, 0xca, 0x91, 0x87, 0x0f, 0x1f, 0x86, + 0xc2, 0x00, 0x62, 0xb1, 0x18, 0xd6, 0xac, 0x59, 0xe3, 0x5b, 0xb6, 0x6c, 0xd9, 0xf8, 0xaa, 0x55, + 0xab, 0x3c, 0x4f, 0x9f, 0x3e, 0x0d, 0xa2, 0x2d, 0x41, 0x73, 0x73, 0x33, 0xe0, 0xbd, 0xf3, 0xc9, + 0x93, 0x27, 0x02, 0x9c, 0x59, 0x42, 0x1c, 0x21, 0x04, 0x2e, 0xa4, 0xbb, 0xae, 0xae, 0x8e, 0x68, + 0x62, 0xa4, 0x85, 0x94, 0xa5, 0x11, 0x60, 0xab, 0x58, 0x0c, 0xaa, 0xb8, 0x5f, 0x05, 0xff, 0x76, + 0x60, 0xe9, 0x9a, 0x09, 0x40, 0xfb, 0xf6, 0xed, 0x93, 0x61, 0x35, 0x2e, 0x4c, 0xec, 0x57, 0x2a, + 0x95, 0xe0, 0x72, 0xb9, 0x00, 0x4d, 0xd1, 0x3f, 0x7f, 0xfe, 0x7c, 0xf9, 0xd2, 0xa5, 0x4b, 0x85, + 0x6d, 0x6d, 0x6d, 0xc4, 0xdc, 0xb9, 0x73, 0xdd, 0x58, 0x05, 0xa0, 0xff, 0xc1, 0xf5, 0xeb, 0xd7, + 0x43, 0xcb, 0x97, 0x2f, 0xf7, 0xcd, 0x9e, 0x3d, 0xdb, 0x81, 0x8b, 0x14, 0x22, 0xbd, 0xbc, 0x97, + 0x39, 0x51, 0x7d, 0x03, 0xa5, 0xab, 0x01, 0x82, 0x1e, 0x00, 0xe9, 0x35, 0xb0, 0xe7, 0xff, 0x11, + 0xa4, 0xb1, 0xb4, 0xec, 0x09, 0x40, 0x6b, 0xd7, 0xae, 0xa5, 0x6a, 0x6b, 0x6b, 0x01, 0xfb, 0x04, + 0x1e, 0x8f, 0x07, 0x1c, 0x0e, 0x07, 0x60, 0x75, 0x5e, 0x4c, 0x26, 0x8c, 0x88, 0x88, 0x20, 0xec, + 0x76, 0x7b, 0x07, 0x82, 0x5a, 0x98, 0x4c, 0xe6, 0xbb, 0x5e, 0x85, 0xdf, 0xcd, 0xca, 0xca, 0x82, + 0x6f, 0xbe, 0xf9, 0xc6, 0x8b, 0xcf, 0x78, 0xb8, 0x10, 0x11, 0x83, 0xc1, 0x10, 0x97, 0xdd, 0xfa, + 0xf3, 0xb8, 0x47, 0x5d, 0x04, 0x60, 0xe6, 0x40, 0x80, 0xb3, 0x0d, 0xb4, 0xb1, 0x5f, 0x84, 0x88, + 0x68, 0xda, 0xb7, 0x1f, 0x81, 0x70, 0xbf, 0xb0, 0xb6, 0x6c, 0xd9, 0x62, 0x42, 0x9a, 0x7c, 0x2a, + 0x95, 0x0a, 0xac, 0x56, 0x2b, 0xe0, 0x38, 0x0f, 0xe0, 0x6c, 0xea, 0xc7, 0x7d, 0x24, 0x44, 0xfb, + 0x10, 0x63, 0x52, 0x0f, 0x87, 0xc3, 0x81, 0x96, 0x96, 0x16, 0xd8, 0xb0, 0x61, 0x83, 0x7f, 0xde, + 0xbc, 0x79, 0x36, 0x64, 0x60, 0xf4, 0xe0, 0xc1, 0x83, 0xc2, 0xfa, 0xfa, 0x7a, 0x02, 0xed, 0x4a, + 0x78, 0xff, 0xf6, 0xf7, 0x75, 0x8a, 0xdc, 0x45, 0x81, 0xa0, 0x9b, 0x04, 0x50, 0xc5, 0x83, 0xbb, + 0x7c, 0x21, 0x48, 0xee, 0xd1, 0xe4, 0x00, 0xef, 0xe7, 0x13, 0x36, 0x38, 0xbc, 0x8b, 0x33, 0xce, + 0x9c, 0x39, 0xd3, 0x9a, 0x98, 0x98, 0x18, 0xd4, 0xeb, 0xf5, 0x20, 0x95, 0x4a, 0x01, 0xa5, 0xee, + 0xc3, 0x7e, 0x38, 0xc2, 0xbd, 0x4a, 0x49, 0x49, 0x81, 0xf0, 0x9e, 0x42, 0xa3, 0x85, 0x25, 0x4b, + 0x96, 0x38, 0xb0, 0x02, 0x1e, 0x3a, 0x07, 0x0f, 0x9d, 0x83, 0x87, 0x63, 0x9c, 0x8f, 0x3d, 0x12, + 0xa2, 0x29, 0xa7, 0x97, 0x3e, 0x88, 0xec, 0xb3, 0x70, 0x6f, 0x02, 0x38, 0x07, 0x00, 0x04, 0x87, + 0xc0, 0x90, 0x32, 0x05, 0xba, 0xee, 0xd0, 0x4e, 0x4f, 0x00, 0xc2, 0x86, 0x17, 0x44, 0x46, 0x46, + 0x7a, 0x70, 0x4f, 0xbd, 0x93, 0x71, 0xb8, 0x27, 0x38, 0xd6, 0xa1, 0xbd, 0xbd, 0x1d, 0xd0, 0xcd, + 0x21, 0x4c, 0x1d, 0xbe, 0x03, 0x48, 0xa9, 0x13, 0xcf, 0x15, 0x44, 0x41, 0x41, 0x01, 0x51, 0x58, + 0x58, 0x48, 0x68, 0xb5, 0x5a, 0x1e, 0xfe, 0x46, 0xa0, 0x88, 0xe8, 0xdf, 0x7d, 0x77, 0x2c, 0xbf, + 0xe5, 0xfe, 0x57, 0x5a, 0xbf, 0xb1, 0x13, 0x60, 0x94, 0x0e, 0xbe, 0xba, 0x55, 0xf0, 0xf6, 0xee, + 0x24, 0x27, 0xeb, 0x07, 0xda, 0x57, 0x34, 0xb4, 0x9b, 0x4c, 0xbf, 0xdf, 0x5f, 0x8e, 0x94, 0x58, + 0x90, 0x82, 0x77, 0xc9, 0xd2, 0xd3, 0xd3, 0xdf, 0xd1, 0x14, 0xa6, 0x0b, 0x57, 0x0b, 0x99, 0x99, + 0x99, 0x80, 0x54, 0x06, 0xd2, 0xd2, 0xd2, 0xe0, 0xec, 0xd9, 0xb3, 0xc1, 0xe8, 0xe8, 0xe8, 0x21, + 0xac, 0x9c, 0x8b, 0x63, 0x9f, 0x87, 0xbd, 0x25, 0x5e, 0xbc, 0x78, 0x21, 0x08, 0x1f, 0x64, 0xd6, + 0xad, 0x5b, 0xf7, 0xed, 0x95, 0xcd, 0xb4, 0xc3, 0x83, 0xd5, 0x91, 0x21, 0x08, 0x7a, 0x51, 0x18, + 0xdf, 0x03, 0x95, 0xfe, 0x35, 0xd4, 0xdc, 0x9c, 0xf2, 0x88, 0x86, 0x0a, 0xdb, 0x87, 0x52, 0x4d, + 0x43, 0x85, 0xa9, 0x71, 0x74, 0x7b, 0x17, 0x2e, 0x5c, 0x38, 0xb8, 0x68, 0xd1, 0x22, 0x35, 0x86, + 0x2b, 0x27, 0x27, 0x07, 0xce, 0x9f, 0x3f, 0x1f, 0x98, 0x33, 0x67, 0x8e, 0x09, 0x05, 0xc2, 0x42, + 0xf5, 0x99, 0x71, 0x63, 0xdb, 0xf7, 0xef, 0xdf, 0xcf, 0x46, 0x47, 0xee, 0x42, 0xd5, 0xb5, 0xdf, + 0xbd, 0x7b, 0xb7, 0x11, 0x29, 0x6f, 0xc4, 0x93, 0xd2, 0x87, 0x7d, 0xf3, 0x1b, 0xfa, 0xa5, 0x49, + 0x0d, 0x63, 0x92, 0xc7, 0x20, 0x29, 0x3f, 0x0f, 0x65, 0x09, 0x27, 0xe1, 0xf6, 0x3f, 0x6e, 0x5e, + 0xfd, 0x54, 0x80, 0x93, 0x26, 0x4f, 0x9e, 0xfc, 0xd7, 0x0f, 0x37, 0x33, 0x66, 0xcc, 0xb8, 0x8f, + 0x49, 0x00, 0x55, 0xa9, 0xc3, 0xdb, 0xdf, 0xbd, 0x7f, 0xfc, 0x25, 0xc6, 0xb4, 0xf0, 0x17, 0xa4, + 0xf0, 0x4f, 0x28, 0xa4, 0x64, 0xec, 0x4d, 0x35, 0x0a, 0xa2, 0x6a, 0xfd, 0xfa, 0xf5, 0x8b, 0x3f, + 0xfc, 0x37, 0x72, 0x21, 0x6d, 0x69, 0xc1, 0xad, 0x4d, 0xdd, 0xed, 0x1d, 0x1c, 0x6f, 0x7a, 0x46, + 0xde, 0xc8, 0xbd, 0x7b, 0xf7, 0xa6, 0xfc, 0xe2, 0x89, 0x08, 0x41, 0xd7, 0xa1, 0xc9, 0x92, 0x68, + 0xb0, 0xe2, 0xff, 0x74, 0x72, 0xc2, 0x85, 0x2c, 0x41, 0xe1, 0xec, 0xfb, 0xec, 0xf1, 0x17, 0x18, + 0xbf, 0xc6, 0xf8, 0xc3, 0xfb, 0x4f, 0xda, 0xbf, 0x00, 0xbc, 0x29, 0xf9, 0xf3, 0xe7, 0x0e, 0xc6, + 0x86, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, +}; + +const BITMAP_OPAQUE gerber_job_file_xpm[1] = {{ png, sizeof( png ), "gerber_job_file_xpm" }}; + +//EOF diff --git a/bitmaps_png/sources/gerber_job_file.svg b/bitmaps_png/sources/gerber_job_file.svg new file mode 100644 index 0000000000..3694a87463 --- /dev/null +++ b/bitmaps_png/sources/gerber_job_file.svg @@ -0,0 +1,818 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + height="26" + width="26" + version="1.1" + id="svg2" + inkscape:version="0.92.0 r15299" + sodipodi:docname="gerber_job_file.svg"> + <metadata + id="metadata172"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1170" + inkscape:window-height="836" + id="namedview170" + showgrid="true" + inkscape:zoom="9.3622609" + inkscape:cx="13.030913" + inkscape:cy="4.5453342" + inkscape:window-x="413" + inkscape:window-y="162" + inkscape:window-maximized="0" + inkscape:current-layer="svg2" + showguides="false"> + <inkscape:grid + type="xygrid" + id="grid3100" + empspacing="5" + visible="true" + enabled="true" + snapvisiblegridlinesonly="true" + originx="0" + originy="0" + spacingx="1.0666667" + spacingy="1.0666667" /> + </sodipodi:namedview> + <defs + id="defs4"> + <linearGradient + id="ab" + y2="4.2192998" + gradientUnits="userSpaceOnUse" + x2="7.5955" + gradientTransform="matrix(0.88924,0,0,0.78227,0.62292,7.6472)" + y1="43.993999" + x1="40.751999"> + <stop + stop-color="#333" + offset="0" + id="stop7" /> + <stop + stop-color="#474747" + offset="1" + id="stop9" /> + </linearGradient> + <linearGradient + id="a" + y2="19500" + gradientUnits="userSpaceOnUse" + x2="15000" + y1="14100" + x1="10100"> + <stop + stop-color="#f5fffa" + offset="0" + id="stop12" /> + <stop + stop-color="#6f6d7f" + offset="1.2" + id="stop14" /> + </linearGradient> + <linearGradient + id="b" + y2="19500" + gradientUnits="userSpaceOnUse" + x2="15000" + y1="14100" + x1="10100"> + <stop + stop-color="#fff" + stop-opacity="0.698" + offset="0" + id="stop17" /> + <stop + stop-color="#5db7ff" + stop-opacity="0.698" + offset="1.2" + id="stop19" /> + </linearGradient> + <linearGradient + id="x" + y2="19500" + gradientUnits="userSpaceOnUse" + x2="15000" + y1="14100" + x1="10100"> + <stop + stop-color="#f5ffff" + offset="0" + id="stop22" /> + <stop + stop-color="#fff" + stop-opacity="0" + offset="1.2" + id="stop24" /> + </linearGradient> + <radialGradient + id="ac" + xlink:href="#b" + gradientUnits="userSpaceOnUse" + cy="17526" + cx="18632" + gradientTransform="matrix(0.00205653,0,0,0.00205653,35.864533,-12.1536)" + r="40170" /> + <radialGradient + id="ad" + xlink:href="#b" + gradientUnits="userSpaceOnUse" + cy="17831" + cx="18969" + r="23166" + gradientTransform="matrix(0.00191701,0,0,0.00191701,38.437333,-10.359467)" /> + <radialGradient + id="ae" + xlink:href="#a" + gradientUnits="userSpaceOnUse" + cy="27370" + cx="25538" + gradientTransform="matrix(0.00194549,0,0,0.00194549,24.0288,-25.181866)" + r="3682.2" /> + <radialGradient + id="af" + xlink:href="#x" + gradientUnits="userSpaceOnUse" + cy="17398" + cx="18401" + gradientTransform="matrix(0.00191701,0,0,0.00191701,38.242133,-10.359467)" + r="11888" /> + <radialGradient + id="ag" + xlink:href="#a" + gradientUnits="userSpaceOnUse" + cy="15674" + cx="16467" + gradientTransform="matrix(0.00204277,0,0,0.00207051,35.864533,-12.1536)" + r="3055.2" /> + <radialGradient + id="ah" + xlink:href="#b" + gradientUnits="userSpaceOnUse" + cy="17753" + cx="18300" + gradientTransform="matrix(0.00205653,0,0,0.00205653,35.864533,-12.1536)" + r="28430" /> + <radialGradient + id="ai" + xlink:href="#a" + gradientUnits="userSpaceOnUse" + cy="33086" + cx="-2182.7" + gradientTransform="matrix(0.00349152,0,0,0.00121131,33.954133,16.765867)" + r="11540" /> + <radialGradient + id="aj" + xlink:href="#a" + gradientUnits="userSpaceOnUse" + cy="18596" + cx="17070" + gradientTransform="matrix(0.00208203,0,0,0.00203136,35.864533,-12.1536)" + r="3734.6001" /> + <linearGradient + id="ao" + y2="39368" + xlink:href="#x" + gradientUnits="userSpaceOnUse" + x2="2312.5" + gradientTransform="matrix(0.00349152,0,0,0.00121131,33.954133,16.765867)" + y1="39560" + x1="-1083.8" /> + <radialGradient + id="ak" + xlink:href="#b" + gradientUnits="userSpaceOnUse" + cy="11246" + cx="13190" + gradientTransform="matrix(0.00173621,0,0,0.00173621,34.7392,-13.975467)" + r="16248" /> + <linearGradient + id="ap" + y2="18951" + xlink:href="#a" + gradientUnits="userSpaceOnUse" + x2="12508" + gradientTransform="matrix(0.00205653,0,0,0.00205653,35.864533,-12.1536)" + y1="-85.142998" + x1="-1308.3" /> + <radialGradient + id="al" + xlink:href="#a" + gradientUnits="userSpaceOnUse" + cy="29167" + cx="26631" + gradientTransform="matrix(0.00178912,0,0,0.00178912,42.586666,-6.9703469)" + r="4284.2002" /> + <linearGradient + id="y" + y2="20482" + gradientUnits="userSpaceOnUse" + x2="6753.3999" + gradientTransform="matrix(0.00141995,0,0,0.00297856,33.954133,16.765867)" + y1="27356" + x1="850.32001"> + <stop + stop-color="#a66500" + offset="0" + id="stop39" /> + <stop + stop-color="#da8f00" + offset="1" + id="stop41" /> + </linearGradient> + <linearGradient + id="z" + y2="21261" + gradientUnits="userSpaceOnUse" + x2="3741.1001" + gradientTransform="matrix(0.001344,0,0,0.00314709,33.954133,16.765867)" + y1="21261" + x1="-3478.8999"> + <stop + stop-color="#eda700" + offset="0" + id="stop44" /> + <stop + stop-color="#fff" + offset=".38824" + id="stop46" /> + <stop + stop-color="#ffcb50" + offset="0.7" + id="stop48" /> + <stop + stop-color="#ed8700" + offset="1" + id="stop50" /> + </linearGradient> + <linearGradient + id="aa" + y2="29618" + xlink:href="#a" + gradientUnits="userSpaceOnUse" + x2="24590" + gradientTransform="matrix(0.00205653,0,0,0.00205653,35.864533,-12.1536)" + y1="405.03" + x1="389.39999" /> + <radialGradient + id="am" + gradientUnits="userSpaceOnUse" + cy="10444" + cx="11715" + gradientTransform="matrix(0.00205653,0,0,0.00205653,35.864533,-12.1536)" + r="15132"> + <stop + stop-color="#f5ffff" + stop-opacity=".49020" + offset="0" + id="stop54" /> + <stop + stop-color="#fff" + stop-opacity="0" + offset="1.2" + id="stop56" /> + </radialGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#ab" + id="linearGradient3191" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.94852267,0,0,0.83442133,0.664448,8.1570133)" + x1="40.751999" + y1="43.993999" + x2="7.5955" + y2="4.2192998" /> + <linearGradient + inkscape:collect="always" + xlink:href="#ab" + id="linearGradient1016" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.94852267,0,0,0.83442133,0.664448,8.1570133)" + x1="40.751999" + y1="43.993999" + x2="7.5955" + y2="4.2192998" /> + <linearGradient + id="a-6" + y2="39.685001" + gradientUnits="userSpaceOnUse" + x2="34.534" + gradientTransform="matrix(0.92673,0,0,0.84499,4.7271,52.187)" + y1="12.285" + x1="14.463"> + <stop + stop-color="#c9c9c9" + offset="0" + id="stop1040" /> + <stop + stop-color="#f8f8f8" + offset=".25" + id="stop1042" /> + <stop + stop-color="#e2e2e2" + offset=".5" + id="stop1044" /> + <stop + stop-color="#b0b0b0" + offset=".75" + id="stop1046" /> + <stop + stop-color="#c9c9c9" + offset="1" + id="stop1048" /> + </linearGradient> + </defs> + <g + id="g1010" + transform="matrix(0.96357902,0,0,0.99699248,-0.99217666,0.8052567)"> + <g + style="opacity:0.81081082" + id="g99" + transform="matrix(0.54157884,0,0,0.5495207,0.11187994,-2.8442232)"> + <g + style="stroke-linecap:round;stroke-linejoin:round" + id="use101" + transform="matrix(0.88516,0.46528,-0.46528,0.88516,20.799849,-8.6726939)"> + <rect + style="color:#000000;display:block;fill:#ffffff;fill-opacity:0.63253;stroke:url(#linearGradient3191);stroke-width:1.06666672" + ry="0.95879465" + height="34.145069" + width="33.079464" + display="block" + y="11.2" + x="6.928" + id="rect3151" /> + <rect + style="color:#000000;display:block;opacity:0.79120998;fill:none;stroke:#ffffff;stroke-width:1.06666672" + display="block" + rx="0.14066133" + ry="0.12247467" + height="32.004265" + width="30.9312" + y="12.262401" + x="8" + id="rect3153" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:1.06666672" + d="m 10.862933,14.365867 5.6704,0.03413 3.2,3.2 v 8.533333" + display="block" + id="path3155" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:1.06666672" + d="M 24,26.133333 V 17.6 l -3.2,-3.2" + display="block" + id="path3157" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:1.06666672" + d="M 28.266667,26.133333 V 17.6 l -3.2,-3.2" + display="block" + id="path3159" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:1.06666672" + d="M 32.533333,26.133333 V 14.4" + display="block" + id="path3161" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:2.13333344" + d="m 19.733333,26.133333 v 2.133334" + display="block" + id="path3163" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:2.13333344" + d="m 24,26.133333 v 2.133334" + display="block" + id="path3165" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:2.13333344" + d="m 28.266667,26.133333 v 2.133334" + display="block" + id="path3167" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:2.13333344" + d="m 32.533333,26.133333 v 2.133334" + display="block" + id="path3169" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:2.13333344" + d="m 32.533333,33.6 v 2.133333" + display="block" + id="path3171" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:2.13333344" + d="m 28.266667,33.6 v 2.133333" + display="block" + id="path3173" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:2.13333344" + d="m 24,33.6 v 2.133333" + display="block" + id="path3175" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:2.13333344" + d="m 19.733333,33.6 v 2.133333" + display="block" + id="path3177" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:1.06666672" + d="m 19.733333,35.733333 v 3.2 L 17.6,41.066667 h -6.4" + display="block" + id="path3179" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:1.06666672" + d="m 24,35.733333 v 5.333334" + display="block" + id="path3181" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:1.06666672" + d="m 28.266667,35.733333 v 3.2 L 30.4,41.066667 h 6.4" + display="block" + id="path3183" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:1.06666672" + d="m 32.533333,35.733333 2.133334,2.133334 H 36.8" + display="block" + id="path3185" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;stroke:#000000;stroke-width:1.06666672" + display="block" + d="m 11.2,16.533333 h 4.266667 L 17.6,18.666667 v 19.2 l -1.066667,1.066666 H 11.2 Z" + id="path3187" /> + <rect + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:1.06666672" + display="block" + ry="2.1632001" + height="13.866667" + width="17.066668" + y="24" + x="17.6" + id="rect3189" /> + </g> + <use + id="use103" + x="0" + y="0" + width="48" + height="48" + transform="matrix(0.97367,0.22797,-0.22797,0.97367,10.729289,-7.9365122)" + xlink:href="#an" /> + <g + style="stroke-linecap:round;stroke-linejoin:round" + id="an" + transform="translate(-4.2613333,1.0552224)"> + <rect + style="color:#000000;display:block;fill:#ffffff;fill-opacity:0.63253;stroke:url(#linearGradient1016);stroke-width:1.06666672" + ry="0.95879465" + height="34.145069" + width="33.079464" + display="block" + y="11.2" + x="6.928" + id="rect3195" /> + <rect + style="color:#000000;display:block;opacity:0.79120998;fill:none;stroke:#ffffff;stroke-width:1.06666672" + display="block" + rx="0.14066133" + ry="0.12247467" + height="32.004265" + width="30.9312" + y="12.262401" + x="8" + id="rect3197" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:1.06666672" + d="m 10.862933,14.365867 5.6704,0.03413 3.2,3.2 v 8.533333" + display="block" + id="path3199" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:1.06666672" + d="M 24,26.133333 V 17.6 l -3.2,-3.2" + display="block" + id="path3201" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:1.06666672" + d="M 28.266667,26.133333 V 17.6 l -3.2,-3.2" + display="block" + id="path3203" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:1.06666672" + d="M 32.533333,26.133333 V 14.4" + display="block" + id="path3205" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:2.13333344" + d="m 19.733333,26.133333 v 2.133334" + display="block" + id="path3207" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:2.13333344" + d="m 24,26.133333 v 2.133334" + display="block" + id="path3209" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:2.13333344" + d="m 28.266667,26.133333 v 2.133334" + display="block" + id="path3211" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:2.13333344" + d="m 32.533333,26.133333 v 2.133334" + display="block" + id="path3213" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:2.13333344" + d="m 32.533333,33.6 v 2.133333" + display="block" + id="path3215" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:2.13333344" + d="m 28.266667,33.6 v 2.133333" + display="block" + id="path3217" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:2.13333344" + d="m 24,33.6 v 2.133333" + display="block" + id="path3219" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:2.13333344" + d="m 19.733333,33.6 v 2.133333" + display="block" + id="path3221" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:1.06666672" + d="m 19.733333,35.733333 v 3.2 L 17.6,41.066667 h -6.4" + display="block" + id="path3223" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:1.06666672" + d="m 24,35.733333 v 5.333334" + display="block" + id="path3225" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:1.06666672" + d="m 28.266667,35.733333 v 3.2 L 30.4,41.066667 h 6.4" + display="block" + id="path3227" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:1.06666672" + d="m 32.533333,35.733333 2.133334,2.133334 H 36.8" + display="block" + id="path3229" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;display:block;stroke:#000000;stroke-width:1.06666672" + display="block" + d="m 11.2,16.533333 h 4.266667 L 17.6,18.666667 v 19.2 l -1.066667,1.066666 H 11.2 Z" + id="path3231" /> + <rect + style="color:#000000;display:block;fill:none;stroke:#000000;stroke-width:1.06666672" + display="block" + ry="2.1632001" + height="13.866667" + width="17.066668" + y="24" + x="17.6" + id="rect3233" /> + </g> + <path + style="fill:#ffffff;fill-opacity:0.51807;fill-rule:evenodd;stroke-width:1.06666672" + inkscape:connector-curvature="0" + id="path106" + d="M 4.2666667,27.733333 V 13.866667 H 34.133333 v 13.866666 c -7.466666,6.4 -19.2,-6.4 -29.8666663,0 z" /> + </g> + <g + id="g114" + transform="matrix(0.37303414,0.10324413,-0.09465317,0.34403422,-4.4968508,-1.3805606)"> + <g + style="opacity:0.18469998" + id="g116" + transform="matrix(0.001928,0,0,0.001928,35.5648,-10.49184)"> + <path + style="fill-rule:evenodd;stroke-width:1.10570669" + inkscape:connector-curvature="0" + id="path118" + d="m 23872.83,21016.084 a 2527.3137,2527.3137 0 1 1 -5054.627,0 2527.3137,2527.3137 0 1 1 5054.627,0 z" /> + <path + style="fill-rule:evenodd;stroke-width:1.06666672" + inkscape:connector-curvature="0" + id="path120" + d="m 20995.2,18544 c -494.848,-610.219 -685.771,-195.563 -944.715,-401.365 -198.73,-178.134 135.168,-459.222 -297.205,-926.87 l -2109.76,2098.454 c 360.523,355.733 558.496,97.792 779.307,400.128 165.578,240.64 -18.251,553.856 514.89,898.57 l 2057.494,-2068.906 z" /> + <rect + style="fill-rule:evenodd;stroke-width:1.06666672" + id="rect122" + x="-2201.6001" + y="24636.801" + width="4977.8135" + height="1726.9333" + transform="rotate(-45)" /> + <path + style="fill-rule:evenodd;stroke-width:1.06666672" + inkscape:connector-curvature="0" + id="path124" + d="m 20958.933,10346.987 c 0,5395.2 -4373.653,9768.96 -9768.96,9768.96 -5395.1997,0 -9768.9597,-4373.654 -9768.9597,-9768.96 0,-5395.2003 4373.6534,-9768.96033 9768.9597,-9768.96033 5395.2,0 9768.96,4373.65333 9768.96,9768.96033 z m -967.69,-0.01 c 0,4860.8 -3940.48,8801.28 -8801.28,8801.28 -4860.8003,0 -8801.1737,-3940.48 -8801.1737,-8801.28 0,-4860.8 3940.48,-8801.28 8801.1737,-8801.28 4860.8,0 8801.28,3940.48 8801.28,8801.28 z" /> + <path + style="fill-rule:evenodd;stroke-width:1.0222187" + inkscape:connector-curvature="0" + id="path126" + d="m 31187.387,28241.364 a 2336.4855,2336.4855 0 1 1 -4672.971,0 2336.4855,2336.4855 0 1 1 4672.971,0 z" /> + <rect + style="stroke-width:1.06666672" + id="rect128" + x="-2533.3333" + y="28601.6" + width="5890.3467" + height="12355.2" + transform="rotate(-45)" /> + </g> + <path + style="opacity:0.29300005;fill:url(#ac);fill-rule:evenodd;stroke-width:1.06666672" + inkscape:connector-curvature="0" + id="path130" + d="m 72.802133,10.33856 c 0,7.183893 -5.82368,13.008 -13.008,13.008 -7.183786,0 -13.006933,-5.82368 -13.006933,-13.008 0,-7.1837867 5.82368,-13.008 13.006933,-13.008 7.183894,0 13.008,5.82368 13.008,13.008 z m 1.97152,-2.5621333 c 0,9.5886933 -7.77312,17.3621333 -17.362133,17.3621333 -9.588693,0 -17.362133,-7.773227 -17.362133,-17.3621333 0,-9.5886934 7.773226,-17.3621334 17.362133,-17.3621334 9.588693,0 17.362133,7.7732267 17.362133,17.3621334 z" /> + <path + style="opacity:0.68790002;fill:url(#ad);fill-rule:evenodd;stroke-width:0.00191701" + inkscape:connector-curvature="0" + id="path132" + d="m 75.617807,7.5176412 a 17.686557,17.686557 0 1 1 -35.37273,0 17.686557,17.686557 0 1 1 35.37273,0 z" /> + <path + style="fill:#717386;fill-rule:evenodd;stroke-width:0.00213184" + inkscape:connector-curvature="0" + id="path134" + d="m 81.892977,28.365297 a 4.8727467,4.8727467 0 1 1 -9.745493,0 4.8727467,4.8727467 0 1 1 9.745493,0 z" /> + <path + style="fill:url(#ae);fill-rule:evenodd;stroke-width:0.00194549" + inkscape:connector-curvature="0" + id="path136" + d="m 81.467545,28.365892 a 4.4468141,4.4468141 0 1 1 -8.893628,0 4.4468141,4.4468141 0 1 1 8.893628,0 z" /> + <path + style="fill:url(#af);fill-rule:evenodd;stroke-width:0.00191701" + inkscape:connector-curvature="0" + id="path138" + d="m 75.422607,7.5176412 a 17.686557,17.686557 0 1 1 -35.37273,0 17.686557,17.686557 0 1 1 35.37273,0 z" /> + <path + style="fill:url(#ag);fill-rule:evenodd;stroke-width:1.06666672" + inkscape:connector-curvature="0" + id="path140" + d="m 76.343467,23.6 c -0.954091,-1.176533 -1.32224,-0.377056 -1.82144,-0.773845 -0.383158,-0.343446 0.260608,-0.885398 -0.573024,-1.787094 l -4.06784,4.045867 c 0.695104,0.685867 1.0768,0.188544 1.502506,0.771467 0.319243,0.463968 -0.03519,1.06784 0.992726,1.73248 l 3.96704,-3.988907 z" /> + <path + style="fill:url(#ah);fill-rule:evenodd;stroke-width:1.06666672" + inkscape:connector-curvature="0" + id="path142" + d="m 74.241067,8.1754667 c 0,8.9271463 -7.184427,16.1642663 -16.046934,16.1642663 -8.8624,0 -16.046933,-7.236906 -16.046933,-16.1642663 0,-8.9271467 7.184427,-16.1642667 16.046933,-16.1642667 8.8624,0 16.046934,7.2368 16.046934,16.1642667 z m 1.31424,-0.6552107 c 0,10.01696 -8.12032,18.1376 -18.1376,18.1376 -10.01696,0 -18.1376,-8.12032 -18.1376,-18.1376 0,-10.01696 8.12032,-18.1376 18.1376,-18.1376 10.01696,0 18.1376,8.12032 18.1376,18.1376 z" /> + <rect + style="opacity:0.9554;fill:url(#ai);fill-rule:evenodd;stroke-width:1.06666672" + id="rect144" + x="29.709867" + y="64.267731" + width="9.5974398" + height="3.3297067" + transform="rotate(-45)" /> + <path + style="fill:url(#aj);fill-rule:evenodd;stroke-width:1.06666672" + inkscape:connector-curvature="0" + id="path146" + d="m 76.0992,23.943467 c -0.954091,-1.176534 -1.32224,-0.377056 -1.82144,-0.773846 -0.383157,-0.343445 0.211648,-1.1792 -0.866805,-2.227733 l -3.773974,3.703147 c 0.842006,0.832768 1.664427,0.286485 2.090134,0.869397 0.319242,0.463968 -0.03519,1.06784 0.992725,1.73248 l 3.379413,-3.30336 z" /> + <rect + style="fill:url(#ao);fill-rule:evenodd;stroke-width:1.06666672" + id="rect148" + x="30.532267" + y="64" + width="7.9522138" + height="2.7589333" + transform="rotate(-45)" /> + <path + style="opacity:0.21019999;fill:url(#ak);fill-rule:evenodd;stroke-width:0.00173621" + inkscape:connector-curvature="0" + id="path150" + d="m 58.124257,-0.35660928 a 6.1968926,6.1968926 0 1 1 -12.393785,0 6.1968926,6.1968926 0 1 1 12.393785,0 z" /> + <path + style="fill:url(#ap);fill-rule:evenodd;stroke-width:1.06666672" + inkscape:connector-curvature="0" + id="path152" + d="m 76.274133,7.79552 c 0,10.40224 -8.43264,18.8352 -18.8352,18.8352 -10.40224,0 -18.8352,-8.43264 -18.8352,-18.8352 0,-10.40224 8.43264,-18.8352 18.8352,-18.8352 10.40224,0 18.8352,8.43264 18.8352,18.8352 z m -1.865706,-1.81e-5 c 0,9.3718401 -7.597334,16.9696001 -16.9696,16.9696001 -9.371734,0 -16.9696,-7.597333 -16.9696,-16.9696001 0,-9.37184 7.597333,-16.9696 16.9696,-16.9696 9.37184,0 16.9696,7.5973333 16.9696,16.9696 z" /> + <path + style="fill:#808080;fill-rule:evenodd;stroke-width:0.00197088" + inkscape:connector-curvature="0" + id="path154" + d="m 95.995194,42.296634 a 4.5048404,4.5048404 0 1 1 -9.00968,0 4.5048404,4.5048404 0 1 1 9.00968,0 z" /> + <path + style="fill:url(#al);fill-rule:evenodd;stroke-width:0.00178912" + inkscape:connector-curvature="0" + id="path156" + d="m 95.408646,42.273392 a 4.089392,4.089392 0 1 1 -8.178784,0 4.089392,4.089392 0 1 1 8.178784,0 z" /> + <rect + style="fill:url(#y);stroke-width:1.06666672" + id="rect158" + x="29.069866" + y="71.911469" + width="11.3568" + height="23.821867" + transform="rotate(-45)" /> + <rect + style="fill:url(#z);stroke-width:1.06666672" + id="rect160" + x="30.209066" + y="73.19146" + width="9.080533" + height="21.262934" + transform="rotate(-45)" /> + <path + style="fill:url(#aa);fill-rule:evenodd;stroke-width:1.06666672" + inkscape:connector-curvature="0" + id="path162" + d="m 74.776533,7.6485333 c 0,9.5166937 -7.71488,17.2319997 -17.232,17.2319997 -9.516693,0 -17.232,-7.71488 -17.232,-17.2319997 0,-9.5166933 7.71488,-17.232 17.232,-17.232 9.516694,0 17.232,7.71488 17.232,17.232 z m -0.514368,6.4e-6 c 0,9.2326403 -7.484586,16.7168003 -16.7168,16.7168003 -9.23264,0 -16.7168,-7.484587 -16.7168,-16.7168003 0,-9.23264 7.484587,-16.7168 16.7168,-16.7168 9.23264,0 16.7168,7.4845867 16.7168,16.7168 z" /> + <path + style="opacity:0.54140003;fill:url(#am);fill-rule:evenodd;stroke-width:1.06666672" + inkscape:connector-curvature="0" + id="path164" + d="m 60.269867,2.3768533 c 0,3.8557867 -3.12576,6.9815467 -6.98144,6.9815467 -3.855787,0 -6.98144,-3.12576 -6.98144,-6.9815467 0,-3.8557866 3.12576,-6.98144 6.98144,-6.98144 3.855786,0 6.98144,3.12576 6.98144,6.98144 z M 61.49472,1.641984 c 0,4.9381333 -4.003093,8.941227 -8.941227,8.941227 -4.938133,0 -8.941226,-4.0030937 -8.941226,-8.941227 0,-4.9381333 4.003093,-8.9412267 8.941226,-8.9412267 4.938134,0 8.941227,4.0030934 8.941227,8.9412267 z" /> + <path + style="fill:#9a9ba9;fill-rule:evenodd;stroke-width:1.06666672" + inkscape:connector-curvature="0" + id="path166" + d="m 72.385067,27.006933 0.310048,0.25232 3.43712,-3.307946 -0.187648,-0.301291 -3.559467,3.356907 z" /> + <path + style="fill:#8a92a0;fill-rule:evenodd;stroke-width:1.06666672" + inkscape:connector-curvature="0" + id="path168" + d="m 69.693867,24.718933 0.285653,0.210699 3.72416,-3.651093 -0.222336,-0.343243 -3.787413,3.78368 z" /> + </g> + </g> + <g + style="stroke:#000000" + transform="matrix(0.4228008,0,0,0.47494899,-3.6057646,-15.908652)" + id="g1063"> + <path + inkscape:connector-curvature="0" + style="color:#000000;fill:url(#a-6);stroke-width:1.30209994" + d="m 25.828,57.411 c -0.34731,0.02167 -0.68489,0.07071 -1.026,0.10631 h -0.02332 l -0.81616,4.061 c -1.3303,0.27623 -2.5818,0.74502 -3.7077,1.382 l -3.661,-2.402 c -0.98968,0.70058 -1.8903,1.5177 -2.6817,2.4026 l 2.5417,3.3807 c -0.77174,1.0754 -1.3521,2.3033 -1.679,3.5933 -5.2e-5,0.0061 -4.5e-5,0.0202 0,0.02126 l -4.4306,0.63786 c -0.081,0.60325 -0.11659,1.2267 -0.11659,1.8498 0,0.50981 0.0154,1.0128 0.0699,1.5096 l 4.4306,0.72291 c 0.31511,1.4029 0.91369,2.713 1.7489,3.8697 l -2.635,3.2956 c 0.75466,0.85424 1.6259,1.632 2.5651,2.3176 l 3.731,-2.3388 c 1.3039,0.75844 2.7595,1.2903 4.3373,1.5521 l 0.69956,4.0185 c 0.49711,0.04126 1.0069,0.04252 1.5157,0.04252 0.71836,-10e-7 1.4045,-0.02482 2.0987,-0.10631 l 0.83948,-4.1036 c 1.499,-0.341 2.906,-0.931 4.128,-1.723 l 3.5911,2.3813 c 0.93128,-0.72243 1.7829,-1.5528 2.5184,-2.4451 l -2.6117,-3.4444 c 0.70729,-1.1138 1.1974,-2.3427 1.4458,-3.6571 l 4.4073,-0.63786 c 0.03865,-0.41935 0.04663,-0.82605 0.04663,-1.2545 0,-0.74449 -0.09491,-1.4745 -0.20987,-2.19 l -4.476,-0.745 c -0.351,-1.181 -0.927,-2.283 -1.656,-3.274 l 2.635,-3.2956 c -0.817,-0.911 -1.749,-1.752 -2.775,-2.466 l -3.801,2.381 c -1.092,-0.589 -2.268,-1.041 -3.544,-1.297 l -0.7,-4.04 c -0.63673,-0.06829 -1.2787,-0.10631 -1.9355,-0.10631 -0.1775,0 -0.36018,-0.0051 -0.53633,0 -0.08587,0.0024 -0.17086,-0.0046 -0.25651,0 -0.0232,0.0012 -0.0468,-0.0014 -0.06996,0 z m 0.60629,10.333 c 0.08519,-0.0039 0.17025,0 0.25651,0 2.7603,0 5.0135,2.0545 5.0135,4.5713 1e-6,2.5168 -2.2532,4.5501 -5.0135,4.5501 -2.7603,1e-6 -4.9902,-2.0332 -4.9902,-4.5501 0,-2.4382 2.0928,-4.4491 4.7337,-4.5713 z" + id="path1057" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;opacity:0.34658999;fill:none;stroke-width:1.40030003" + d="m 25.311,58.215 -0.6553,3.932 c -1.2469,0.25892 -3.5405,1.0508 -4.5959,1.6479 l -3.4863,-2.3726 c -0.92766,0.65668 -0.99127,0.70121 -1.7331,1.5307 l 2.5207,3.4087 c -0.72338,1.008 -1.5922,2.8042 -1.9042,4.0878 0,0 -4.4171,0.67892 -4.4171,0.67892 -0.07593,0.56544 -0.03948,1.7757 0.01164,2.2413 l 4.2192,0.69303 c 0.29536,1.315 1.4006,3.4316 2.1835,4.5157 l -2.6681,3.2142 c 0.70736,0.8007 0.84892,0.87397 1.7292,1.5166 l 3.5677,-2.3833 c 1.2222,0.7109 3.6482,1.5757 5.1271,1.8211 l 0.58553,3.8824 c 0.46595,0.03867 1.7532,0.14715 2.4038,0.07077 l 0.65531,-4.0416 c 1.4042,-0.31862 3.8304,-1.2267 4.9759,-1.9697 l 3.5639,2.3479 c 0.87292,-0.67715 0.88074,-0.77919 1.5702,-1.6156 l -2.641,-3.4228 c 0.66296,-1.044 1.5202,-3.0857 1.753,-4.3177 l 4.324,-0.65416 c 0.03623,-0.39307 0.03799,-1.4892 -0.06977,-2.1599 l -4.4054,-0.69303 c -0.32887,-1.1073 -1.4575,-3.1025 -2.1409,-4.0314 l 2.8,-3.2142 c -0.76558,-0.85369 -1.0502,-0.97082 -2.0124,-1.6403 l -3.688,2.408 c -1.024,-0.553 -3.066,-1.394 -4.262,-1.634 l -0.65149,-3.8471 c -0.59683,-0.06401 -2.3187,-0.03559 -2.6598,0 z" + id="path1059" /> + <path + inkscape:connector-curvature="0" + style="color:#000000;opacity:0.64772997;fill:none;stroke-width:0.71253002" + d="m 32.454,72.306 a 5.7605,5.2524 0 0 1 -11.521,0 5.7605,5.2524 0 1 1 11.521,0 z" + id="path1061" /> + </g> +</svg> diff --git a/common/gbr_metadata.cpp b/common/gbr_metadata.cpp index f9faecf525..fe24f23377 100644 --- a/common/gbr_metadata.cpp +++ b/common/gbr_metadata.cpp @@ -122,6 +122,41 @@ std::string GBR_APERTURE_METADATA::FormatAttribute( GBR_APERTURE_ATTRIB aAttribu return attribute_string; } +wxString FormatStringFromGerber( const wxString& aString ) +{ + // make the inverse conversion of formatStringToGerber() + // It converts a "normalized" gerber string and convert it to a 16 bits sequence unicode + // and return a wxString (unicode 16) from the gerber string + wxString txt; + + for( unsigned ii = 0; ii < aString.Length(); ++ii ) + { + unsigned code = aString[ii]; + + if( code == '\\' ) + { + // Convert 4 hexadecimal digits to a 16 bit unicode + // (Gerber allows only 4 hexadecimal digits) + long value = 0; + + for( int jj = 0; jj < 4; jj++ ) + { + value <<= 4; + code = aString[++ii]; + // Very basic conversion, but it expects a valid gerber file + int hexa = (code <= '9' ? code - '0' : code - 'A' + 10) & 0xF; + value += hexa; + } + + txt.Append( wxChar( value ) ); + } + else + txt.Append( aString[ii] ); + } + + return txt; +} + std::string formatStringToGerber( const wxString& aString ) { diff --git a/common/pcb_plot_params.keywords b/common/pcb_plot_params.keywords index 12ff3db2b3..059eb84684 100644 --- a/common/pcb_plot_params.keywords +++ b/common/pcb_plot_params.keywords @@ -1,3 +1,4 @@ +creategerberjobfile drillshape excludeedgelayer false diff --git a/common/wildcards_and_files_ext.cpp b/common/wildcards_and_files_ext.cpp index 1ac009c112..d29b1f62f7 100644 --- a/common/wildcards_and_files_ext.cpp +++ b/common/wildcards_and_files_ext.cpp @@ -42,7 +42,8 @@ const wxString ProjectFileExtension( wxT( "pro" ) ); const wxString SchematicFileExtension( wxT( "sch" ) ); const wxString NetlistFileExtension( wxT( "net" ) ); const wxString ComponentFileExtension( wxT( "cmp" ) ); -const wxString GerberFileExtension( wxT( ".((gbr|(gb|gt)[alops])|pho)" ) ); +const wxString GerberFileExtension( "gbr" ); +const wxString GerberJobFileExtension( "gbj" ); const wxString HtmlFileExtension( wxT( "html" ) ); const wxString LegacyPcbFileExtension( wxT( "brd" ) ); diff --git a/gerbview/CMakeLists.txt b/gerbview/CMakeLists.txt index ffbde6a668..be12ffae31 100644 --- a/gerbview/CMakeLists.txt +++ b/gerbview/CMakeLists.txt @@ -51,7 +51,7 @@ set( GERBVIEW_SRCS gerbview_config.cpp gerbview_frame.cpp hotkeys.cpp - clear_gbr_drawlayers.cpp + job_file_reader.cpp locate.cpp menubar.cpp onleftclick.cpp diff --git a/gerbview/events_called_functions.cpp b/gerbview/events_called_functions.cpp index c9512bcc8b..4e70219014 100644 --- a/gerbview/events_called_functions.cpp +++ b/gerbview/events_called_functions.cpp @@ -54,6 +54,7 @@ BEGIN_EVENT_TABLE( GERBVIEW_FRAME, EDA_DRAW_FRAME ) EVT_TOOL( ID_GERBVIEW_ERASE_ALL, GERBVIEW_FRAME::Files_io ) EVT_TOOL( ID_GERBVIEW_LOAD_DRILL_FILE, GERBVIEW_FRAME::Files_io ) EVT_TOOL( ID_GERBVIEW_LOAD_ZIP_ARCHIVE_FILE, GERBVIEW_FRAME::Files_io ) + EVT_TOOL( ID_GERBVIEW_LOAD_JOB_FILE, GERBVIEW_FRAME::Files_io ) EVT_TOOL( ID_NEW_BOARD, GERBVIEW_FRAME::Files_io ) EVT_TOOL( ID_GERBVIEW_SET_PAGE_BORDER, GERBVIEW_FRAME::Process_Special_Functions ) @@ -70,6 +71,9 @@ BEGIN_EVENT_TABLE( GERBVIEW_FRAME, EDA_DRAW_FRAME ) EVT_MENU_RANGE( ID_GERBVIEW_ZIP_FILE1, ID_GERBVIEW_ZIP_FILE9, GERBVIEW_FRAME::OnZipFileHistory ) + EVT_MENU_RANGE( ID_GERBVIEW_JOB_FILE1, ID_GERBVIEW_JOB_FILE9, + GERBVIEW_FRAME::OnJobFileHistory ) + EVT_MENU( wxID_EXIT, GERBVIEW_FRAME::OnQuit ) // menu Preferences diff --git a/gerbview/files.cpp b/gerbview/files.cpp index 3fe971402d..3562a29486 100644 --- a/gerbview/files.cpp +++ b/gerbview/files.cpp @@ -74,6 +74,7 @@ void GERBVIEW_FRAME::OnDrlFileHistory( wxCommandEvent& event ) } } + void GERBVIEW_FRAME::OnZipFileHistory( wxCommandEvent& event ) { wxString filename; @@ -87,6 +88,18 @@ void GERBVIEW_FRAME::OnZipFileHistory( wxCommandEvent& event ) } +void GERBVIEW_FRAME::OnJobFileHistory( wxCommandEvent& event ) +{ + wxString filename; + filename = GetFileFromHistory( event.GetId(), _( "Job files" ), &m_jobFileHistory ); + + if( !filename.IsEmpty() ) + { + LoadGerberJobFile( filename ); + } +} + + /* File commands. */ void GERBVIEW_FRAME::Files_io( wxCommandEvent& event ) { @@ -116,6 +129,11 @@ void GERBVIEW_FRAME::Files_io( wxCommandEvent& event ) m_canvas->Refresh(); break; + case ID_GERBVIEW_LOAD_JOB_FILE: + LoadGerberJobFile( wxEmptyString ); + m_canvas->Refresh(); + break; + default: wxFAIL_MSG( wxT( "File_io: unexpected command id" ) ); break; diff --git a/gerbview/gerbview_config.cpp b/gerbview/gerbview_config.cpp index 75c1ceacab..8b52e1a19b 100644 --- a/gerbview/gerbview_config.cpp +++ b/gerbview/gerbview_config.cpp @@ -29,7 +29,6 @@ */ #include <fctsys.h> -#include <macros.h> #include <id.h> #include <common.h> #include <class_drawpanel.h> @@ -41,9 +40,6 @@ #include <dialog_hotkeys_editor.h> -#define GROUP wxT("/gerbview") - - void GERBVIEW_FRAME::Process_Config( wxCommandEvent& event ) { int id = event.GetId(); diff --git a/gerbview/gerbview_frame.cpp b/gerbview/gerbview_frame.cpp index 0853de3552..418d43fd7e 100644 --- a/gerbview/gerbview_frame.cpp +++ b/gerbview/gerbview_frame.cpp @@ -37,6 +37,7 @@ #include <class_gbr_layer_box_selector.h> #include <msgpanel.h> #include <bitmaps.h> +#include <wildcards_and_files_ext.h> #include <gerbview.h> #include <gerbview_frame.h> @@ -81,6 +82,7 @@ GERBVIEW_FRAME::GERBVIEW_FRAME( KIWAY* aKiway, wxWindow* aParent ): m_displayMode = 0; m_drillFileHistory.SetBaseId( ID_GERBVIEW_DRILL_FILE1 ); m_zipFileHistory.SetBaseId( ID_GERBVIEW_ZIP_FILE1 ); + m_jobFileHistory.SetBaseId( ID_GERBVIEW_JOB_FILE1 ); if( m_canvas ) m_canvas->SetEnableBlockCommands( true ); @@ -230,8 +232,10 @@ bool GERBVIEW_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in wxFileName fn( aFileSet[i] ); wxString ext = fn.GetExt(); - if( ext == "drl" ) + if( ext == DrillFileExtension ) // In Excellon format LoadExcellonFiles( aFileSet[i] ); + else if( ext == GerberJobFileExtension ) + LoadGerberJobFile( aFileSet[i] ); else LoadGerberFiles( aFileSet[i] ); } @@ -307,6 +311,12 @@ void GERBVIEW_FRAME::LoadSettings( wxConfigBase* aCfg ) aCfg->SetPath( wxT( "zip_files" ) ); m_zipFileHistory.Load( *aCfg ); aCfg->SetPath( wxT( ".." ) ); + + // because we have more than one file history, we must read this one + // using a specific path + aCfg->SetPath( "job_files" ); + m_jobFileHistory.Load( *aCfg ); + aCfg->SetPath( wxT( ".." ) ); } @@ -334,6 +344,11 @@ void GERBVIEW_FRAME::SaveSettings( wxConfigBase* aCfg ) aCfg->SetPath( wxT( "zip_files" ) ); m_zipFileHistory.Save( *aCfg ); aCfg->SetPath( wxT( ".." ) ); + + // Save the job file history list. + aCfg->SetPath( "job_files" ); + m_jobFileHistory.Save( *aCfg ); + aCfg->SetPath( ".." ); } diff --git a/gerbview/gerbview_frame.h b/gerbview/gerbview_frame.h index 31f23e9fb0..39a7f1b868 100644 --- a/gerbview/gerbview_frame.h +++ b/gerbview/gerbview_frame.h @@ -163,6 +163,9 @@ protected: // Auxiliary file history used to store drill files history. wxFileHistory m_drillFileHistory; + // Auxiliary file history used to store job files history. + wxFileHistory m_jobFileHistory; + /// The last filename chosen to be proposed to the user wxString m_lastFileName; @@ -606,6 +609,12 @@ public: */ void OnZipFileHistory( wxCommandEvent& event ); + /** + * deletes the current data and load a gerber job file selected from the + * history list. + */ + void OnJobFileHistory( wxCommandEvent& event ); + /** * Extracts gerber and drill files from the zip archive, and load them * @param aFullFileName is the full filename of the zip archive @@ -647,6 +656,17 @@ public: */ bool LoadZipArchiveFile( const wxString& aFileName ); + + /** + * Load a Gerber job file, and load gerber files found in job files. + * @param aFileName - void string or file name with full path to open or empty string to + * open a new file. + * if empty string: user will be prompted for filename(s) + * @return true if file(s) was opened successfully. + */ + bool LoadGerberJobFile( const wxString& aFileName ); + + bool GeneralControl( wxDC* aDC, const wxPoint& aPosition, EDA_KEY aHotKey = 0 ) override; /** diff --git a/gerbview/gerbview_id.h b/gerbview/gerbview_id.h index 48e39fb5dc..e54a6bb07e 100644 --- a/gerbview/gerbview_id.h +++ b/gerbview/gerbview_id.h @@ -41,6 +41,7 @@ enum gerbview_ids ID_GERBVIEW_SHOW_LIST_DCODES, ID_GERBVIEW_LOAD_DRILL_FILE, + ID_GERBVIEW_LOAD_JOB_FILE, ID_GERBVIEW_LOAD_ZIP_ARCHIVE_FILE, ID_GERBVIEW_ERASE_ALL, ID_TOOLBARH_GERBER_SELECT_ACTIVE_DCODE, @@ -66,7 +67,19 @@ enum gerbview_ids ID_GERBVIEW_DRILL_FILE8, ID_GERBVIEW_DRILL_FILE9, - // IDs for drill file history (wxID_FILEnn is already in use) + // IDs for job file history (wxID_FILEnn is already in use) + ID_GERBVIEW_JOB_FILE, + ID_GERBVIEW_JOB_FILE1, + ID_GERBVIEW_JOB_FILE2, + ID_GERBVIEW_JOB_FILE3, + ID_GERBVIEW_JOB_FILE4, + ID_GERBVIEW_JOB_FILE5, + ID_GERBVIEW_JOB_FILE6, + ID_GERBVIEW_JOB_FILE7, + ID_GERBVIEW_JOB_FILE8, + ID_GERBVIEW_JOB_FILE9, + + // IDs for zip file history (wxID_FILEnn is already in use) ID_GERBVIEW_ZIP_FILE, ID_GERBVIEW_ZIP_FILE1, ID_GERBVIEW_ZIP_FILE2, diff --git a/gerbview/job_file_reader.cpp b/gerbview/job_file_reader.cpp new file mode 100644 index 0000000000..48798dbba8 --- /dev/null +++ b/gerbview/job_file_reader.cpp @@ -0,0 +1,245 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2007-2017 Jean-Pierre Charras jp.charras at wanadoo.fr + * Copyright (C) 1992-2017 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 + */ + +/** + * @file job_file_reader.cpp + */ + +#include <fctsys.h> +#include <wx/filename.h> + +#include <gerbview.h> +#include <richio.h> +#include <class_drawpanel.h> +#include <class_gerber_file_image.h> +#include <class_gerber_file_image_list.h> +#include <gerbview_frame.h> +#include <reporter.h> +#include <plot_auxiliary_data.h> +#include <html_messagebox.h> + +extern int ReadInt( char*& text, bool aSkipSeparator = true ); +extern double ReadDouble( char*& text, bool aSkipSeparator = true ); +extern bool GetEndOfBlock( char* buff, char*& text, FILE* gerber_file ); + +/** + * this class read and parse a Gerber job file to extract useful info + * for GerbView + * + * In a gerber job file, data lines start by + * %TF. (usual Gerber X2 info) + * %TJ.B. (board info) + * %TJ.D. (design info) + * %TJ.L. (layers info) + * some others are not yet handled by Kicad + * M02* is the last line + */ +class GERBER_JOBFILE_READER +{ +public: + GERBER_JOBFILE_READER( const wxString& aFileName, REPORTER* aReporter ) + { + m_filename = aFileName; + m_reporter = aReporter; + } + + ~GERBER_JOBFILE_READER() {} + + bool ReadGerberJobFile(); /// read the .gbj file + wxArrayString& GetGerberFiles() { return m_GerberFiles; } + +private: + /** parse a string starting by "%TJ.L" (layer gerber filename) + * and add the filename in m_GerberFiles + */ + bool parseTJLayerString( wxString& aText ); + +private: + REPORTER* m_reporter; + wxFileName m_filename; + wxArrayString m_GerberFiles; // List of gerber files in job +}; + + +bool GERBER_JOBFILE_READER::ReadGerberJobFile() +{ + // Read the gerber file */ + FILE* jobFile = wxFopen( m_filename.GetFullPath(), wxT( "rt" ) ); + + if( jobFile == nullptr ) + return false; + + LOCALE_IO toggleIo; + + FILE_LINE_READER jobfileReader( jobFile, m_filename.GetFullPath() ); // Will close jobFile + + wxString msg; + wxString data; + + while( true ) + { + char* line = jobfileReader.ReadLine(); + + if( !line ) // end of file + break; + + wxString text( line ); + text.Trim( true ); + text.Trim( false ); + + // Search for lines starting by '%', others are not usefull + if( text.StartsWith( "%TJ.L.", &data ) ) + { + parseTJLayerString( data ); + continue; + } + + if( text.StartsWith( "M02" ) ) // End of file + break; + } + + return true; +} + + +bool GERBER_JOBFILE_READER::parseTJLayerString( wxString& aText ) +{ + // Parse a line like: + // %TJ.L."Copper,L1,Top",Positive,kit-dev-coldfire-xilinx_5213-Top_layer.gbr*% + // and extract the .gbr filename + + // The filename is between the last comma in string and the '*' char + // the filename cannot contain itself a comma: + // this is a not allowed char, that is transcoded in hexa sequence + // if found in filename + wxString name = aText.AfterLast( ',' ).BeforeFirst( '*' ); + m_GerberFiles.Add( FormatStringFromGerber( name ) ); + + return true; +} + + +bool GERBVIEW_FRAME::LoadGerberJobFile( const wxString& aFullFileName ) +{ +#define jobFileWildcard _( "Gerber job file (*.gbj)|*.gbj;.gbj" ) + wxFileName filename = aFullFileName; + wxString currentPath; + + if( !filename.IsOk() ) + { + // Use the current working directory if the file name path does not exist. + if( filename.DirExists() ) + currentPath = filename.GetPath(); + else + currentPath = m_mruPath; + + wxFileDialog dlg( this, _( "Open Gerber Job File" ), + currentPath, + filename.GetFullName(), + jobFileWildcard, + wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_CHANGE_DIR ); + + if( dlg.ShowModal() == wxID_CANCEL ) + return false; + + filename = dlg.GetPath(); + currentPath = wxGetCwd(); + m_mruPath = currentPath; + } + else + { + currentPath = filename.GetPath(); + m_mruPath = currentPath; + } + + wxString msg; + WX_STRING_REPORTER reporter( &msg ); + + if( filename.IsOk() ) + { + GERBER_JOBFILE_READER gbjReader( filename.GetFullPath(), &reporter ); + + if( gbjReader.ReadGerberJobFile() ) + { + // Update the list of recent drill files. + UpdateFileHistory( filename.GetFullPath(), &m_jobFileHistory ); + + Clear_DrawLayers( false ); + ClearMsgPanel(); + + wxArrayString& gbrfiles = gbjReader.GetGerberFiles(); + + wxFileName gbr_fn = filename; + bool read_ok; + int layer = 0; + setActiveLayer( layer, false ); + + for( unsigned ii = 0; ii < gbrfiles.GetCount(); ii++ ) + { + gbr_fn.SetFullName( gbrfiles[ii] ); + + if( gbr_fn.FileExists() ) + { + //LoadGerberFiles( gbr_fn.GetFullPath() ); + read_ok = Read_GERBER_File( gbr_fn.GetFullPath() ); + + if( read_ok ) + { + layer = getNextAvailableLayer( layer ); + setActiveLayer( layer, false ); + } + } + else + read_ok = false; + + if( !read_ok ) + { + wxString err; + err.Printf( _( "Can't load Gerber file:<br><i>%s</i><br>" ), gbr_fn.GetFullPath() ); + reporter.Report( err, REPORTER::RPT_WARNING ); + } + } + + GetImagesList()->SortImagesByZOrder(); + ReFillLayerWidget(); + syncLayerBox( true ); + GetCanvas()->Refresh(); + } + } + + Zoom_Automatique( false ); + + if( !msg.IsEmpty() ) + { + wxSafeYield(); // Allows slice of time to redraw the screen + // to refresh widgets, before displaying messages + HTML_MESSAGE_BOX mbox( this, _( "Messages" ) ); + mbox.ListSet( msg ); + mbox.ShowModal(); + } + + return true; +} + + diff --git a/gerbview/menubar.cpp b/gerbview/menubar.cpp index f991b1ad06..40bb93fb93 100644 --- a/gerbview/menubar.cpp +++ b/gerbview/menubar.cpp @@ -59,22 +59,25 @@ void GERBVIEW_FRAME::ReCreateMenuBar() wxMenu* fileMenu = new wxMenu; // Load Gerber files - AddMenuItem( fileMenu, - wxID_FILE, + AddMenuItem( fileMenu, wxID_FILE, _( "Load &Gerber File" ), _( "Load a new Gerber file on the current layer. Previous data will be deleted" ), KiBitmap( gerber_file_xpm ) ); // Load Excellon drill files - AddMenuItem( fileMenu, - ID_GERBVIEW_LOAD_DRILL_FILE, + AddMenuItem( fileMenu, ID_GERBVIEW_LOAD_DRILL_FILE, _( "Load &EXCELLON Drill File" ), _( "Load excellon drill file" ), KiBitmap( gerbview_drill_file_xpm ) ); + // Load Gerber job files + AddMenuItem( fileMenu, ID_GERBVIEW_LOAD_JOB_FILE, + _( "Load Gerber &Job File" ), + _( "Load a Gerber job file, and load gerber files depending on the job" ), + KiBitmap( gerber_job_file_xpm ) ); + // Load Zip archive files - AddMenuItem( fileMenu, - ID_GERBVIEW_LOAD_ZIP_ARCHIVE_FILE, + AddMenuItem( fileMenu, ID_GERBVIEW_LOAD_ZIP_ARCHIVE_FILE, _( "Load &Zip Archive File" ), _( "Load a zipped archive (Gerber and drill) file" ), KiBitmap( zip_xpm ) ); @@ -92,8 +95,7 @@ void GERBVIEW_FRAME::ReCreateMenuBar() Kiface().GetFileHistory().UseMenu( openRecentGbrMenu ); Kiface().GetFileHistory().AddFilesToMenu(); - AddMenuItem( fileMenu, openRecentGbrMenu, - wxID_ANY, + AddMenuItem( fileMenu, openRecentGbrMenu, wxID_ANY, _( "Open &Recent Gerber File" ), _( "Open a recent opened Gerber file" ), KiBitmap( recent_xpm ) ); @@ -107,8 +109,7 @@ void GERBVIEW_FRAME::ReCreateMenuBar() openRecentDrlMenu = new wxMenu(); m_drillFileHistory.UseMenu( openRecentDrlMenu ); m_drillFileHistory.AddFilesToMenu( ); - AddMenuItem( fileMenu, openRecentDrlMenu, - wxID_ANY, + AddMenuItem( fileMenu, openRecentDrlMenu, wxID_ANY, _( "Open Recent Dri&ll File" ), _( "Open a recent opened drill file" ), KiBitmap( recent_xpm ) ); @@ -122,12 +123,25 @@ void GERBVIEW_FRAME::ReCreateMenuBar() openRecentZipArchiveMenu = new wxMenu(); m_zipFileHistory.UseMenu( openRecentZipArchiveMenu ); m_zipFileHistory.AddFilesToMenu( ); - AddMenuItem( fileMenu, openRecentZipArchiveMenu, - wxID_ANY, + AddMenuItem( fileMenu, openRecentZipArchiveMenu, wxID_ANY, _( "Open Recent Zip &Archive File" ), _( "Open a recent opened zip archive file" ), KiBitmap( recent_xpm ) ); + // Recent job files + static wxMenu* openRecentJobFilesMenu; + + if( openRecentJobFilesMenu ) + m_jobFileHistory.RemoveMenu( openRecentJobFilesMenu ); + + openRecentJobFilesMenu = new wxMenu(); + m_jobFileHistory.UseMenu( openRecentJobFilesMenu ); + m_jobFileHistory.AddFilesToMenu( ); + AddMenuItem( fileMenu, openRecentJobFilesMenu, wxID_ANY, + _( "Open Recent &Job File" ), + _( "Open a recent opened gerber job file" ), + KiBitmap( recent_xpm ) ); + // Separator fileMenu->AppendSeparator(); @@ -152,40 +166,33 @@ void GERBVIEW_FRAME::ReCreateMenuBar() fileMenu->AppendSeparator(); // Print - AddMenuItem( fileMenu, - wxID_PRINT, - _( "&Print" ), - _( "Print gerber" ), + AddMenuItem( fileMenu, wxID_PRINT, + _( "&Print" ), _( "Print gerber" ), KiBitmap( print_button_xpm ) ); // Separator fileMenu->AppendSeparator(); // Exit - AddMenuItem( fileMenu, - wxID_EXIT, - _( "&Close" ), - _( "Close GerbView" ), + AddMenuItem( fileMenu, wxID_EXIT, + _( "&Close" ), _( "Close GerbView" ), KiBitmap( exit_xpm ) ); // Menu for configuration and preferences wxMenu* configMenu = new wxMenu; // Hide layer manager - AddMenuItem( configMenu, - ID_MENU_GERBVIEW_SHOW_HIDE_LAYERS_MANAGER_DIALOG, + AddMenuItem( configMenu, ID_MENU_GERBVIEW_SHOW_HIDE_LAYERS_MANAGER_DIALOG, _( "Hide &Layers Manager" ), m_show_layer_manager_tools ? _( "Hide &Layers Manager" ) : _("Show &Layers Manager" ), KiBitmap( layers_manager_xpm ) ); // Options (Preferences on WXMAC) - #ifdef __WXMAC__ configMenu->Append(wxID_PREFERENCES); #else - AddMenuItem( configMenu, - wxID_PREFERENCES, + AddMenuItem( configMenu, wxID_PREFERENCES, _( "&Options" ), _( "Set options to draw items" ), KiBitmap( preference_xpm ) ); @@ -204,15 +211,13 @@ void GERBVIEW_FRAME::ReCreateMenuBar() wxMenu* miscellaneousMenu = new wxMenu; // List dcodes - AddMenuItem( miscellaneousMenu, - ID_GERBVIEW_SHOW_LIST_DCODES, + AddMenuItem( miscellaneousMenu, ID_GERBVIEW_SHOW_LIST_DCODES, _( "&List DCodes" ), _( "List D-codes defined in Gerber files" ), KiBitmap( show_dcodenumber_xpm ) ); // Show source - AddMenuItem( miscellaneousMenu, - ID_GERBVIEW_SHOW_SOURCE, + AddMenuItem( miscellaneousMenu, ID_GERBVIEW_SHOW_SOURCE, _( "&Show Source" ), _( "Show source file for the current layer" ), KiBitmap( tools_xpm ) ); @@ -221,8 +226,7 @@ void GERBVIEW_FRAME::ReCreateMenuBar() miscellaneousMenu->AppendSeparator(); // Erase graphic layer - AddMenuItem( miscellaneousMenu, - ID_GERBVIEW_ERASE_CURR_LAYER, + AddMenuItem( miscellaneousMenu, ID_GERBVIEW_ERASE_CURR_LAYER, _( "&Clear Current Layer" ), _( "Erase the graphic layer currently selected" ), KiBitmap( delete_sheet_xpm ) ); @@ -231,8 +235,7 @@ void GERBVIEW_FRAME::ReCreateMenuBar() miscellaneousMenu->AppendSeparator(); // Text editor (usefull to browse source files) - AddMenuItem( miscellaneousMenu, - ID_MENU_GERBVIEW_SELECT_PREFERED_EDITOR, + AddMenuItem( miscellaneousMenu, ID_MENU_GERBVIEW_SELECT_PREFERED_EDITOR, _( "&Text Editor" ), _( "Select your preferred text editor" ), KiBitmap( editor_xpm ) ); @@ -240,14 +243,12 @@ void GERBVIEW_FRAME::ReCreateMenuBar() // Help menu wxMenu* helpMenu = new wxMenu; - AddMenuItem( helpMenu, - wxID_HELP, + AddMenuItem( helpMenu, wxID_HELP, _( "Gerbview &Manual" ), _( "Open the GerbView Manual" ), KiBitmap( online_help_xpm ) ); - AddMenuItem( helpMenu, - ID_PREFERENCES_HOTKEY_SHOW_CURRENT_LIST, + AddMenuItem( helpMenu, ID_PREFERENCES_HOTKEY_SHOW_CURRENT_LIST, _( "&List Hotkeys" ), _( "Displays the current hotkeys list and corresponding commands" ), KiBitmap( hotkeys_xpm ) ); @@ -264,10 +265,8 @@ void GERBVIEW_FRAME::ReCreateMenuBar() helpMenu->AppendSeparator(); // About Kicad - AddMenuItem( helpMenu, - wxID_ABOUT, - _( "&About Kicad" ), - _( "About KiCad" ), + AddMenuItem( helpMenu, wxID_ABOUT, + _( "&About Kicad" ), _( "About KiCad" ), KiBitmap( about_xpm ) ); // Append menus to the menubar diff --git a/gerbview/readgerb.cpp b/gerbview/readgerb.cpp index ce30cd52aa..59f2ec61f1 100644 --- a/gerbview/readgerb.cpp +++ b/gerbview/readgerb.cpp @@ -69,9 +69,9 @@ bool GERBVIEW_FRAME::Read_GERBER_File( const wxString& GERBER_FullFileName ) } /* if the gerber file is only a RS274D file - * (i.e. without any aperture information), wran the user: + * (i.e. without any aperture information, but with items), warn the user: */ - if( !gerber->m_Has_DCode ) + if( !gerber->m_Has_DCode && gerber->GetItemsList() ) { msg = _("Warning: this file has no D-Code definition\n" "It is perhaps an old RS274D file\n" @@ -101,12 +101,6 @@ bool GERBER_FILE_IMAGE::LoadGerberFile( const wxString& aFullFileName ) m_FileName = aFullFileName; - wxString path = wxPathOnly( aFullFileName ); - - // This change is needed to load included files, if exists: - if( path != wxEmptyString ) - wxSetWorkingDirectory( path ); - LOCALE_IO toggleIo; wxString msg; diff --git a/include/bitmaps.h b/include/bitmaps.h index 14a7dffc31..a5de83bfab 100644 --- a/include/bitmaps.h +++ b/include/bitmaps.h @@ -169,6 +169,7 @@ EXTERN_BITMAP( gbr_select_mode0_xpm ) EXTERN_BITMAP( gbr_select_mode1_xpm ) EXTERN_BITMAP( gbr_select_mode2_xpm ) EXTERN_BITMAP( gerbview_drill_file_xpm ) +EXTERN_BITMAP( gerber_job_file_xpm ) EXTERN_BITMAP( gerber_file_xpm ) EXTERN_BITMAP( gerbview_clear_layers_xpm ) EXTERN_BITMAP( gerbview_show_negative_objects_xpm ) diff --git a/include/plot_auxiliary_data.h b/include/plot_auxiliary_data.h index b909d7e27f..100acb3feb 100644 --- a/include/plot_auxiliary_data.h +++ b/include/plot_auxiliary_data.h @@ -151,6 +151,7 @@ private: bool m_isCopper; }; + /** * This helper function "normalize" aString and convert it to a Gerber std::string * Normalisation means convert any code > 0x7F and unautorized code to a hexadecimal @@ -161,6 +162,14 @@ private: */ std::string formatStringToGerber( const wxString& aString ); +/** + * This helper function make the inverse conversion of formatStringToGerber() + * It converts a "normalized" gerber string and convert it to a 16 bits sequence unicode + * @param aString = the wxString compliant with a gerber string format + * @return a wxString (unicode 16) from the gerber string + */ +wxString FormatStringFromGerber( const wxString& aString ); + /** * Generates the string to print to a gerber file, to set a net attribute * for a graphic object. diff --git a/include/wildcards_and_files_ext.h b/include/wildcards_and_files_ext.h index 5bd7fa1ca3..1a2f223f2d 100644 --- a/include/wildcards_and_files_ext.h +++ b/include/wildcards_and_files_ext.h @@ -51,6 +51,7 @@ extern const wxString ProjectFileExtension; extern const wxString SchematicFileExtension; extern const wxString NetlistFileExtension; extern const wxString GerberFileExtension; +extern const wxString GerberJobFileExtension; extern const wxString HtmlFileExtension; extern const wxString LegacyPcbFileExtension; diff --git a/kicad/tree_project_frame.cpp b/kicad/tree_project_frame.cpp index 4512d47f2a..2eb304d23e 100644 --- a/kicad/tree_project_frame.cpp +++ b/kicad/tree_project_frame.cpp @@ -75,9 +75,10 @@ static const wxChar* s_allowedExtensionsToList[] = wxT( "^.*\\.txt$" ), wxT( "^.*\\.pho$" ), // Gerber file (Old Kicad extension) wxT( "^.*\\.gbr$" ), // Gerber file - wxT( "^.*\\.gb[alops]$" ), // Gerber back (or bottom) layer file - wxT( "^.*\\.gt[alops]$" ), // Gerber front (or top) layer file - wxT( "^.*\\.g[0-9]{1,2}$" ), // Gerber inner layer file + wxT( "^.*\\.gbj$" ), // Gerber job file + wxT( "^.*\\.gb[alops]$" ), // Gerber back (or bottom) layer file (deprecated Protel ext) + wxT( "^.*\\.gt[alops]$" ), // Gerber front (or top) layer file (deprecated Protel ext) + wxT( "^.*\\.g[0-9]{1,2}$" ), // Gerber inner layer file (deprecated Protel ext) wxT( "^.*\\.odt$" ), wxT( "^.*\\.htm$" ), wxT( "^.*\\.html$" ), @@ -102,6 +103,9 @@ const wxChar TextFileExtension[] = wxT( "txt" ); // File wildcard definitions. const wxChar TextFileWildcard[] = wxT( "Text files (*.txt)|*.txt" ); +// Gerber file extension wildcard. +const wxString GerberFileExtensionWildCard( ".((gbr|gbj|(gb|gt)[alops])|pho)" ); + /** * @brief class TREE_PROJECT_FRAME is the frame that shows the tree list @@ -255,7 +259,7 @@ wxString TREE_PROJECT_FRAME::GetFileExt( TreeFileType type ) break; case TREE_GERBER: - ext = GerberFileExtension; + ext = GerberFileExtensionWildCard; break; case TREE_HTML: diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 85a1144786..a57c035f55 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -182,6 +182,7 @@ set( PCBNEW_EXPORTERS exporters/gendrill_Excellon_writer.cpp exporters/gendrill_file_writer_base.cpp exporters/gendrill_gerber_writer.cpp + exporters/gerber_jobfile_writer.cpp ) set( PCBNEW_MICROWAVE_SRCS diff --git a/pcbnew/dialogs/dialog_plot.cpp b/pcbnew/dialogs/dialog_plot.cpp index 8c89425215..efb7272690 100644 --- a/pcbnew/dialogs/dialog_plot.cpp +++ b/pcbnew/dialogs/dialog_plot.cpp @@ -31,9 +31,11 @@ #include <confirm.h> #include <wxPcbStruct.h> #include <pcbplot.h> +#include <gerber_jobfile_writer.h> #include <base_units.h> #include <macros.h> #include <reporter.h> +#include <wildcards_and_files_ext.h> #include <class_board.h> #include <wx/ffile.h> @@ -164,6 +166,9 @@ void DIALOG_PLOT::init_Dialog() // Grey out if m_useGerberX2Attributes is not checked m_useGerberNetAttributes->Enable( m_useGerberX2Attributes->GetValue() ); + // Option to generate a Gerber job file + m_generateGerberJobFile->SetValue( m_plotOpts.GetCreateGerberJobFile() ); + // Gerber precision for coordinates m_rbGerberFormat->SetSelection( m_plotOpts.GetGerberPrecision() == 5 ? 0 : 1 ); @@ -682,6 +687,8 @@ void DIALOG_PLOT::applyPlotSettings() tempOptions.SetUseGerberProtelExtensions( m_useGerberExtensions->GetValue() ); tempOptions.SetUseGerberAttributes( m_useGerberX2Attributes->GetValue() ); tempOptions.SetIncludeGerberNetlistInfo( m_useGerberNetAttributes->GetValue() ); + tempOptions.SetCreateGerberJobFile( m_generateGerberJobFile->GetValue() ); + tempOptions.SetGerberPrecision( m_rbGerberFormat->GetSelection() == 0 ? 5 : 6 ); LSET selectedLayers; @@ -740,6 +747,14 @@ void DIALOG_PLOT::Plot( wxCommandEvent& event ) { applyPlotSettings(); + // If no layer selected, we have nothing plotted. + // Prompt user if it happens because he could think there is a bug in Pcbnew. + if( !m_plotOpts.GetLayerSelection().any() ) + { + DisplayError( this, _( "No layer selected, Nothing to plot" ) ); + return; + } + // Create output directory if it does not exist (also transform it in // absolute form). Bail if it fails wxFileName outputDir = wxFileName::DirName( m_plotOpts.GetOutputDirectory() ); @@ -781,7 +796,7 @@ void DIALOG_PLOT::Plot( wxCommandEvent& event ) } /* If the scale factor edit controls are disabled or the scale value - * is 0, don't adjust the base scale factor. This fixes a bug when + * is 0, don't adjust the base scale factor. This fixes a bug when * the default scale adjust is initialized to 0 and saved in program * settings resulting in a divide by zero fault. */ @@ -807,6 +822,8 @@ void DIALOG_PLOT::Plot( wxCommandEvent& event ) DisplayInfoMessage( this, _( "Warning: Scale option set to a very large value" ) ); + GERBER_JOBFILE_WRITER jobfile_writer( m_board, &reporter ); + // Save the current plot options in the board m_parent->SetPlotSettings( m_plotOpts ); @@ -833,9 +850,9 @@ void DIALOG_PLOT::Plot( wxCommandEvent& event ) if( m_plotOpts.GetFormat() == PLOT_FORMAT_GERBER && m_useGerberExtensions->GetValue() ) file_ext = GetGerberProtelExtension( layer ); - BuildPlotFileName( &fn, outputDir.GetPath(), - m_board->GetLayerName( layer ), - file_ext ); + BuildPlotFileName( &fn, outputDir.GetPath(), m_board->GetLayerName( layer ), file_ext ); + wxString fullname = fn.GetFullName(); + jobfile_writer.AddGbrFile( layer, fullname ); LOCALE_IO toggle; @@ -861,10 +878,14 @@ void DIALOG_PLOT::Plot( wxCommandEvent& event ) } } - // If no layer selected, we have nothing plotted. - // Prompt user if it happens because he could think there is a bug in Pcbnew. - if( !m_plotOpts.GetLayerSelection().any() ) - DisplayError( this, _( "No layer selected" ) ); + if( m_plotOpts.GetFormat() == PLOT_FORMAT_GERBER && m_plotOpts.GetCreateGerberJobFile() ) + { + // Pick the basename from the board file + wxFileName fn( boardFilename ); + // Build gerber job file from basename + BuildPlotFileName( &fn, outputDir.GetPath(), "job", GerberJobFileExtension ); + jobfile_writer.CreateJobFile( fn.GetFullPath() ); + } } #include <drc_stuff.h> diff --git a/pcbnew/dialogs/dialog_plot_base.cpp b/pcbnew/dialogs/dialog_plot_base.cpp index 75ff3946cf..b9c9d9a859 100644 --- a/pcbnew/dialogs/dialog_plot_base.cpp +++ b/pcbnew/dialogs/dialog_plot_base.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Jul 2 2017) +// C++ code generated with wxFormBuilder (version May 6 2016) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! @@ -238,6 +238,11 @@ DIALOG_PLOT_BASE::DIALOG_PLOT_BASE( wxWindow* parent, wxWindowID id, const wxStr bSizerGbrOpt->Add( m_useGerberNetAttributes, 0, wxALL, 2 ); + m_generateGerberJobFile = new wxCheckBox( m_GerberOptionsSizer->GetStaticBox(), wxID_ANY, _("Generate Gerber job file"), wxDefaultPosition, wxDefaultSize, 0 ); + m_generateGerberJobFile->SetToolTip( _("Generate a Gerber job file that contains info about the board,\nand the list of generated Gerber plot files") ); + + bSizerGbrOpt->Add( m_generateGerberJobFile, 0, wxALL, 2 ); + m_subtractMaskFromSilk = new wxCheckBox( m_GerberOptionsSizer->GetStaticBox(), wxID_ANY, _("Subtract soldermask from silkscreen"), wxDefaultPosition, wxDefaultSize, 0 ); m_subtractMaskFromSilk->SetToolTip( _("Remove silkscreen from areas without soldermask") ); diff --git a/pcbnew/dialogs/dialog_plot_base.fbp b/pcbnew/dialogs/dialog_plot_base.fbp index 95ef900d15..9360357f0f 100644 --- a/pcbnew/dialogs/dialog_plot_base.fbp +++ b/pcbnew/dialogs/dialog_plot_base.fbp @@ -2958,6 +2958,94 @@ <event name="OnUpdateUI"></event> </object> </object> + <object class="sizeritem" expanded="1"> + <property name="border">2</property> + <property name="flag">wxALL</property> + <property name="proportion">0</property> + <object class="wxCheckBox" expanded="1"> + <property name="BottomDockable">1</property> + <property name="LeftDockable">1</property> + <property name="RightDockable">1</property> + <property name="TopDockable">1</property> + <property name="aui_layer"></property> + <property name="aui_name"></property> + <property name="aui_position"></property> + <property name="aui_row"></property> + <property name="best_size"></property> + <property name="bg"></property> + <property name="caption"></property> + <property name="caption_visible">1</property> + <property name="center_pane">0</property> + <property name="checked">0</property> + <property name="close_button">1</property> + <property name="context_help"></property> + <property name="context_menu">1</property> + <property name="default_pane">0</property> + <property name="dock">Dock</property> + <property name="dock_fixed">0</property> + <property name="docking">Left</property> + <property name="enabled">1</property> + <property name="fg"></property> + <property name="floatable">1</property> + <property name="font"></property> + <property name="gripper">0</property> + <property name="hidden">0</property> + <property name="id">wxID_ANY</property> + <property name="label">Generate Gerber job file</property> + <property name="max_size"></property> + <property name="maximize_button">0</property> + <property name="maximum_size"></property> + <property name="min_size"></property> + <property name="minimize_button">0</property> + <property name="minimum_size"></property> + <property name="moveable">1</property> + <property name="name">m_generateGerberJobFile</property> + <property name="pane_border">1</property> + <property name="pane_position"></property> + <property name="pane_size"></property> + <property name="permission">protected</property> + <property name="pin_button">1</property> + <property name="pos"></property> + <property name="resize">Resizable</property> + <property name="show">1</property> + <property name="size"></property> + <property name="style"></property> + <property name="subclass"></property> + <property name="toolbar_pane">0</property> + <property name="tooltip">Generate a Gerber job file that contains info about the board,
and the list of generated Gerber plot files</property> + <property name="validator_data_type"></property> + <property name="validator_style">wxFILTER_NONE</property> + <property name="validator_type">wxDefaultValidator</property> + <property name="validator_variable"></property> + <property name="window_extra_style"></property> + <property name="window_name"></property> + <property name="window_style"></property> + <event name="OnChar"></event> + <event name="OnCheckBox"></event> + <event name="OnEnterWindow"></event> + <event name="OnEraseBackground"></event> + <event name="OnKeyDown"></event> + <event name="OnKeyUp"></event> + <event name="OnKillFocus"></event> + <event name="OnLeaveWindow"></event> + <event name="OnLeftDClick"></event> + <event name="OnLeftDown"></event> + <event name="OnLeftUp"></event> + <event name="OnMiddleDClick"></event> + <event name="OnMiddleDown"></event> + <event name="OnMiddleUp"></event> + <event name="OnMotion"></event> + <event name="OnMouseEvents"></event> + <event name="OnMouseWheel"></event> + <event name="OnPaint"></event> + <event name="OnRightDClick"></event> + <event name="OnRightDown"></event> + <event name="OnRightUp"></event> + <event name="OnSetFocus"></event> + <event name="OnSize"></event> + <event name="OnUpdateUI"></event> + </object> + </object> <object class="sizeritem" expanded="0"> <property name="border">2</property> <property name="flag">wxALL</property> diff --git a/pcbnew/dialogs/dialog_plot_base.h b/pcbnew/dialogs/dialog_plot_base.h index d0d5043088..01aaeded78 100644 --- a/pcbnew/dialogs/dialog_plot_base.h +++ b/pcbnew/dialogs/dialog_plot_base.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Jul 2 2017) +// C++ code generated with wxFormBuilder (version May 6 2016) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! @@ -94,6 +94,7 @@ class DIALOG_PLOT_BASE : public DIALOG_SHIM wxCheckBox* m_useGerberExtensions; wxCheckBox* m_useGerberX2Attributes; wxCheckBox* m_useGerberNetAttributes; + wxCheckBox* m_generateGerberJobFile; wxCheckBox* m_subtractMaskFromSilk; wxRadioBox* m_rbGerberFormat; wxStaticBoxSizer* m_HPGLOptionsSizer; diff --git a/pcbnew/exporters/gerber_jobfile_writer.cpp b/pcbnew/exporters/gerber_jobfile_writer.cpp new file mode 100644 index 0000000000..da132f4bb0 --- /dev/null +++ b/pcbnew/exporters/gerber_jobfile_writer.cpp @@ -0,0 +1,388 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2017 Jean_Pierre Charras <jp.charras at wanadoo.fr> + * Copyright (C) 1992-2017 KiCad Developers, see change_log.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 + */ + +/** + * @file gendrill_gerber_writer.cpp + * @brief Functions to create drill files in gerber X2 format. + */ + +#include <fctsys.h> + +#include <vector> + +#include <plot_common.h> +#include <wxPcbStruct.h> +#include <build_version.h> + +#include <class_board.h> +#include <class_zone.h> +#include <class_module.h> + +#include <pcbplot.h> +#include <pcbnew.h> +#include <gerber_jobfile_writer.h> +#include <wildcards_and_files_ext.h> +#include <reporter.h> +#include <plot_auxiliary_data.h> + + +GERBER_JOBFILE_WRITER::GERBER_JOBFILE_WRITER( BOARD* aPcb, REPORTER* aReporter ) +{ + m_pcb = aPcb; + m_reporter = aReporter; + m_conversionUnits = 1.0 / IU_PER_MM; // Gerber units = mm +} + +enum ONSIDE GERBER_JOBFILE_WRITER::hasSilkLayers() +{ + int flag = SIDE_NONE; + + for( unsigned ii = 0; ii < m_params.m_LayerId.size(); ii++ ) + { + if( m_params.m_LayerId[ii] == B_SilkS ) + flag |= SIDE_BOTTOM; + + if( m_params.m_LayerId[ii] == F_SilkS ) + flag |= SIDE_TOP; + } + + return (enum ONSIDE)flag; +} + + +enum ONSIDE GERBER_JOBFILE_WRITER::hasSolderMasks() +{ + int flag = SIDE_NONE; + + for( unsigned ii = 0; ii < m_params.m_LayerId.size(); ii++ ) + { + if( m_params.m_LayerId[ii] == B_Mask ) + flag |= SIDE_BOTTOM; + + if( m_params.m_LayerId[ii] == F_Mask ) + flag |= SIDE_TOP; + } + + return (enum ONSIDE)flag; +} + +const char* GERBER_JOBFILE_WRITER::sideKeyValue( enum ONSIDE aValue ) +{ + // return the key associated to sides used for some layers + // "No, TopOnly, BotOnly or Both" + const char* value = nullptr; + + switch( aValue ) + { + case SIDE_NONE: + value = "No"; break; + + case SIDE_TOP: + value = "TopOnly"; break; + + case SIDE_BOTTOM: + value = "BotOnly"; break; + + case SIDE_BOTH: + value = "Both"; break; + + } + + return value; +} + + +extern void BuildGerberX2Header( const BOARD *aBoard, wxArrayString& aHeader ); + + +bool GERBER_JOBFILE_WRITER::CreateJobFile( const wxString& aFullFilename ) +{ + // Note: in Gerber job file, dimensions are in mm, and are floating numbers + FILE* jobFile = wxFopen( aFullFilename, "wt" ); + + wxString msg; + + if( jobFile == nullptr ) + { + if( m_reporter ) + { + msg.Printf( _( "Unable to create job file '%s'" ), aFullFilename ); + m_reporter->Report( msg, REPORTER::RPT_ERROR ); + } + return false; + } + + LOCALE_IO dummy; + + // output the job file header + bool hasInnerLayers = m_pcb->GetCopperLayerCount() > 2; + wxArrayString header; + + fputs( "G04 Gerber job file with board parameters*\n" + "%TF.FileFunction,JobInfo*%\n" + "%TF.Part,SinglePCB*%\n", jobFile ); + fputs( "G04 Single PCB fabrication instructions*\n", jobFile ); + + BuildGerberX2Header( m_pcb, header ); + + for( unsigned ii = 0; ii < header.GetCount(); ii++ ) + { + if( header[ii].Contains( "TF.SameCoordinates" ) ) + continue; // This attribute is not useful in job file, skip it + + fputs( header[ii], jobFile ); + fputs( "\n", jobFile ); + } + + + fputs( "%MOMM*%\n", jobFile ); + + fputs( "G04 Overall board parameters*\n", jobFile ); + // output the bord size in mm: + EDA_RECT brect = m_pcb->GetBoardEdgesBoundingBox(); + fprintf( jobFile, "%%TJ.B.Size.X,%.3f*%%\n", brect.GetWidth()*m_conversionUnits ); + fprintf( jobFile, "%%TJ.B.Size.Y,%.3f*%%\n", brect.GetHeight()*m_conversionUnits ); + + // number of copper layers + fprintf( jobFile, "%%TJ.B.LayerNum,%d*%%\n", m_pcb->GetCopperLayerCount() ); + + // Board thickness + fprintf( jobFile, "%%TJ.B.Overall.Thickness,%.3f*%%\n", + m_pcb->GetDesignSettings().GetBoardThickness()*m_conversionUnits ); + + fprintf( jobFile, "%%TJ.B.Legend.Present,%s*%%\n", sideKeyValue( hasSilkLayers() ) ); + + fprintf( jobFile, "%%TJ.B.SolderMask.Present,%s*%%\n", sideKeyValue( hasSolderMasks() ) ); + + // Job file support a few design rules: + fputs( "G04 board design rules*\n", jobFile ); + const BOARD_DESIGN_SETTINGS& dsnSettings = m_pcb->GetDesignSettings(); + NETCLASS defaultNC = *dsnSettings.GetDefault(); + int minclearanceOuter = defaultNC.GetClearance(); + + // Search a smaller clearance in other net classes, if any. + for( NETCLASSES::const_iterator it = dsnSettings.m_NetClasses.begin(); + it != dsnSettings.m_NetClasses.end(); + ++it ) + { + NETCLASS netclass = *it->second; + minclearanceOuter = std::min( minclearanceOuter, netclass.GetClearance() ); + } + + // job file knows different clearance types. + // Kicad knows only one clearance for pads and tracks + // However, pads can have a specific clearance defined for a pad or a footprint, + // and min clearance can be dependent on layers. + // Search for a minimal pad clearance: + int minPadClearanceOuter = defaultNC.GetClearance(); + int minPadClearanceInner = defaultNC.GetClearance(); + + for( MODULE* module : m_pcb->Modules() ) + { + for( auto& pad : module->Pads() ) + { + if( ( pad->GetLayerSet() & LSET::InternalCuMask() ).any() ) + minPadClearanceInner = std::min( minPadClearanceInner, pad->GetClearance() ); + + if( ( pad->GetLayerSet() & LSET::ExternalCuMask() ).any() ) + minPadClearanceOuter = std::min( minPadClearanceOuter, pad->GetClearance() ); + } + } + + + fprintf( jobFile, "%%TJ.D.PadToPad.Outer,%.3f*%%\n", minPadClearanceOuter*m_conversionUnits ); + + if( hasInnerLayers ) + fprintf( jobFile, "%%TJ.D.PadToPad.Inner,%.3f*%%\n", minPadClearanceInner*m_conversionUnits ); + + fprintf( jobFile, "%%TJ.D.PadToTrack.Outer,%.3f*%%\n", minPadClearanceOuter*m_conversionUnits ); + + if( hasInnerLayers ) + fprintf( jobFile, "%%TJ.D.PadToTrack.Inner,%.3f*%%\n", minPadClearanceInner*m_conversionUnits ); + + // Until this is changed in Kicad, use the same value for internal tracks + int minclearanceInner = minclearanceOuter; + + fprintf( jobFile, "%%TJ.D.TrackToTrack.Outer,%.3f*%%\n", minclearanceOuter*m_conversionUnits ); + + if( hasInnerLayers ) + fprintf( jobFile, "%%TJ.D.TrackToTrack.Inner,%.3f*%%\n", minclearanceInner*m_conversionUnits ); + + // Output the minimal track width + int mintrackWidthOuter = INT_MAX; + int mintrackWidthInner = INT_MAX; + + for( TRACK* track : m_pcb->Tracks() ) + { + if( track->Type() == PCB_VIA_T ) + continue; + + if( track->GetLayer() == B_Cu || track->GetLayer() == F_Cu ) + mintrackWidthOuter = std::min( mintrackWidthOuter, track->GetWidth() ); + else + mintrackWidthInner = std::min( mintrackWidthInner, track->GetWidth() ); + } + + if( mintrackWidthOuter != INT_MAX ) + fprintf( jobFile, "%%TJ.D.MinLineWidth.Outer,%.3f*%%\n", mintrackWidthOuter*m_conversionUnits ); + + if( mintrackWidthInner != INT_MAX ) + fprintf( jobFile, "%%TJ.D.MinLineWidth.Inner,%.3f*%%\n", mintrackWidthInner*m_conversionUnits ); + + // Output the minimal zone to xx clearance + // Note: zones can have a zone clearance set to 0 + // if happens, the actual zone clearance is the clearance of its class + minclearanceOuter = INT_MAX; + minclearanceInner = INT_MAX; + + for( int ii = 0; ii < m_pcb->GetAreaCount(); ii++ ) + { + ZONE_CONTAINER* zone = m_pcb->GetArea( ii ); + + if( zone->GetIsKeepout() || !zone->IsOnCopperLayer() ) + continue; + + int zclerance = zone->GetClearance(); + + if( zone->GetLayer() == B_Cu || zone->GetLayer() == F_Cu ) + minclearanceOuter = std::min( minclearanceOuter, zclerance ); + else + minclearanceInner = std::min( minclearanceInner, zclerance ); + } + + if( minclearanceOuter != INT_MAX ) + fprintf( jobFile, "%%TJ.D.TrackToRegion.Outer,%.3f*%%\n", minclearanceOuter*m_conversionUnits ); + + if( hasInnerLayers && minclearanceInner != INT_MAX ) + fprintf( jobFile, "%%TJ.D.TrackToRegion.Inner,%.3f*%%\n", minclearanceInner*m_conversionUnits ); + + if( minclearanceOuter != INT_MAX ) + fprintf( jobFile, "%%TJ.D.RegionToRegion.Outer,%.3f*%%\n", minclearanceOuter*m_conversionUnits ); + + if( hasInnerLayers && minclearanceInner != INT_MAX ) + fprintf( jobFile, "%%TJ.D.RegionToRegion.Inner,%.3f*%%\n", minclearanceInner*m_conversionUnits ); + + // output the gerber file list: + fputs( "G04 Layer Structure*\n", jobFile ); + + for( unsigned ii = 0; ii < m_params.m_GerberFileList.GetCount(); ii ++ ) + { + wxString& name = m_params.m_GerberFileList[ii]; + PCB_LAYER_ID layer = m_params.m_LayerId[ii]; + wxString gbr_layer_id; + bool skip_file = false; // true to skip files which should not be in job file + const char* polarity = "Positive"; + + if( layer <= B_Cu ) + { + gbr_layer_id = "Copper,L"; + + if( layer == B_Cu ) + gbr_layer_id << m_pcb->GetCopperLayerCount(); + else + gbr_layer_id << layer+1; + + gbr_layer_id << ","; + + if( layer == B_Cu ) + gbr_layer_id << "Bottom"; + else if( layer == F_Cu ) + gbr_layer_id << "Top"; + else + gbr_layer_id << "Inner"; + } + + else + { + switch( layer ) + { + case B_Adhes: + gbr_layer_id = "Glue,Bottom"; break; + case F_Adhes: + gbr_layer_id = "Glue,Top"; break; + + case B_Paste: + gbr_layer_id = "SolderPaste,Bottom"; break; + case F_Paste: + gbr_layer_id = "SolderPaste,Top"; break; + + case B_SilkS: + gbr_layer_id = "Legend,Bottom"; break; + case F_SilkS: + gbr_layer_id = "Legend,Top"; break; + + case B_Mask: + gbr_layer_id = "SolderMask,Bottom"; polarity = "Negative"; break; + case F_Mask: + gbr_layer_id = "SolderMask,Top"; polarity = "Negative"; break; + + case Edge_Cuts: + gbr_layer_id = "Profile"; break; + + case B_Fab: + gbr_layer_id = "AssemblyDrawing,Bottom"; break; + case F_Fab: + gbr_layer_id = "AssemblyDrawing,Top"; break; + + case Dwgs_User: + case Cmts_User: + case Eco1_User: + case Eco2_User: + case Margin: + case B_CrtYd: + case F_CrtYd: + skip_file = true; break; + + default: + skip_file = true; + m_reporter->Report( "Unexpected layer id in job file", + REPORTER::RPT_ERROR ); + break; + } + } + + if( !skip_file ) + { + // name can contain non ASCII7 chars. + // Only ASCII7 chars are accepted in gerber files. others must be converted to + // a gerber hexa sequence. + std::string strname = formatStringToGerber( name ); + fprintf( jobFile, "%%TJ.L.\"%s\",%s,%s*%%\n", TO_UTF8( gbr_layer_id ), + polarity, strname.c_str() ); + } + } + + // Close job file + fputs( "M02*\n", jobFile ); + + fclose( jobFile ); + + if( m_reporter ) + { + msg.Printf( _( "Create Gerber job file '%s'" ), aFullFilename ); + m_reporter->Report( msg, REPORTER::RPT_ACTION ); + } + + return true; +} diff --git a/pcbnew/exporters/gerber_jobfile_writer.h b/pcbnew/exporters/gerber_jobfile_writer.h new file mode 100644 index 0000000000..f5f24fa9fb --- /dev/null +++ b/pcbnew/exporters/gerber_jobfile_writer.h @@ -0,0 +1,125 @@ +/** + * @file gerber_jobfile_writer.h + * @brief Classes used in drill files, map files and report files generation. + */ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2017 Jean_Pierre Charras <jp.charras at wanadoo.fr> + * Copyright (C) 1992-2017 KiCad Developers, see change_log.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 GERBER_JOBFILE_WRITER_H +#define GERBER_JOBFILE_WRITER_H + + +// A helper enum to handle sides of some layers (silk, mask) +enum ONSIDE +{ + SIDE_NONE = 0, // layers not present + SIDE_TOP = 1, // top layer only + SIDE_BOTTOM = 2, // bottom layer only + SIDE_BOTH = SIDE_TOP|SIDE_BOTTOM // both layers +}; + +class BOARD; + +/** + * class JOBFILE_PARAMS store the list of parameters written in Gerber job file + * especialy list of .gbr filenames and the corresponding layer id belonging the job + */ +class JOBFILE_PARAMS +{ +public: + wxArrayString m_GerberFileList; // the list of gerber filenames (without path) + std::vector<PCB_LAYER_ID> m_LayerId; // the list of corresponding layer id +}; + + +/** + * GERBER_JOBFILE_WRITER is a class used to create Gerber job file + * a Gerber job file stores info to make a board: + * list of gerber files + * info about the board itsel: + * size, number of copper layers + * thickness of the board, copper and dielectric + * and some other info (colors, finish type ...) + * + * note: dimensions are always in mm in Kicad job file (can be also in inches in a job file) + * and they are in floating point notation + */ +class GERBER_JOBFILE_WRITER +{ +public: + GERBER_JOBFILE_WRITER( BOARD* aPcb, REPORTER* aReporter = nullptr ); + + virtual ~GERBER_JOBFILE_WRITER() + { + } + + /** + * add a gerber file name and type in job file list + * @param aLayer is the PCB_LAYER_ID corresponding to the gerber file + * @param aFilename is the filename (without path) of the gerber file + */ + void AddGbrFile( PCB_LAYER_ID aLayer, wxString& aFilename ) + { + m_params.m_GerberFileList.Add( aFilename ); + m_params.m_LayerId.push_back( aLayer ); + } + + /** + * Creates an Excellon drill file + * @param aFullFilename = the full filename + * @param aParams = true for a NPTH file, false for a PTH file + * @return true, or false if the file cannot be created + */ + bool CreateJobFile( const wxString& aFullFilename ); + +private: + /** @return SIDE_NONE if no silk screen layer is in list + * SIDE_TOP if top silk screen layer is in list + * SIDE_BOTTOM if bottom silk screen layer is in list + * SIDE_BOTH if top and bottom silk screen layers are in list + */ + enum ONSIDE hasSilkLayers(); + + /** @return SIDE_NONE if no soldermask layer is in list + * SIDE_TOP if top soldermask layer is in list + * SIDE_BOTTOM if bottom soldermask layer is in list + * SIDE_BOTH if top and bottom soldermask layers are in list + */ + enum ONSIDE hasSolderMasks(); + + /** @return the key associated to sides used for some layers + * No TopOnly BotOnly Both + */ + const char* sideKeyValue( enum ONSIDE aValue ); + + +private: + BOARD* m_pcb; // The board + REPORTER* m_reporter; // a reporter for messages (can be null) + JOBFILE_PARAMS m_params; // the list of various prms and data to write in a job file + double m_conversionUnits; // scaling factor to convert brd units to gerber units (mm) +}; + +#endif // #ifndef GERBER_JOBFILE_WRITER_H diff --git a/pcbnew/pcb_plot_params.cpp b/pcbnew/pcb_plot_params.cpp index 5ae43b2e18..2e153b3308 100644 --- a/pcbnew/pcb_plot_params.cpp +++ b/pcbnew/pcb_plot_params.cpp @@ -82,6 +82,7 @@ PCB_PLOT_PARAMS::PCB_PLOT_PARAMS() m_useGerberProtelExtensions = false; m_useGerberAttributes = false; m_includeGerberNetlistInfo = false; + m_createGerberJobFile = false; m_gerberPrecision = gbrDefaultPrecision; m_excludeEdgeLayer = true; m_lineWidth = g_DrawDefaultLineThickness; @@ -146,14 +147,11 @@ void PCB_PLOT_PARAMS::Format( OUTPUTFORMATTER* aFormatter, aFormatter->Print( aNestLevel+1, "(%s %s)\n", getTokenName( T_usegerberextensions ), m_useGerberProtelExtensions ? trueStr : falseStr ); - if( m_useGerberAttributes ) // save this option only if active, - // to avoid incompatibility with older Pcbnew version - { - aFormatter->Print( aNestLevel+1, "(%s %s)\n", getTokenName( T_usegerberattributes ), trueStr ); + aFormatter->Print( aNestLevel+1, "(%s %s)\n", getTokenName( T_usegerberattributes ), trueStr ); - if( GetIncludeGerberNetlistInfo() ) - aFormatter->Print( aNestLevel+1, "(%s %s)\n", getTokenName( T_usegerberadvancedattributes ), trueStr ); - } + aFormatter->Print( aNestLevel+1, "(%s %s)\n", getTokenName( T_usegerberadvancedattributes ), trueStr ); + + aFormatter->Print( aNestLevel+1, "(%s %s)\n", getTokenName( T_creategerberjobfile ), trueStr ); if( m_gerberPrecision != gbrDefaultPrecision ) // save this option only if it is not the default value, // to avoid incompatibility with older Pcbnew version @@ -228,6 +226,8 @@ bool PCB_PLOT_PARAMS::IsSameAs( const PCB_PLOT_PARAMS &aPcbPlotParams, bool aCom return false; if( m_useGerberAttributes && m_includeGerberNetlistInfo != aPcbPlotParams.m_includeGerberNetlistInfo ) return false; + if( m_createGerberJobFile != aPcbPlotParams.m_createGerberJobFile ) + return false; if( m_gerberPrecision != aPcbPlotParams.m_gerberPrecision ) return false; if( m_excludeEdgeLayer != aPcbPlotParams.m_excludeEdgeLayer ) @@ -392,6 +392,10 @@ void PCB_PLOT_PARAMS_PARSER::Parse( PCB_PLOT_PARAMS* aPcbPlotParams ) aPcbPlotParams->m_includeGerberNetlistInfo = parseBool(); break; + case T_creategerberjobfile: + aPcbPlotParams->m_createGerberJobFile = parseBool(); + break; + case T_gerberprecision: aPcbPlotParams->m_gerberPrecision = parseInt( gbrDefaultPrecision-1, gbrDefaultPrecision); diff --git a/pcbnew/pcb_plot_params.h b/pcbnew/pcb_plot_params.h index 6d0e2fca12..cf3e6e082a 100644 --- a/pcbnew/pcb_plot_params.h +++ b/pcbnew/pcb_plot_params.h @@ -108,6 +108,9 @@ private: /// Include netlist info (only in Gerber X2 format) (chapter ? in revision ?) bool m_includeGerberNetlistInfo; + /// generate the auxiliary "job file" in gerber format + bool m_createGerberJobFile; + /// precision of coordinates in Gerber files: accepted 5 or 6 /// when units are in mm (6 or 7 in inches, but Pcbnew uses mm). /// 6 is the internal resolution of Pcbnew, but not alwys accepted by board maker @@ -245,6 +248,9 @@ public: void SetIncludeGerberNetlistInfo( bool aUse ) { m_includeGerberNetlistInfo = aUse; } bool GetIncludeGerberNetlistInfo() const { return m_includeGerberNetlistInfo; } + void SetCreateGerberJobFile( bool aCreate ) { m_createGerberJobFile = aCreate; } + bool GetCreateGerberJobFile() const { return m_createGerberJobFile; } + void SetUseGerberProtelExtensions( bool aUse ) { m_useGerberProtelExtensions = aUse; } bool GetUseGerberProtelExtensions() const { return m_useGerberProtelExtensions; } diff --git a/pcbnew/pcbplot.cpp b/pcbnew/pcbplot.cpp index 6ddcb50129..2fea89e650 100644 --- a/pcbnew/pcbplot.cpp +++ b/pcbnew/pcbplot.cpp @@ -270,6 +270,102 @@ static wxString& makeStringCompatX1( wxString& aText, bool aUseX1CompatibilityMo } +void BuildGerberX2Header( const BOARD *aBoard, wxArrayString& aHeader ) +{ + wxString text; + + // Creates the TF,.GenerationSoftware. Format is: + // %TF,.GenerationSoftware,<vendor>,<application name>[,<application version>]*% + text.Printf( wxT( "%%TF.GenerationSoftware,KiCad,Pcbnew,%s*%%" ), GetBuildVersion() ); + aHeader.Add( text ); + + // creates the TF.CreationDate ext: + // The attribute value must conform to the full version of the ISO 8601 + // date and time format, including time and time zone. Note that this is + // the date the Gerber file was effectively created, + // not the time the project of PCB was started + wxDateTime date( wxDateTime::GetTimeNow() ); + // Date format: see http://www.cplusplus.com/reference/ctime/strftime + wxString msg = date.Format( wxT( "%z" ) ); // Extract the time zone offset + // The time zone offset format is + (or -) mm or hhmm (mm = number of minutes, hh = number of hours) + // we want +(or -) hh:mm + if( msg.Len() > 3 ) + msg.insert( 3, ":", 1 ), + text.Printf( wxT( "%%TF.CreationDate,%s%s*%%" ), GetChars( date.FormatISOCombined() ), GetChars( msg ) ); + aHeader.Add( text ); + + // Creates the TF,.ProjectId. Format is (from Gerber file format doc): + // %TF.ProjectId,<project id>,<project GUID>,<revision id>*% + // <project id> is the name of the project, restricted to basic ASCII symbols only, + // and comma not accepted + // All illegal chars will be replaced by underscore + // <project GUID> is a 32 hexadecimal digits string which is an unique id of a project. + // This is a random 128-bit number expressed in 32 hexadecimal digits. + // See en.wikipedia.org/wiki/GUID for more information + // However Kicad does not handle such a project GUID, so it is built from the board name + // Rem: <project id> accepts only ASCII 7 code (only basic ASCII codes are allowed in gerber files). + wxFileName fn = aBoard->GetFileName(); + msg = fn.GetFullName(); + wxString guid; + + // Build a 32 digits GUID from the board name: + for( unsigned ii = 0; ii < msg.Len(); ii++ ) + { + int cc1 = int( msg[ii] ) & 0x0F; + int cc2 = ( int( msg[ii] ) >> 4) & 0x0F; + guid << wxString::Format( wxT( "%X%X" ), cc2, cc1 ); + + if( guid.Len() >= 32 ) + break; + } + + // guid has 32 digits, so add missing digits + int cnt = 32 - guid.Len(); + + if( cnt > 0 ) + guid.Append( '0', cnt ); + + // build the <project id> string: this is the board short filename (without ext) + // and all non ASCII chars and comma are replaced by '_' + msg = fn.GetName(); + msg.Replace( wxT( "," ), wxT( "_" ) ); + + // build the <rec> string. All non ASCII chars and comma are replaced by '_' + wxString rev = ((BOARD*)aBoard)->GetTitleBlock().GetRevision(); + rev.Replace( wxT( "," ), wxT( "_" ) ); + + if( rev.IsEmpty() ) + rev = wxT( "rev?" ); + + text.Printf( wxT( "%%TF.ProjectId,%s,%s,%s*%%" ), msg.ToAscii(), GetChars( guid ), rev.ToAscii() ); + aHeader.Add( text ); + + // Add the TF.SameCoordinates, that specify all gerber files uses the same + // origin and orientation, and the registration between files is OK. + // The parameter of TF.SameCoordinates is a string that is common + // to all files using the same registration and has no special meaning: + // this is just a key + // Because there is no mirroring/rotation in Kicad, only the plot offset origin + // can create incorrect registration. + // So we create a key from plot offset options. + // and therefore for a given board, all Gerber files having the same key have the same + // plot origin and use the same registration + // + // Currently the key is "Original" when using absolute Pcbnew coordinates, + // and te PY ans PY position od auxiliary axis, when using it. + // Please, if absolute Pcbnew coordinates, one day, are set by user, change the way + // the key is built to ensure file only using the *same* axis have the same key. + wxString registration_id = "Original"; + wxPoint auxOrigin = aBoard->GetAuxOrigin(); + + if( aBoard->GetPlotOptions().GetUseAuxOrigin() && auxOrigin.x && auxOrigin.y ) + registration_id.Printf( "PX%xPY%x", auxOrigin.x, auxOrigin.y ); + + text.Printf( "%%TF.SameCoordinates,%s*%%", registration_id.GetData() ); + aHeader.Add( text ); +} + + void AddGerberX2Header( PLOTTER * aPlotter, const BOARD *aBoard, bool aUseX1CompatibilityMode ) {