KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcbnew_jobs_handler.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2022 Mark Roszko <[email protected]>
5 * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include "pcbnew_jobs_handler.h"
23#include <jobs/job_fp_upgrade.h>
32#include <cli/exit_codes.h>
39#include <pgm_base.h>
40#include <pcbplot.h>
42#include <pad.h>
43#include <pcbnew_settings.h>
44#include <wx/crt.h>
45#include <wx/dir.h>
46#include <pcb_plot_svg.h>
52
54
55
57{
58 Register( "step",
59 std::bind( &PCBNEW_JOBS_HANDLER::JobExportStep, this, std::placeholders::_1 ) );
60 Register( "svg", std::bind( &PCBNEW_JOBS_HANDLER::JobExportSvg, this, std::placeholders::_1 ) );
61 Register( "dxf", std::bind( &PCBNEW_JOBS_HANDLER::JobExportDxf, this, std::placeholders::_1 ) );
62 Register( "pdf", std::bind( &PCBNEW_JOBS_HANDLER::JobExportPdf, this, std::placeholders::_1 ) );
63 Register( "gerber",
64 std::bind( &PCBNEW_JOBS_HANDLER::JobExportGerber, this, std::placeholders::_1 ) );
65 Register( "gerbers",
66 std::bind( &PCBNEW_JOBS_HANDLER::JobExportGerbers, this, std::placeholders::_1 ) );
67 Register( "drill",
68 std::bind( &PCBNEW_JOBS_HANDLER::JobExportDrill, this, std::placeholders::_1 ) );
69 Register( "pos", std::bind( &PCBNEW_JOBS_HANDLER::JobExportPos, this, std::placeholders::_1 ) );
70 Register( "fpupgrade",
71 std::bind( &PCBNEW_JOBS_HANDLER::JobExportFpUpgrade, this, std::placeholders::_1 ) );
72 Register( "fpsvg",
73 std::bind( &PCBNEW_JOBS_HANDLER::JobExportFpSvg, this, std::placeholders::_1 ) );
74}
75
76
78{
79 JOB_EXPORT_PCB_STEP* aStepJob = dynamic_cast<JOB_EXPORT_PCB_STEP*>( aJob );
80
81 if( aStepJob == nullptr )
83
84 if( aJob->IsCli() )
85 wxPrintf( _( "Loading board\n" ) );
86
87 BOARD* brd = LoadBoard( aStepJob->m_filename );
88
89 if( aStepJob->m_outputFile.IsEmpty() )
90 {
91 wxFileName fn = brd->GetFileName();
92 fn.SetName( fn.GetName() );
93 fn.SetExt( wxS( "step" ) );
94
95 aStepJob->m_outputFile = fn.GetFullName();
96 }
97
99 params.m_exportTracks = aStepJob->m_exportTracks;
101 params.m_includeDNP = aStepJob->m_includeDNP;
103 params.m_overwrite = aStepJob->m_overwrite;
104 params.m_substModels = aStepJob->m_substModels;
105 params.m_origin = VECTOR2D( aStepJob->m_xOrigin, aStepJob->m_yOrigin );
106 params.m_useDrillOrigin = aStepJob->m_useDrillOrigin;
107 params.m_useGridOrigin = aStepJob->m_useGridOrigin;
108 params.m_boardOnly = aStepJob->m_boardOnly;
109
110 EXPORTER_STEP stepExporter( brd, params );
111 stepExporter.m_outputFile = aStepJob->m_outputFile;
112
113 if( !stepExporter.Export() )
114 {
116 }
117
118 return CLI::EXIT_CODES::OK;
119}
120
121
123{
124 JOB_EXPORT_PCB_SVG* aSvgJob = dynamic_cast<JOB_EXPORT_PCB_SVG*>( aJob );
125
126 if( aSvgJob == nullptr )
128
129 PCB_PLOT_SVG_OPTIONS svgPlotOptions;
130 svgPlotOptions.m_blackAndWhite = aSvgJob->m_blackAndWhite;
131 svgPlotOptions.m_colorTheme = aSvgJob->m_colorTheme;
132 svgPlotOptions.m_outputFile = aSvgJob->m_outputFile;
133 svgPlotOptions.m_mirror = aSvgJob->m_mirror;
134 svgPlotOptions.m_pageSizeMode = aSvgJob->m_pageSizeMode;
135 svgPlotOptions.m_printMaskLayer = aSvgJob->m_printMaskLayer;
136 svgPlotOptions.m_plotFrame = aSvgJob->m_plotDrawingSheet;
137
138 if( aJob->IsCli() )
139 wxPrintf( _( "Loading board\n" ) );
140
141 BOARD* brd = LoadBoard( aSvgJob->m_filename );
142
143 if( aJob->IsCli() )
144 {
145 if( PCB_PLOT_SVG::Plot( brd, svgPlotOptions ) )
146 wxPrintf( _( "Successfully created svg file" ) );
147 else
148 wxPrintf( _( "Error creating svg file" ) );
149 }
150
151 return CLI::EXIT_CODES::OK;
152}
153
154
156{
157 JOB_EXPORT_PCB_DXF* aDxfJob = dynamic_cast<JOB_EXPORT_PCB_DXF*>( aJob );
158
159 if( aDxfJob == nullptr )
161
162 if( aJob->IsCli() )
163 wxPrintf( _( "Loading board\n" ) );
164
165 BOARD* brd = LoadBoard( aDxfJob->m_filename );
166
167 if( aDxfJob->m_outputFile.IsEmpty() )
168 {
169 wxFileName fn = brd->GetFileName();
170 fn.SetName( fn.GetName() );
171 fn.SetExt( GetDefaultPlotExtension( PLOT_FORMAT::DXF ) );
172
173 aDxfJob->m_outputFile = fn.GetFullName();
174 }
175
176 PCB_PLOT_PARAMS plotOpts;
177 plotOpts.SetFormat( PLOT_FORMAT::DXF );
178
180
182 {
183 plotOpts.SetDXFPlotUnits( DXF_UNITS::MILLIMETERS );
184 }
185 else
186 {
187 plotOpts.SetDXFPlotUnits( DXF_UNITS::INCHES );
188 }
189
190 plotOpts.SetPlotFrameRef( aDxfJob->m_plotBorderTitleBlocks );
191 plotOpts.SetPlotValue( aDxfJob->m_plotFootprintValues );
192 plotOpts.SetPlotReference( aDxfJob->m_plotRefDes );
193 plotOpts.SetLayerSelection( aDxfJob->m_printMaskLayer );
194
196 brd, &plotOpts, UNDEFINED_LAYER, aDxfJob->m_outputFile, wxEmptyString, wxEmptyString );
197
198 if( plotter )
199 {
200 PlotBoardLayers( brd, plotter, aDxfJob->m_printMaskLayer.SeqStackupBottom2Top(), plotOpts );
201 plotter->EndPlot();
202 }
203
204 delete plotter;
205
206 return CLI::EXIT_CODES::OK;
207}
208
209
211{
212 JOB_EXPORT_PCB_PDF* aPdfJob = dynamic_cast<JOB_EXPORT_PCB_PDF*>( aJob );
213
214 if( aPdfJob == nullptr )
216
217 if( aJob->IsCli() )
218 wxPrintf( _( "Loading board\n" ) );
219
220 BOARD* brd = LoadBoard( aPdfJob->m_filename );
221
222 if( aPdfJob->m_outputFile.IsEmpty() )
223 {
224 wxFileName fn = brd->GetFileName();
225 fn.SetName( fn.GetName() );
226 fn.SetExt( GetDefaultPlotExtension( PLOT_FORMAT::PDF ) );
227
228 aPdfJob->m_outputFile = fn.GetFullName();
229 }
230
231 PCB_PLOT_PARAMS plotOpts;
232 plotOpts.SetFormat( PLOT_FORMAT::PDF );
233
234 plotOpts.SetPlotFrameRef( aPdfJob->m_plotBorderTitleBlocks );
235 plotOpts.SetPlotValue( aPdfJob->m_plotFootprintValues );
236 plotOpts.SetPlotReference( aPdfJob->m_plotRefDes );
237
238 plotOpts.SetLayerSelection( aPdfJob->m_printMaskLayer );
239
240 SETTINGS_MANAGER& mgr = Pgm().GetSettingsManager();
241 plotOpts.SetColorSettings( mgr.GetColorSettings( aPdfJob->m_colorTheme ) );
242 plotOpts.SetBlackAndWhite( aPdfJob->m_blackAndWhite );
243
245 brd, &plotOpts, UNDEFINED_LAYER, aPdfJob->m_outputFile, wxEmptyString, wxEmptyString );
246
247 if( plotter )
248 {
249 PlotBoardLayers( brd, plotter, aPdfJob->m_printMaskLayer.SeqStackupBottom2Top(), plotOpts );
250 PlotInteractiveLayer( brd, plotter, plotOpts );
251 plotter->EndPlot();
252 }
253
254 delete plotter;
255
256 return CLI::EXIT_CODES::OK;
257}
258
259
261{
262 int exitCode = CLI::EXIT_CODES::OK;
263 JOB_EXPORT_PCB_GERBERS* aGerberJob = dynamic_cast<JOB_EXPORT_PCB_GERBERS*>( aJob );
264
265 if( aGerberJob == nullptr )
267
268 if( aJob->IsCli() )
269 wxPrintf( _( "Loading board\n" ) );
270
271 BOARD* brd = LoadBoard( aGerberJob->m_filename );
272 PCB_PLOT_PARAMS boardPlotOptions = brd->GetPlotOptions();
273 LSET plotOnAllLayersSelection = boardPlotOptions.GetPlotOnAllLayersSelection();
274 GERBER_JOBFILE_WRITER jobfile_writer( brd );
275
276 wxString fileExt;
277
278 if( aGerberJob->m_useBoardPlotParams )
279 {
280 aGerberJob->m_printMaskLayer = boardPlotOptions.GetLayerSelection();
281 aGerberJob->m_layersIncludeOnAll = boardPlotOptions.GetPlotOnAllLayersSelection();
282 }
283 else
284 {
285 // default to the board enabled layers
286 if( aGerberJob->m_printMaskLayer == 0 )
287 aGerberJob->m_printMaskLayer = brd->GetEnabledLayers();
288
289 if( aGerberJob->m_layersIncludeOnAllSet )
290 aGerberJob->m_layersIncludeOnAll = plotOnAllLayersSelection;
291 }
292
293 for( LSEQ seq = aGerberJob->m_printMaskLayer.UIOrder(); seq; ++seq )
294 {
295 LSEQ plotSequence;
296
297 // Base layer always gets plotted first.
298 plotSequence.push_back( *seq );
299
300 // Now all the "include on all" layers
301 for( LSEQ seqAll = aGerberJob->m_layersIncludeOnAll.UIOrder(); seqAll; ++seqAll )
302 {
303 // Don't plot the same layer more than once;
304 if( find( plotSequence.begin(), plotSequence.end(), *seqAll ) != plotSequence.end() )
305 continue;
306
307 plotSequence.push_back( *seqAll );
308 }
309
310 // Pick the basename from the board file
311 wxFileName fn( brd->GetFileName() );
312 PCB_LAYER_ID layer = *seq;
313 fileExt = GetGerberProtelExtension( layer );
314
315 PCB_PLOT_PARAMS plotOpts;
316
317 if( aGerberJob->m_useBoardPlotParams )
318 plotOpts = boardPlotOptions;
319 else
320 populateGerberPlotOptionsFromJob( plotOpts, aGerberJob );
321
322 BuildPlotFileName( &fn, aGerberJob->m_outputFile, brd->GetLayerName( layer ), fileExt );
323 wxString fullname = fn.GetFullName();
324
325 jobfile_writer.AddGbrFile( layer, fullname );
326
327 // We are feeding it one layer at the start here to silence a logic check
329 brd, &plotOpts, layer, fn.GetFullPath(), wxEmptyString, wxEmptyString );
330
331 if( plotter )
332 {
333 wxPrintf( _( "Plotted to '%s'.\n" ), fn.GetFullPath() );
334 PlotBoardLayers( brd, plotter, plotSequence, plotOpts );
335 plotter->EndPlot();
336 }
337 else
338 {
339 wxFprintf( stderr, _( "Failed to plot to '%s'.\n" ), fn.GetFullPath() );
341 }
342
343 delete plotter;
344 }
345
346 wxFileName fn( aGerberJob->m_filename );
347 // Build gerber job file from basename
348 BuildPlotFileName( &fn, aGerberJob->m_outputFile, wxT( "job" ), GerberJobFileExtension );
349 jobfile_writer.CreateJobFile( fn.GetFullPath() );
350
351 return exitCode;
352}
353
354
357{
358 aPlotOpts.SetFormat( PLOT_FORMAT::GERBER );
359
360 aPlotOpts.SetPlotFrameRef( aJob->m_plotBorderTitleBlocks );
361 aPlotOpts.SetPlotValue( aJob->m_plotFootprintValues );
362 aPlotOpts.SetPlotReference( aJob->m_plotRefDes );
363
365
366 // Always disable plot pad holes
367 aPlotOpts.SetDrillMarksType( DRILL_MARKS::NO_DRILL_SHAPE );
368
370 aPlotOpts.SetUseGerberX2format( aJob->m_useX2Format );
372 aPlotOpts.SetUseAuxOrigin( aJob->m_useAuxOrigin );
373
374 aPlotOpts.SetGerberPrecision( aJob->m_precision );
375}
376
377
379{
380 int exitCode = CLI::EXIT_CODES::OK;
381 JOB_EXPORT_PCB_GERBER* aGerberJob = dynamic_cast<JOB_EXPORT_PCB_GERBER*>( aJob );
382
383 if( aGerberJob == nullptr )
385
386 if( aJob->IsCli() )
387 wxPrintf( _( "Loading board\n" ) );
388
389 BOARD* brd = LoadBoard( aGerberJob->m_filename );
390
391 if( aGerberJob->m_outputFile.IsEmpty() )
392 {
393 wxFileName fn = brd->GetFileName();
394 fn.SetName( fn.GetName() );
395 fn.SetExt( GetDefaultPlotExtension( PLOT_FORMAT::GERBER ) );
396
397 aGerberJob->m_outputFile = fn.GetFullName();
398 }
399
400 PCB_PLOT_PARAMS plotOpts;
401 populateGerberPlotOptionsFromJob( plotOpts, aGerberJob );
402 plotOpts.SetLayerSelection( aGerberJob->m_printMaskLayer );
403
404 // We are feeding it one layer at the start here to silence a logic check
406 brd, &plotOpts, aGerberJob->m_printMaskLayer.Seq().front(), aGerberJob->m_outputFile,
407 wxEmptyString, wxEmptyString );
408
409 if( plotter )
410 {
411 PlotBoardLayers( brd, plotter, aGerberJob->m_printMaskLayer.SeqStackupBottom2Top(),
412 plotOpts );
413 plotter->EndPlot();
414 }
415 else
416 {
417 wxFprintf( stderr, _( "Failed to plot to '%s'.\n" ), aGerberJob->m_outputFile );
419 }
420
421 delete plotter;
422
423 return exitCode;
424}
425
428
429
431{
432 JOB_EXPORT_PCB_DRILL* aDrillJob = dynamic_cast<JOB_EXPORT_PCB_DRILL*>( aJob );
433
434 if( aDrillJob == nullptr )
436
437 if( aJob->IsCli() )
438 wxPrintf( _( "Loading board\n" ) );
439
440 BOARD* brd = LoadBoard( aDrillJob->m_filename );
441
442 std::unique_ptr<GENDRILL_WRITER_BASE> drillWriter;
443
445 {
446 drillWriter = std::make_unique<EXCELLON_WRITER>( brd );
447 }
448 else
449 {
450 drillWriter = std::make_unique<GERBER_WRITER>( brd );
451 }
452
453 VECTOR2I offset;
454
456 offset = VECTOR2I( 0, 0 );
457 else
458 offset = brd->GetDesignSettings().GetAuxOrigin();
459
460 PLOT_FORMAT mapFormat = PLOT_FORMAT::PDF;
461
462 switch( aDrillJob->m_mapFormat )
463 {
464 case JOB_EXPORT_PCB_DRILL::MAP_FORMAT::POSTSCRIPT: mapFormat = PLOT_FORMAT::POST; break;
465 case JOB_EXPORT_PCB_DRILL::MAP_FORMAT::GERBER_X2: mapFormat = PLOT_FORMAT::GERBER; break;
466 case JOB_EXPORT_PCB_DRILL::MAP_FORMAT::DXF: mapFormat = PLOT_FORMAT::DXF; break;
467 case JOB_EXPORT_PCB_DRILL::MAP_FORMAT::SVG: mapFormat = PLOT_FORMAT::SVG; break;
468 default:
469 case JOB_EXPORT_PCB_DRILL::MAP_FORMAT::PDF: mapFormat = PLOT_FORMAT::PDF; break;
470 }
471
473 {
475 switch( aDrillJob->m_zeroFormat )
476 {
479 break;
482 break;
485 break;
487 default:
489 break;
490 }
491
492 DRILL_PRECISION precision;
493
495 precision = precisionListForInches;
496 else
497 precision = precisionListForMetric;
498
499 EXCELLON_WRITER* excellonWriter = dynamic_cast<EXCELLON_WRITER*>( drillWriter.get() );
500
501 if( excellonWriter == nullptr )
503
504 excellonWriter->SetFormat( aDrillJob->m_drillUnits
506 zeroFmt, precision.m_Lhs, precision.m_Rhs );
507 excellonWriter->SetOptions( aDrillJob->m_excellonMirrorY,
508 aDrillJob->m_excellonMinimalHeader,
509 offset, aDrillJob->m_excellonCombinePTHNPTH );
510 excellonWriter->SetRouteModeForOvalHoles( aDrillJob->m_excellonOvalDrillRoute );
511 excellonWriter->SetMapFileFormat( mapFormat );
512
513 if( !excellonWriter->CreateDrillandMapFilesSet( aDrillJob->m_outputDir, true,
514 aDrillJob->m_generateMap, this ) )
515 {
517 }
518 }
520 {
521 GERBER_WRITER* gerberWriter = dynamic_cast<GERBER_WRITER*>( drillWriter.get() );
522
523 if( gerberWriter == nullptr )
525
526 // Set gerber precision: only 5 or 6 digits for mantissa are allowed
527 // (SetFormat() accept 5 or 6, and any other value set the precision to 5)
528 // the integer part precision is always 4, and units always mm
529 gerberWriter->SetFormat( aDrillJob->m_gerberPrecision );
530 gerberWriter->SetOptions( offset );
531 gerberWriter->SetMapFileFormat( mapFormat );
532
533 if( !gerberWriter->CreateDrillandMapFilesSet( aDrillJob->m_outputDir, true,
534 aDrillJob->m_generateMap, this ) )
535 {
537 }
538 }
539
540 return CLI::EXIT_CODES::OK;
541}
542
543
545{
546 JOB_EXPORT_PCB_POS* aPosJob = dynamic_cast<JOB_EXPORT_PCB_POS*>( aJob );
547
548 if( aPosJob == nullptr )
550
551 if( aJob->IsCli() )
552 wxPrintf( _( "Loading board\n" ) );
553
554 BOARD* brd = LoadBoard( aPosJob->m_filename );
555
556 if( aPosJob->m_outputFile.IsEmpty() )
557 {
558 wxFileName fn = brd->GetFileName();
559 fn.SetName( fn.GetName() );
560
562 fn.SetExt( FootprintPlaceFileExtension );
563 else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::CSV )
564 fn.SetExt( CsvFileExtension );
565 else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::GERBER )
566 fn.SetExt( GerberFileExtension );
567
568 aPosJob->m_outputFile = fn.GetFullName();
569 }
570
573 {
574 FILE* file = nullptr;
575 file = wxFopen( aPosJob->m_outputFile, wxS( "wt" ) );
576
577 if( file == nullptr )
579
580 std::string data;
581
582 bool frontSide = aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::FRONT
584
585 bool backSide = aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BACK
587
588 PLACE_FILE_EXPORTER exporter( brd,
590 aPosJob->m_smdOnly, aPosJob->m_excludeFootprintsWithTh,
591 frontSide, backSide,
594 aPosJob->m_negateBottomX );
595 data = exporter.GenPositionData();
596
597 fputs( data.c_str(), file );
598 fclose( file );
599 }
600 else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::GERBER )
601 {
602 PLACEFILE_GERBER_WRITER exporter( brd );
603
604 PCB_LAYER_ID gbrLayer = F_Cu;
605
606 if( aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BACK )
607 gbrLayer = B_Cu;
608
609 exporter.CreatePlaceFile( aPosJob->m_outputFile, gbrLayer, aPosJob->m_gerberBoardEdge );
610 }
611
612 return CLI::EXIT_CODES::OK;
613}
614
615extern FOOTPRINT* try_load_footprint( const wxFileName& aFileName, IO_MGR::PCB_FILE_T aFileType,
616 const wxString& aName );
617
618
620{
621 JOB_FP_UPGRADE* upgradeJob = dynamic_cast<JOB_FP_UPGRADE*>( aJob );
622
623 if( upgradeJob == nullptr )
625
626 if( aJob->IsCli() )
627 wxPrintf( _( "Loading footprint library\n" ) );
628
629 if( !upgradeJob->m_outputLibraryPath.IsEmpty() )
630 {
631 if( wxFile::Exists( upgradeJob->m_outputLibraryPath ) ||
632 wxDir::Exists( upgradeJob->m_outputLibraryPath) )
633 {
634 wxFprintf( stderr, _( "Output path must not conflict with existing path\n" ) );
636 }
637 }
638
639 PCB_PLUGIN pcb_io( CTL_FOR_LIBRARY );
640 FP_CACHE fpLib( &pcb_io, upgradeJob->m_libraryPath );
641
642 try
643 {
644 fpLib.Load();
645 }
646 catch(...)
647 {
648 wxFprintf( stderr, _( "Unable to load library\n" ) );
650 }
651
652 bool shouldSave = upgradeJob->m_force;
653
654 for( const auto& footprint : fpLib.GetFootprints() )
655 {
656 if( footprint.second->GetFootprint()->GetFileFormatVersionAtLoad() < SEXPR_BOARD_FILE_VERSION )
657 {
658 shouldSave = true;
659 }
660 }
661
662 if( shouldSave )
663 {
664 wxPrintf( _( "Saving footprint library\n" ) );
665
666 try
667 {
668 if( !upgradeJob->m_outputLibraryPath.IsEmpty() )
669 {
670 fpLib.SetPath( upgradeJob->m_outputLibraryPath );
671 }
672
673 fpLib.Save();
674 }
675 catch( ... )
676 {
677 wxFprintf( stderr, _( "Unable to save library\n" ) );
679 }
680 }
681 else
682 {
683 wxPrintf( _( "Footprint library was not updated\n" ) );
684 }
685
686 return CLI::EXIT_CODES::OK;
687}
688
689
691{
692 JOB_FP_EXPORT_SVG* svgJob = dynamic_cast<JOB_FP_EXPORT_SVG*>( aJob );
693
694 if( svgJob == nullptr )
696
697 if( aJob->IsCli() )
698 wxPrintf( _( "Loading footprint library\n" ) );
699
700 PCB_PLUGIN pcb_io( CTL_FOR_LIBRARY );
701 FP_CACHE fpLib( &pcb_io, svgJob->m_libraryPath );
702
703 try
704 {
705 fpLib.Load();
706 }
707 catch( ... )
708 {
709 wxFprintf( stderr, _( "Unable to load library\n" ) );
711 }
712
713 if( !svgJob->m_outputDirectory.IsEmpty() && !wxDir::Exists( svgJob->m_outputDirectory ) )
714 {
715 wxFileName::Mkdir( svgJob->m_outputDirectory );
716 }
717
718 int exitCode = CLI::EXIT_CODES::OK;
719
720 // Just plot all the symbols we can
721 FP_CACHE_FOOTPRINT_MAP& footprintMap = fpLib.GetFootprints();
722
723 bool singleFpPlotted = false;
724 for( FP_CACHE_FOOTPRINT_MAP::iterator it = footprintMap.begin(); it != footprintMap.end();
725 ++it )
726 {
727 const FOOTPRINT* fp = it->second->GetFootprint();
728 if( !svgJob->m_footprint.IsEmpty() )
729 {
730 if( fp->GetFPID().GetLibItemName().wx_str() != svgJob->m_footprint )
731 {
732 // skip until we find the right footprint
733 continue;
734 }
735 else
736 {
737 singleFpPlotted = true;
738 }
739 }
740
741 exitCode = doFpExportSvg( svgJob, fp );
742 if( exitCode != CLI::EXIT_CODES::OK )
743 break;
744 }
745
746 if( !svgJob->m_footprint.IsEmpty() && !singleFpPlotted )
747 wxFprintf( stderr, _( "The given footprint could not be found to export." ) );
748
749 return CLI::EXIT_CODES::OK;
750}
751
752
754{
755 // the hack for now is we create fake boards containing the footprint and plot the board
756 // until we refactor better plot api later
757 std::unique_ptr<BOARD> brd;
758 brd.reset( CreateEmptyBoard() );
759
760 FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( aFootprint->Clone() );
761
762 if( fp == nullptr )
764
765 fp->SetLink( niluuid );
766 fp->SetFlags( IS_NEW );
767 fp->SetParent( brd.get() );
768
769 for( PAD* pad : fp->Pads() )
770 {
771 pad->SetLocalRatsnestVisible( false );
772 pad->SetNetCode( 0 );
773 }
774
775 fp->SetOrientation( ANGLE_0 );
776 fp->SetPosition( VECTOR2I( 0, 0 ) );
777
778 brd->Add( fp, ADD_MODE::INSERT, true );
779
780 wxFileName outputFile;
781 outputFile.SetPath( aSvgJob->m_outputDirectory );
782 outputFile.SetName( aFootprint->GetFPID().GetLibItemName().wx_str() );
783 outputFile.SetExt( SVGFileExtension );
784
785 wxPrintf( _( "Plotting footprint '%s' to '%s'\n" ),
786 aFootprint->GetFPID().GetLibItemName().wx_str(), outputFile.GetFullPath() );
787
788
789 PCB_PLOT_SVG_OPTIONS svgPlotOptions;
790 svgPlotOptions.m_blackAndWhite = aSvgJob->m_blackAndWhite;
791 svgPlotOptions.m_colorTheme = aSvgJob->m_colorTheme;
792 svgPlotOptions.m_outputFile = outputFile.GetFullPath();
793 svgPlotOptions.m_mirror = false;
794 svgPlotOptions.m_pageSizeMode = 2; // board bounding box
795 svgPlotOptions.m_printMaskLayer = aSvgJob->m_printMaskLayer;
796 svgPlotOptions.m_plotFrame = false;
797
798 if( !PCB_PLOT_SVG::Plot( brd.get(), svgPlotOptions ) )
799 wxFprintf( stderr, _( "Error creating svg file" ) );
800
801
802 return CLI::EXIT_CODES::OK;
803}
804
805
806REPORTER& PCBNEW_JOBS_HANDLER::Report( const wxString& aText, SEVERITY aSeverity )
807{
808 if( aSeverity == RPT_SEVERITY_ERROR )
809 wxFprintf( stderr, wxS( "%s\n" ), aText );
810 else
811 wxPrintf( wxS( "%s\n" ), aText );
812
813 return *this;
814}
const VECTOR2I & GetAuxOrigin()
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:270
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:611
const wxString & GetFileName() const
Definition: board.h:307
const PCB_PLOT_PARAMS & GetPlotOptions() const
Definition: board.h:641
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:498
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:728
Helper to handle drill precision format in excellon files.
virtual bool EndPlot() override
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:123
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:100
Create Excellon drill, drill map, and drill report files.
void SetFormat(bool aMetric, ZEROS_FMT aZerosFmt=DECIMAL_FORMAT, int aLeftDigits=0, int aRightDigits=0)
Initialize internal parameters to match the given format.
bool CreateDrillandMapFilesSet(const wxString &aPlotDirectory, bool aGenDrill, bool aGenMap, REPORTER *aReporter=nullptr)
Create the full set of Excellon drill file for the board.
void SetOptions(bool aMirror, bool aMinimalHeader, const VECTOR2I &aOffset, bool aMerge_PTH_NPTH)
Initialize internal parameters to match drill options.
void SetRouteModeForOvalHoles(bool aUseRouteModeForOvalHoles)
double m_BoardOutlinesChainingEpsilon
Definition: exporter_step.h:70
wxString m_outputFile
Definition: exporter_step.h:83
void SetPosition(const VECTOR2I &aPos) override
Definition: footprint.cpp:1656
void SetLink(const KIID &aLink)
Definition: footprint.h:692
void SetOrientation(const EDA_ANGLE &aNewAngle)
Definition: footprint.cpp:1728
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: footprint.cpp:1386
PADS & Pads()
Definition: footprint.h:172
const LIB_ID & GetFPID() const
Definition: footprint.h:214
FP_CACHE_FOOTPRINT_MAP & GetFootprints()
Definition: pcb_plugin.h:209
void Save(FOOTPRINT *aFootprint=nullptr)
Save the footprint cache or a single footprint from it to disk.
Definition: pcb_plugin.cpp:82
void SetPath(const wxString &aPath)
Definition: pcb_plugin.cpp:241
void Load()
Definition: pcb_plugin.cpp:152
void SetMapFileFormat(PLOT_FORMAT aMapFmt)
Initialize the format for the drill map file.
GERBER_JOBFILE_WRITER is a class used to create Gerber job file a Gerber job file stores info to make...
bool CreateJobFile(const wxString &aFullFilename)
Creates a Gerber job file.
void AddGbrFile(PCB_LAYER_ID aLayer, wxString &aFilename)
add a gerber file name and type in job file list
virtual bool EndPlot() override
Used to create Gerber drill files.
bool CreateDrillandMapFilesSet(const wxString &aPlotDirectory, bool aGenDrill, bool aGenMap, REPORTER *aReporter=nullptr)
Create the full set of Excellon drill file for the board filenames are computed from the board name,...
void SetOptions(const VECTOR2I &aOffset)
Initialize internal parameters to match drill options.
void SetFormat(int aRightDigits=6)
Initialize internal parameters to match the given format.
PCB_FILE_T
The set of file types that the IO_MGR knows about, and for which there has been a plugin written.
Definition: io_mgr.h:54
void Register(const std::string &aJobTypeName, std::function< int(JOB *job)> aHandler)
wxString m_libraryPath
wxString m_outputLibraryPath
An simple container class that lets us dispatch output jobs to kifaces.
Definition: job.h:28
bool IsCli() const
Definition: job.h:35
const UTF8 & GetLibItemName() const
Definition: lib_id.h:102
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition: layer_ids.h:497
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:536
LSEQ UIOrder() const
Definition: lset.cpp:922
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:411
LSEQ SeqStackupBottom2Top() const
Return the sequence that is typical for a bottom-to-top stack-up.
Definition: lset.cpp:475
Definition: pad.h:59
int JobExportStep(JOB *aJob)
void populateGerberPlotOptionsFromJob(PCB_PLOT_PARAMS &aPlotOpts, JOB_EXPORT_PCB_GERBER *aJob)
int JobExportFpUpgrade(JOB *aJob)
int JobExportGerber(JOB *aJob)
int JobExportGerbers(JOB *aJob)
REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED) override
Report a string with a given severity.
int doFpExportSvg(JOB_FP_EXPORT_SVG *aSvgJob, const FOOTPRINT *aFootprint)
Parameters and options when plotting/printing a board.
void SetDrillMarksType(DRILL_MARKS aVal)
void SetLayerSelection(LSET aSelection)
void SetPlotReference(bool aFlag)
void SetUseGerberX2format(bool aUse)
void SetDXFPlotPolygonMode(bool aFlag)
void SetPlotFrameRef(bool aFlag)
LSET GetLayerSelection() const
LSET GetPlotOnAllLayersSelection() const
void SetDisableGerberMacros(bool aDisable)
void SetBlackAndWhite(bool blackAndWhite)
void SetGerberPrecision(int aPrecision)
void SetSubtractMaskFromSilk(bool aSubtract)
void SetPlotValue(bool aFlag)
void SetDXFPlotUnits(DXF_UNITS aUnit)
void SetColorSettings(COLOR_SETTINGS *aSettings)
void SetIncludeGerberNetlistInfo(bool aUse)
void SetUseAuxOrigin(bool aAux)
void SetFormat(PLOT_FORMAT aFormat)
static bool Plot(BOARD *aBoard, const PCB_PLOT_SVG_OPTIONS &aSvgPlotOptions)
A PLUGIN derivation for saving and loading Pcbnew s-expression formatted files.
Definition: pcb_plugin.h:261
virtual bool EndPlot() override
Used to create Gerber drill files.
int CreatePlaceFile(wxString &aFullFilename, PCB_LAYER_ID aLayer, bool aIncludeBrdEdges)
Create an pnp gerber file.
The ASCII format of the kicad place file is:
std::string GenPositionData()
build a string filled with the position data
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:71
COLOR_SETTINGS * GetColorSettings(const wxString &aName="user")
Retrieves a color settings object that applications can read colors from.
wxString wx_str() const
Definition: utf8.cpp:46
wxString GetDefaultPlotExtension(PLOT_FORMAT aFormat)
Returns the default plot extension for a format.
static DRILL_PRECISION precisionListForInches(2, 4)
static DRILL_PRECISION precisionListForMetric(3, 3)
#define _(s)
static constexpr EDA_ANGLE & ANGLE_0
Definition: eda_angle.h:429
#define IS_NEW
New item, just created.
Classes used in drill files, map files and report files generation.
Classes used in drill files, map files and report files generation.
Classes used to generate a Gerber job file in JSON.
Classes used in place file generation.
const std::string FootprintPlaceFileExtension
const std::string GerberJobFileExtension
const std::string SVGFileExtension
const std::string CsvFileExtension
const std::string GerberFileExtension
KIID niluuid(0)
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:59
@ B_Cu
Definition: layer_ids.h:95
@ UNDEFINED_LAYER
Definition: layer_ids.h:60
@ F_Cu
Definition: layer_ids.h:64
static const int OK
Definition: exit_codes.h:30
static const int ERR_INVALID_OUTPUT_CONFLICT
Definition: exit_codes.h:34
static const int ERR_UNKNOWN
Definition: exit_codes.h:32
#define SEXPR_BOARD_FILE_VERSION
Current s-expression file format version. 2 was the last legacy format version.
Definition: pcb_plugin.h:133
boost::ptr_map< wxString, FP_CACHE_ITEM > FP_CACHE_FOOTPRINT_MAP
Definition: pcb_plugin.h:186
#define CTL_FOR_LIBRARY
Format output for a footprint library instead of clipboard or BOARD.
Definition: pcb_plugin.h:158
static DRILL_PRECISION precisionListForInches(2, 4)
static DRILL_PRECISION precisionListForMetric(3, 3)
FOOTPRINT * try_load_footprint(const wxFileName &aFileName, IO_MGR::PCB_FILE_T aFileType, const wxString &aName)
Try to load a footprint, returning nullptr if the file couldn't be accessed.
BOARD * CreateEmptyBoard()
Construct a default BOARD with a temporary (no filename) project.
BOARD * LoadBoard(wxString &aFileName)
const wxString GetGerberProtelExtension(int aLayer)
Definition: pcbplot.cpp:42
void BuildPlotFileName(wxFileName *aFilename, const wxString &aOutputDir, const wxString &aSuffix, const wxString &aExtension)
Complete a plot filename.
Definition: pcbplot.cpp:361
PLOTTER * StartPlotBoard(BOARD *aBoard, const PCB_PLOT_PARAMS *aPlotOpts, int aLayer, const wxString &aFullFileName, const wxString &aSheetName, const wxString &aSheetPath)
Open a new plotfile using the options (and especially the format) specified in the options and prepar...
void PlotBoardLayers(BOARD *aBoard, PLOTTER *aPlotter, const LSEQ &aLayerSequence, const PCB_PLOT_PARAMS &aPlotOptions)
Plot a sequence of board layer IDs.
void PlotInteractiveLayer(BOARD *aBoard, PLOTTER *aPlotter, const PCB_PLOT_PARAMS &aPlotOpt)
Plot interactive items (hypertext links, properties, etc.).
see class PGM_BASE
PLOT_FORMAT
The set of supported output plot formats.
Definition: plotter.h:70
Plotting engine (DXF)
Plotting engine (Gerber)
Plotting engines similar to ps (PostScript, Gerber, svg)
SEVERITY
@ RPT_SEVERITY_ERROR
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:115
VECTOR2< double > VECTOR2D
Definition: vector2d.h:587
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588
Definition of file extensions used in Kicad.