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 The 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 <wx/dir.h>
22#include "pcbnew_jobs_handler.h"
23#include <board_commit.h>
26#include <drc/drc_item.h>
27#include <drc/drc_report.h>
31#include <jobs/job_fp_upgrade.h>
47#include <jobs/job_pcb_render.h>
48#include <jobs/job_pcb_drc.h>
50#include <eda_units.h>
51#include <lset.h>
52#include <cli/exit_codes.h>
58#include <tool/tool_manager.h>
59#include <tools/drc_tool.h>
60#include <wx/crt.h>
61#include <filename_resolver.h>
66#include <kiface_base.h>
67#include <macros.h>
68#include <pad.h>
69#include <pcb_marker.h>
73#include <kiface_ids.h>
76#include <pcbnew_settings.h>
77#include <pcbplot.h>
78#include <pcb_plotter.h>
79#include <pcb_edit_frame.h>
80#include <pgm_base.h>
83#include <project_pcb.h>
85#include <reporter.h>
86#include <progress_reporter.h>
88#include <export_vrml.h>
89#include <wx/wfstream.h>
90#include <wx/zipstrm.h>
91#include <wx/filename.h>
98#include <dialogs/dialog_plot.h>
103#include <paths.h>
105
107#include <locale_io.h>
108#include <confirm.h>
109
110
111#ifdef _WIN32
112#ifdef TRANSPARENT
113#undef TRANSPARENT
114#endif
115#endif
116
117
119 JOB_DISPATCHER( aKiway ),
120 m_cliBoard( nullptr ),
121 m_toolManager( nullptr )
122{
123 Register( "3d", std::bind( &PCBNEW_JOBS_HANDLER::JobExportStep, this, std::placeholders::_1 ),
124 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
125 {
126 JOB_EXPORT_PCB_3D* svgJob = dynamic_cast<JOB_EXPORT_PCB_3D*>( job );
127
128 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
129 false ) );
130
131 wxCHECK( svgJob && editFrame, false );
132
133 DIALOG_EXPORT_STEP dlg( editFrame, aParent, "", svgJob );
134 return dlg.ShowModal() == wxID_OK;
135 } );
136 Register( "render",
137 std::bind( &PCBNEW_JOBS_HANDLER::JobExportRender, this, std::placeholders::_1 ),
138 []( JOB* job, wxWindow* aParent ) -> bool
139 {
140 JOB_PCB_RENDER* renderJob = dynamic_cast<JOB_PCB_RENDER*>( job );
141
142 wxCHECK( renderJob, false );
143
144 DIALOG_RENDER_JOB dlg( aParent, renderJob );
145 return dlg.ShowModal() == wxID_OK;
146 } );
147 Register( "upgrade", std::bind( &PCBNEW_JOBS_HANDLER::JobUpgrade, this, std::placeholders::_1 ),
148 []( JOB* job, wxWindow* aParent ) -> bool
149 {
150 return true;
151 } );
152 Register( "svg", std::bind( &PCBNEW_JOBS_HANDLER::JobExportSvg, this, std::placeholders::_1 ),
153 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
154 {
155 JOB_EXPORT_PCB_SVG* svgJob = dynamic_cast<JOB_EXPORT_PCB_SVG*>( job );
156
157 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
158 false ) );
159
160 wxCHECK( svgJob && editFrame, false );
161
162 DIALOG_PLOT dlg( editFrame, aParent, svgJob );
163 return dlg.ShowModal() == wxID_OK;
164 } );
165 Register( "gencad",
166 std::bind( &PCBNEW_JOBS_HANDLER::JobExportGencad, this, std::placeholders::_1 ),
167 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
168 {
169 JOB_EXPORT_PCB_GENCAD* gencadJob = dynamic_cast<JOB_EXPORT_PCB_GENCAD*>( job );
170
171 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
172 false ) );
173
174 wxCHECK( gencadJob && editFrame, false );
175
176 DIALOG_GENCAD_EXPORT_OPTIONS dlg( editFrame, gencadJob->GetSettingsDialogTitle(), gencadJob );
177 return dlg.ShowModal() == wxID_OK;
178 } );
179 Register( "dxf", std::bind( &PCBNEW_JOBS_HANDLER::JobExportDxf, this, std::placeholders::_1 ),
180 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
181 {
182 JOB_EXPORT_PCB_DXF* dxfJob = dynamic_cast<JOB_EXPORT_PCB_DXF*>( job );
183
184 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
185 false ) );
186
187 wxCHECK( dxfJob && editFrame, false );
188
189 DIALOG_PLOT dlg( editFrame, aParent, dxfJob );
190 return dlg.ShowModal() == wxID_OK;
191 } );
192 Register( "pdf", std::bind( &PCBNEW_JOBS_HANDLER::JobExportPdf, this, std::placeholders::_1 ),
193 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
194 {
195 JOB_EXPORT_PCB_PDF* pdfJob = dynamic_cast<JOB_EXPORT_PCB_PDF*>( job );
196
197 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
198 false ) );
199
200 wxCHECK( pdfJob && editFrame, false );
201
202 DIALOG_PLOT dlg( editFrame, aParent, pdfJob );
203 return dlg.ShowModal() == wxID_OK;
204 } );
205 Register( "ps", std::bind( &PCBNEW_JOBS_HANDLER::JobExportPs, this, std::placeholders::_1 ),
206 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
207 {
208 JOB_EXPORT_PCB_PS* psJob = dynamic_cast<JOB_EXPORT_PCB_PS*>( job );
209
210 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
211 false ) );
212
213 wxCHECK( psJob && editFrame, false );
214
215 DIALOG_PLOT dlg( editFrame, aParent, psJob );
216 return dlg.ShowModal() == wxID_OK;
217 } );
218 Register( "stats",
219 std::bind( &PCBNEW_JOBS_HANDLER::JobExportStats, this, std::placeholders::_1 ),
220 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
221 {
222 JOB_EXPORT_PCB_STATS* statsJob = dynamic_cast<JOB_EXPORT_PCB_STATS*>( job );
223
224 PCB_EDIT_FRAME* editFrame =
225 dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR, false ) );
226
227 wxCHECK( statsJob && editFrame, false );
228
229 if( statsJob->m_filename.IsEmpty() && editFrame->GetBoard() )
230 {
231 wxFileName boardName = editFrame->GetBoard()->GetFileName();
232 statsJob->m_filename = boardName.GetFullPath();
233 }
234
235 wxWindow* parent = aParent ? aParent : static_cast<wxWindow*>( editFrame );
236
237 DIALOG_BOARD_STATS_JOB dlg( parent, statsJob );
238
239 return dlg.ShowModal() == wxID_OK;
240 } );
241 Register( "gerber",
242 std::bind( &PCBNEW_JOBS_HANDLER::JobExportGerber, this, std::placeholders::_1 ),
243 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
244 {
245 JOB_EXPORT_PCB_GERBER* gJob = dynamic_cast<JOB_EXPORT_PCB_GERBER*>( job );
246
247 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
248 false ) );
249
250 wxCHECK( gJob && editFrame, false );
251
252 DIALOG_PLOT dlg( editFrame, aParent, gJob );
253 return dlg.ShowModal() == wxID_OK;
254 } );
255 Register( "gerbers",
256 std::bind( &PCBNEW_JOBS_HANDLER::JobExportGerbers, this, std::placeholders::_1 ),
257 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
258 {
259 JOB_EXPORT_PCB_GERBERS* gJob = dynamic_cast<JOB_EXPORT_PCB_GERBERS*>( job );
260
261 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
262 false ) );
263
264 wxCHECK( gJob && editFrame, false );
265
266 DIALOG_PLOT dlg( editFrame, aParent, gJob );
267 return dlg.ShowModal() == wxID_OK;
268 } );
269 Register( "hpgl",
270 [&]( JOB* aJob )
271 {
272 m_reporter->Report( _( "Plotting to HPGL is no longer supported as of KiCad 10.0.\n" ),
275 },
276 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
277 {
278 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
279 false ) );
280
281 wxCHECK( editFrame, false );
282
283 DisplayErrorMessage( editFrame,
284 _( "Plotting to HPGL is no longer supported as of KiCad 10.0." ) );
285 return false;
286 } );
287 Register( "drill",
288 std::bind( &PCBNEW_JOBS_HANDLER::JobExportDrill, this, std::placeholders::_1 ),
289 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
290 {
291 JOB_EXPORT_PCB_DRILL* drillJob = dynamic_cast<JOB_EXPORT_PCB_DRILL*>( job );
292
293 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
294 false ) );
295
296 wxCHECK( drillJob && editFrame, false );
297
298 DIALOG_GENDRILL dlg( editFrame, drillJob, aParent );
299 return dlg.ShowModal() == wxID_OK;
300 } );
301 Register( "pos", std::bind( &PCBNEW_JOBS_HANDLER::JobExportPos, this, std::placeholders::_1 ),
302 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
303 {
304 JOB_EXPORT_PCB_POS* posJob = dynamic_cast<JOB_EXPORT_PCB_POS*>( job );
305
306 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
307 false ) );
308
309 wxCHECK( posJob && editFrame, false );
310
311 DIALOG_GEN_FOOTPRINT_POSITION dlg( posJob, editFrame, aParent );
312 return dlg.ShowModal() == wxID_OK;
313 } );
314 Register( "fpupgrade",
315 std::bind( &PCBNEW_JOBS_HANDLER::JobExportFpUpgrade, this, std::placeholders::_1 ),
316 []( JOB* job, wxWindow* aParent ) -> bool
317 {
318 return true;
319 } );
320 Register( "fpsvg",
321 std::bind( &PCBNEW_JOBS_HANDLER::JobExportFpSvg, this, std::placeholders::_1 ),
322 []( JOB* job, wxWindow* aParent ) -> bool
323 {
324 return true;
325 } );
326 Register( "drc", std::bind( &PCBNEW_JOBS_HANDLER::JobExportDrc, this, std::placeholders::_1 ),
327 []( JOB* job, wxWindow* aParent ) -> bool
328 {
329 JOB_PCB_DRC* drcJob = dynamic_cast<JOB_PCB_DRC*>( job );
330
331 wxCHECK( drcJob, false );
332
333 DIALOG_DRC_JOB_CONFIG dlg( aParent, drcJob );
334 return dlg.ShowModal() == wxID_OK;
335 } );
336 Register( "ipc2581",
337 std::bind( &PCBNEW_JOBS_HANDLER::JobExportIpc2581, this, std::placeholders::_1 ),
338 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
339 {
340 JOB_EXPORT_PCB_IPC2581* ipcJob = dynamic_cast<JOB_EXPORT_PCB_IPC2581*>( job );
341
342 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
343 false ) );
344
345 wxCHECK( ipcJob && editFrame, false );
346
347 DIALOG_EXPORT_2581 dlg( ipcJob, editFrame, aParent );
348 return dlg.ShowModal() == wxID_OK;
349 } );
350 Register( "ipcd356",
351 std::bind( &PCBNEW_JOBS_HANDLER::JobExportIpcD356, this, std::placeholders::_1 ),
352 []( JOB* job, wxWindow* aParent ) -> bool
353 {
354 return true;
355 } );
356 Register( "odb",
357 std::bind( &PCBNEW_JOBS_HANDLER::JobExportOdb, this, std::placeholders::_1 ),
358 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
359 {
360 JOB_EXPORT_PCB_ODB* odbJob = dynamic_cast<JOB_EXPORT_PCB_ODB*>( job );
361
362 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
363 false ) );
364
365 wxCHECK( odbJob && editFrame, false );
366
367 DIALOG_EXPORT_ODBPP dlg( odbJob, editFrame, aParent );
368 return dlg.ShowModal() == wxID_OK;
369 } );
370}
371
372
376
377
379{
380 TOOL_MANAGER* toolManager = nullptr;
381 if( Pgm().IsGUI() )
382 {
383 // we assume the PCB we are working on here is the one in the frame
384 // so use the frame's tool manager
385 PCB_EDIT_FRAME* editFrame = (PCB_EDIT_FRAME*) m_kiway->Player( FRAME_PCB_EDITOR, false );
386 if( editFrame )
387 toolManager = editFrame->GetToolManager();
388 }
389 else
390 {
391 if( m_toolManager == nullptr )
392 {
393 m_toolManager = std::make_unique<TOOL_MANAGER>();
394 }
395
396 toolManager = m_toolManager.get();
397
398 toolManager->SetEnvironment( aBrd, nullptr, nullptr, Kiface().KifaceSettings(), nullptr );
399 }
400 return toolManager;
401}
402
403
404BOARD* PCBNEW_JOBS_HANDLER::getBoard( const wxString& aPath )
405{
406 BOARD* brd = nullptr;
407
408 if( !Pgm().IsGUI() && Pgm().GetSettingsManager().IsProjectOpen() )
409 {
410 wxString pcbPath = aPath;
411
412 if( pcbPath.IsEmpty() )
413 {
414 wxFileName path = Pgm().GetSettingsManager().Prj().GetProjectFullName();
416 path.MakeAbsolute();
417 pcbPath = path.GetFullPath();
418 }
419
420 if( !m_cliBoard )
421 m_cliBoard = LoadBoard( pcbPath, true );
422
423 brd = m_cliBoard;
424 }
425 else if( Pgm().IsGUI() && Pgm().GetSettingsManager().IsProjectOpen() )
426 {
427 PCB_EDIT_FRAME* editFrame = (PCB_EDIT_FRAME*) m_kiway->Player( FRAME_PCB_EDITOR, false );
428
429 if( editFrame )
430 brd = editFrame->GetBoard();
431 }
432 else
433 {
434 brd = LoadBoard( aPath, true );
435 }
436
437 if( !brd )
438 m_reporter->Report( _( "Failed to load board\n" ), RPT_SEVERITY_ERROR );
439
440 return brd;
441}
442
443
444LSEQ PCBNEW_JOBS_HANDLER::convertLayerArg( wxString& aLayerString, BOARD* aBoard ) const
445{
446 std::map<wxString, LSET> layerUserMasks;
447 std::map<wxString, LSET> layerMasks;
448 std::map<wxString, LSET> layerGuiMasks;
449
450 // Build list of layer names and their layer mask:
451 for( PCB_LAYER_ID layer : LSET::AllLayersMask() )
452 {
453 // Add user layer name
454 if( aBoard )
455 layerUserMasks[ aBoard->GetLayerName( layer ) ] = LSET( { layer } );
456
457 // Add layer name used in pcb files
458 layerMasks[ LSET::Name( layer ) ] = LSET( { layer } );
459 // Add layer name using GUI canonical layer name
460 layerGuiMasks[ LayerName( layer ) ] = LSET( { layer } );
461 }
462
463 // Add list of grouped layer names used in pcb files
464 layerMasks[ wxT( "*" ) ] = LSET::AllLayersMask();
465 layerMasks[ wxT( "*.Cu" ) ] = LSET::AllCuMask();
466 layerMasks[ wxT( "*In.Cu" ) ] = LSET::InternalCuMask();
467 layerMasks[ wxT( "F&B.Cu" ) ] = LSET( { F_Cu, B_Cu } );
468 layerMasks[ wxT( "*.Adhes" ) ] = LSET( { B_Adhes, F_Adhes } );
469 layerMasks[ wxT( "*.Paste" ) ] = LSET( { B_Paste, F_Paste } );
470 layerMasks[ wxT( "*.Mask" ) ] = LSET( { B_Mask, F_Mask } );
471 layerMasks[ wxT( "*.SilkS" ) ] = LSET( { B_SilkS, F_SilkS } );
472 layerMasks[ wxT( "*.Fab" ) ] = LSET( { B_Fab, F_Fab } );
473 layerMasks[ wxT( "*.CrtYd" ) ] = LSET( { B_CrtYd, F_CrtYd } );
474
475 // Add list of grouped layer names using GUI canonical layer names
476 layerGuiMasks[ wxT( "*.Adhesive" ) ] = LSET( { B_Adhes, F_Adhes } );
477 layerGuiMasks[ wxT( "*.Silkscreen" ) ] = LSET( { B_SilkS, F_SilkS } );
478 layerGuiMasks[ wxT( "*.Courtyard" ) ] = LSET( { B_CrtYd, F_CrtYd } );
479
480 LSEQ layerMask;
481
482 auto pushLayers =
483 [&]( const LSET& layerSet )
484 {
485 for( PCB_LAYER_ID layer : layerSet.Seq() )
486 layerMask.push_back( layer );
487 };
488
489 if( !aLayerString.IsEmpty() )
490 {
491 wxStringTokenizer layerTokens( aLayerString, "," );
492
493 while( layerTokens.HasMoreTokens() )
494 {
495 std::string token = TO_UTF8( layerTokens.GetNextToken().Trim( true ).Trim( false ) );
496
497 if( layerUserMasks.contains( token ) )
498 pushLayers( layerUserMasks.at( token ) );
499 else if( layerMasks.count( token ) )
500 pushLayers( layerMasks.at( token ) );
501 else if( layerGuiMasks.count( token ) )
502 pushLayers( layerGuiMasks.at( token ) );
503 else
504 m_reporter->Report( wxString::Format( _( "Invalid layer name '%s'\n" ), token ) );
505 }
506 }
507
508 return layerMask;
509}
510
511
513{
514 JOB_EXPORT_PCB_3D* aStepJob = dynamic_cast<JOB_EXPORT_PCB_3D*>( aJob );
515
516 if( aStepJob == nullptr )
518
519 BOARD* brd = getBoard( aStepJob->m_filename );
520
521 if( !brd )
523
524 if( aStepJob->GetConfiguredOutputPath().IsEmpty() )
525 {
526 wxFileName fn = brd->GetFileName();
527 fn.SetName( fn.GetName() );
528
529 switch( aStepJob->m_format )
530 {
540 default:
541 m_reporter->Report( _( "Unknown export format" ), RPT_SEVERITY_ERROR );
542 return CLI::EXIT_CODES::ERR_UNKNOWN; // shouldnt have gotten here
543 }
544
545 aStepJob->SetWorkingOutputPath( fn.GetFullName() );
546 }
547
548 wxString outPath = resolveJobOutputPath( aJob, brd );
549
550 if( !PATHS::EnsurePathExists( outPath, true ) )
551 {
552 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
554 }
555
557 {
558
559 double scale = 0.0;
560 switch ( aStepJob->m_vrmlUnits )
561 {
562 case JOB_EXPORT_PCB_3D::VRML_UNITS::MM: scale = 1.0; break;
563 case JOB_EXPORT_PCB_3D::VRML_UNITS::METERS: scale = 0.001; break;
564 case JOB_EXPORT_PCB_3D::VRML_UNITS::TENTHS: scale = 10.0 / 25.4; break;
565 case JOB_EXPORT_PCB_3D::VRML_UNITS::INCH: scale = 1.0 / 25.4; break;
566 }
567
568 EXPORTER_VRML vrmlExporter( brd );
569 wxString messages;
570
571 double originX = pcbIUScale.IUTomm( aStepJob->m_3dparams.m_Origin.x );
572 double originY = pcbIUScale.IUTomm( aStepJob->m_3dparams.m_Origin.y );
573
574 if( !aStepJob->m_hasUserOrigin )
575 {
576 BOX2I bbox = brd->ComputeBoundingBox( true );
577 originX = pcbIUScale.IUTomm( bbox.GetCenter().x );
578 originY = pcbIUScale.IUTomm( bbox.GetCenter().y );
579 }
580
581 bool success = vrmlExporter.ExportVRML_File( brd->GetProject(),
582 &messages,
583 outPath,
584 scale,
586 aStepJob->m_3dparams.m_IncludeDNP,
587 !aStepJob->m_vrmlModelDir.IsEmpty(),
588 aStepJob->m_vrmlRelativePaths,
589 aStepJob->m_vrmlModelDir,
590 originX,
591 originY );
592
593 if ( success )
594 {
595 m_reporter->Report( wxString::Format( _( "Successfully exported VRML to %s" ),
596 outPath ),
598 }
599 else
600 {
601 m_reporter->Report( _( "Error exporting VRML" ), RPT_SEVERITY_ERROR );
603 }
604 }
605 else
606 {
607 EXPORTER_STEP_PARAMS params = aStepJob->m_3dparams;
608
609 switch( aStepJob->m_format )
610 {
620 default:
621 m_reporter->Report( _( "Unknown export format" ), RPT_SEVERITY_ERROR );
622 return CLI::EXIT_CODES::ERR_UNKNOWN; // shouldnt have gotten here
623 }
624
625 EXPORTER_STEP stepExporter( brd, params, m_reporter );
626 stepExporter.m_outputFile = aStepJob->GetFullOutputPath( brd->GetProject() );
627
628 if( !stepExporter.Export() )
630 }
631
632 return CLI::EXIT_CODES::OK;
633}
634
635
637{
638 JOB_PCB_RENDER* aRenderJob = dynamic_cast<JOB_PCB_RENDER*>( aJob );
639
640 if( aRenderJob == nullptr )
642
643 // Reject width and height being invalid
644 // Final bit of sanity because this can blow things up
645 if( aRenderJob->m_width <= 0 || aRenderJob->m_height <= 0 )
646 {
647 m_reporter->Report( _( "Invalid image dimensions" ), RPT_SEVERITY_ERROR );
649 }
650
651 BOARD* brd = getBoard( aRenderJob->m_filename );
652
653 if( !brd )
655
656 if( aRenderJob->GetConfiguredOutputPath().IsEmpty() )
657 {
658 wxFileName fn = brd->GetFileName();
659
660 switch( aRenderJob->m_format )
661 {
664 default:
665 m_reporter->Report( _( "Unknown export format" ), RPT_SEVERITY_ERROR );
666 return CLI::EXIT_CODES::ERR_UNKNOWN; // shouldnt have gotten here
667 }
668
669 // set the name to board name + "side", its lazy but its hard to generate anything truely unique
670 // incase someone is doing this in a jobset with multiple jobs, they should be setting the output themselves
671 // or we do a hash based on all the options
672 fn.SetName( wxString::Format( "%s-%d", fn.GetName(), static_cast<int>( aRenderJob->m_side ) ) );
673
674 aRenderJob->SetWorkingOutputPath( fn.GetFullName() );
675 }
676
677 wxString outPath = resolveJobOutputPath( aJob, brd );
678
679 if( !PATHS::EnsurePathExists( outPath, true ) )
680 {
681 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
683 }
684
685 BOARD_ADAPTER boardAdapter;
686
687 boardAdapter.SetBoard( brd );
688 boardAdapter.m_IsBoardView = false;
689
691
693 {
694 cfg.m_Render = userCfg->m_Render;
695 cfg.m_Camera = userCfg->m_Camera;
696 cfg.m_LayerPresets = userCfg->m_LayerPresets;
697 }
698
699 if( aRenderJob->m_appearancePreset.empty() )
700 {
701 // Force display 3D models
703 cfg.m_Render.show_footprints_dnp = true;
707 }
708
709 if( aRenderJob->m_quality == JOB_PCB_RENDER::QUALITY::BASIC )
710 {
711 // Silkscreen is pixelated without antialiasing
713
714 cfg.m_Render.raytrace_backfloor = aRenderJob->m_floor;
715 cfg.m_Render.raytrace_post_processing = aRenderJob->m_floor;
716
718 cfg.m_Render.raytrace_reflections = false;
719 cfg.m_Render.raytrace_shadows = aRenderJob->m_floor;
720
721 // Better colors
723
724 // Tracks below soldermask are not visible without refractions
727 }
728 else if( aRenderJob->m_quality == JOB_PCB_RENDER::QUALITY::HIGH )
729 {
731 cfg.m_Render.raytrace_backfloor = true;
735 cfg.m_Render.raytrace_shadows = true;
738 }
739 else if( aRenderJob->m_quality == JOB_PCB_RENDER::QUALITY::JOB_SETTINGS )
740 {
742 cfg.m_Render.raytrace_backfloor = aRenderJob->m_floor;
745 }
746
748 aRenderJob->m_lightTopIntensity.y,
749 aRenderJob->m_lightTopIntensity.z, 1.0 );
750
752 aRenderJob->m_lightBottomIntensity.y,
753 aRenderJob->m_lightBottomIntensity.z, 1.0 );
754
756 aRenderJob->m_lightCameraIntensity.y,
757 aRenderJob->m_lightCameraIntensity.z, 1.0 );
758
759 COLOR4D lightColor( aRenderJob->m_lightSideIntensity.x,
760 aRenderJob->m_lightSideIntensity.y,
761 aRenderJob->m_lightSideIntensity.z, 1.0 );
762
764 lightColor, lightColor, lightColor, lightColor,
765 lightColor, lightColor, lightColor, lightColor,
766 };
767
768 int sideElevation = aRenderJob->m_lightSideElevation;
769
771 sideElevation, sideElevation, sideElevation, sideElevation,
772 -sideElevation, -sideElevation, -sideElevation, -sideElevation,
773 };
774
776 45, 135, 225, 315, 45, 135, 225, 315,
777 };
778
779 cfg.m_CurrentPreset = aRenderJob->m_appearancePreset;
781 boardAdapter.m_Cfg = &cfg;
782
785 && aRenderJob->m_format == JOB_PCB_RENDER::FORMAT::PNG ) )
786 {
787 boardAdapter.m_ColorOverrides[LAYER_3D_BACKGROUND_TOP] = COLOR4D( 1.0, 1.0, 1.0, 0.0 );
788 boardAdapter.m_ColorOverrides[LAYER_3D_BACKGROUND_BOTTOM] = COLOR4D( 1.0, 1.0, 1.0, 0.0 );
789 }
790
792
793 static std::map<JOB_PCB_RENDER::SIDE, VIEW3D_TYPE> s_viewCmdMap = {
800 };
801
804
805 wxSize windowSize( aRenderJob->m_width, aRenderJob->m_height );
806 TRACK_BALL camera( 2 * RANGE_SCALE_3D );
807
808 camera.SetProjection( projection );
809 camera.SetCurWindowSize( windowSize );
810
811 RENDER_3D_RAYTRACE_RAM raytrace( boardAdapter, camera );
812 raytrace.SetCurWindowSize( windowSize );
813
814 for( bool first = true; raytrace.Redraw( false, m_reporter, m_reporter ); first = false )
815 {
816 if( first )
817 {
818 const float cmTo3D = boardAdapter.BiuTo3dUnits() * pcbIUScale.mmToIU( 10.0 );
819
820 // First redraw resets lookat point to the board center, so set up the camera here
821 camera.ViewCommand_T1( s_viewCmdMap[aRenderJob->m_side] );
822
823 camera.SetLookAtPos_T1( camera.GetLookAtPos_T1() + SFVEC3F( aRenderJob->m_pivot.x,
824 aRenderJob->m_pivot.y,
825 aRenderJob->m_pivot.z ) * cmTo3D );
826
827 camera.Pan_T1( SFVEC3F( aRenderJob->m_pan.x, aRenderJob->m_pan.y, aRenderJob->m_pan.z ) );
828
829 camera.Zoom_T1( aRenderJob->m_zoom );
830
831 camera.RotateX_T1( DEG2RAD( aRenderJob->m_rotation.x ) );
832 camera.RotateY_T1( DEG2RAD( aRenderJob->m_rotation.y ) );
833 camera.RotateZ_T1( DEG2RAD( aRenderJob->m_rotation.z ) );
834
835 camera.Interpolate( 1.0f );
836 camera.SetT0_and_T1_current_T();
837 camera.ParametersChanged();
838 }
839 }
840
841 uint8_t* rgbaBuffer = raytrace.GetBuffer();
842 wxSize realSize = raytrace.GetRealBufferSize();
843 bool success = !!rgbaBuffer;
844
845 if( rgbaBuffer )
846 {
847 const unsigned int wxh = realSize.x * realSize.y;
848
849 unsigned char* rgbBuffer = (unsigned char*) malloc( wxh * 3 );
850 unsigned char* alphaBuffer = (unsigned char*) malloc( wxh );
851
852 unsigned char* rgbaPtr = rgbaBuffer;
853 unsigned char* rgbPtr = rgbBuffer;
854 unsigned char* alphaPtr = alphaBuffer;
855
856 for( int y = 0; y < realSize.y; y++ )
857 {
858 for( int x = 0; x < realSize.x; x++ )
859 {
860 rgbPtr[0] = rgbaPtr[0];
861 rgbPtr[1] = rgbaPtr[1];
862 rgbPtr[2] = rgbaPtr[2];
863 alphaPtr[0] = rgbaPtr[3];
864
865 rgbaPtr += 4;
866 rgbPtr += 3;
867 alphaPtr += 1;
868 }
869 }
870
871 wxImage image( realSize );
872 image.SetData( rgbBuffer );
873 image.SetAlpha( alphaBuffer );
874 image = image.Mirror( false );
875
876 image.SetOption( wxIMAGE_OPTION_QUALITY, 90 );
877 image.SaveFile( outPath, aRenderJob->m_format == JOB_PCB_RENDER::FORMAT::PNG ? wxBITMAP_TYPE_PNG
878 : wxBITMAP_TYPE_JPEG );
879 }
880
881 if( success )
882 {
883 m_reporter->Report( _( "Successfully created 3D render image" ) + wxS( "\n" ), RPT_SEVERITY_INFO );
884 return CLI::EXIT_CODES::OK;
885 }
886 else
887 {
888 m_reporter->Report( _( "Error creating 3D render image" ) + wxS( "\n" ), RPT_SEVERITY_ERROR );
890 }
891}
892
893
895{
896 JOB_EXPORT_PCB_SVG* aSvgJob = dynamic_cast<JOB_EXPORT_PCB_SVG*>( aJob );
897
898 if( aSvgJob == nullptr )
900
901 BOARD* brd = getBoard( aSvgJob->m_filename );
902 TOOL_MANAGER* toolManager = getToolManager( brd );
903
904 if( !brd )
906
908 {
909 if( aSvgJob->GetConfiguredOutputPath().IsEmpty() )
910 {
911 wxFileName fn = brd->GetFileName();
912 fn.SetName( fn.GetName() );
914
915 aSvgJob->SetWorkingOutputPath( fn.GetFullName() );
916 }
917 }
918
919 wxString outPath = resolveJobOutputPath( aJob, brd, &aSvgJob->m_drawingSheet );
920
922 {
923 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
925 }
926
927 if( aSvgJob->m_checkZonesBeforePlot )
928 {
929 if( !toolManager->FindTool( ZONE_FILLER_TOOL_NAME ) )
930 toolManager->RegisterTool( new ZONE_FILLER_TOOL );
931
932 toolManager->GetTool<ZONE_FILLER_TOOL>()->CheckAllZones( nullptr );
933 }
934
935 if( aSvgJob->m_argLayers )
936 aSvgJob->m_plotLayerSequence = convertLayerArg( aSvgJob->m_argLayers.value(), brd );
937
938 if( aSvgJob->m_argCommonLayers )
939 aSvgJob->m_plotOnAllLayersSequence = convertLayerArg( aSvgJob->m_argCommonLayers.value(), brd );
940
941 if( aSvgJob->m_plotLayerSequence.size() < 1 )
942 {
943 m_reporter->Report( _( "At least one layer must be specified\n" ), RPT_SEVERITY_ERROR );
945 }
946
947 PCB_PLOT_PARAMS plotOpts;
948 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, aSvgJob, *m_reporter );
949
950 PCB_PLOTTER plotter( brd, m_reporter, plotOpts );
951
952 std::optional<wxString> layerName;
953 std::optional<wxString> sheetName;
954 std::optional<wxString> sheetPath;
955
957 {
958 if( aJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
959 layerName = aSvgJob->GetVarOverrides().at( wxT( "LAYER" ) );
960
961 if( aJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
962 sheetName = aSvgJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
963
964 if( aJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
965 sheetPath = aSvgJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
966 }
967
968 if( !plotter.Plot( outPath, aSvgJob->m_plotLayerSequence, aSvgJob->m_plotOnAllLayersSequence,
970 layerName, sheetName, sheetPath ) )
971 {
973 }
974
975 return CLI::EXIT_CODES::OK;
976}
977
978
980{
981 JOB_EXPORT_PCB_DXF* aDxfJob = dynamic_cast<JOB_EXPORT_PCB_DXF*>( aJob );
982
983 if( aDxfJob == nullptr )
985
986 BOARD* brd = getBoard( aDxfJob->m_filename );
987
988 if( !brd )
990
991 TOOL_MANAGER* toolManager = getToolManager( brd );
992
993 if( aDxfJob->m_checkZonesBeforePlot )
994 {
995 if( !toolManager->FindTool( ZONE_FILLER_TOOL_NAME ) )
996 toolManager->RegisterTool( new ZONE_FILLER_TOOL );
997
998 toolManager->GetTool<ZONE_FILLER_TOOL>()->CheckAllZones( nullptr );
999 }
1000
1001 if( aDxfJob->m_argLayers )
1002 aDxfJob->m_plotLayerSequence = convertLayerArg( aDxfJob->m_argLayers.value(), brd );
1003
1004 if( aDxfJob->m_argCommonLayers )
1005 aDxfJob->m_plotOnAllLayersSequence = convertLayerArg( aDxfJob->m_argCommonLayers.value(), brd );
1006
1007 if( aDxfJob->m_plotLayerSequence.size() < 1 )
1008 {
1009 m_reporter->Report( _( "At least one layer must be specified\n" ), RPT_SEVERITY_ERROR );
1011 }
1012
1014 {
1015 if( aDxfJob->GetConfiguredOutputPath().IsEmpty() )
1016 {
1017 wxFileName fn = brd->GetFileName();
1018 fn.SetName( fn.GetName() );
1020
1021 aDxfJob->SetWorkingOutputPath( fn.GetFullName() );
1022 }
1023 }
1024
1025 wxString outPath = resolveJobOutputPath( aJob, brd, &aDxfJob->m_drawingSheet );
1026
1028 {
1029 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1031 }
1032
1033 PCB_PLOT_PARAMS plotOpts;
1034 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, aDxfJob, *m_reporter);
1035
1036 PCB_PLOTTER plotter( brd, m_reporter, plotOpts );
1037
1038 std::optional<wxString> layerName;
1039 std::optional<wxString> sheetName;
1040 std::optional<wxString> sheetPath;
1041
1043 {
1044 if( aJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
1045 layerName = aDxfJob->GetVarOverrides().at( wxT( "LAYER" ) );
1046
1047 if( aJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
1048 sheetName = aDxfJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
1049
1050 if( aJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
1051 sheetPath = aDxfJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
1052 }
1053
1054 if( !plotter.Plot( outPath, aDxfJob->m_plotLayerSequence, aDxfJob->m_plotOnAllLayersSequence,
1056 layerName, sheetName, sheetPath ) )
1057 {
1059 }
1060
1061 return CLI::EXIT_CODES::OK;
1062}
1063
1064
1066{
1067 bool plotAllLayersOneFile = false;
1068 JOB_EXPORT_PCB_PDF* pdfJob = dynamic_cast<JOB_EXPORT_PCB_PDF*>( aJob );
1069
1070 if( pdfJob == nullptr )
1072
1073 BOARD* brd = getBoard( pdfJob->m_filename );
1074
1075 if( !brd )
1077
1078 TOOL_MANAGER* toolManager = getToolManager( brd );
1079
1080 if( pdfJob->m_checkZonesBeforePlot )
1081 {
1082 if( !toolManager->FindTool( ZONE_FILLER_TOOL_NAME ) )
1083 toolManager->RegisterTool( new ZONE_FILLER_TOOL );
1084
1085 toolManager->GetTool<ZONE_FILLER_TOOL>()->CheckAllZones( nullptr );
1086 }
1087
1088 if( pdfJob->m_argLayers )
1089 pdfJob->m_plotLayerSequence = convertLayerArg( pdfJob->m_argLayers.value(), brd );
1090
1091 if( pdfJob->m_argCommonLayers )
1092 pdfJob->m_plotOnAllLayersSequence = convertLayerArg( pdfJob->m_argCommonLayers.value(), brd );
1093
1095 plotAllLayersOneFile = true;
1096
1097 if( pdfJob->m_plotLayerSequence.size() < 1 )
1098 {
1099 m_reporter->Report( _( "At least one layer must be specified\n" ), RPT_SEVERITY_ERROR );
1101 }
1102
1103 if( plotAllLayersOneFile && pdfJob->GetConfiguredOutputPath().IsEmpty() )
1104 {
1105 wxFileName fn = brd->GetFileName();
1106 fn.SetName( fn.GetName() );
1108
1109 pdfJob->SetWorkingOutputPath( fn.GetFullName() );
1110 }
1111
1112 wxString outPath = resolveJobOutputPath( pdfJob, brd, &pdfJob->m_drawingSheet );
1113
1114 PCB_PLOT_PARAMS plotOpts;
1115 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, pdfJob, *m_reporter );
1116
1117 // ensure this is set for this one gen mode
1118 if( plotAllLayersOneFile )
1119 plotOpts.m_PDFSingle = true;
1120
1121 PCB_PLOTTER pcbPlotter( brd, m_reporter, plotOpts );
1122
1123 if( !PATHS::EnsurePathExists( outPath, plotAllLayersOneFile ) )
1124 {
1125 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1127 }
1128
1129 std::optional<wxString> layerName;
1130 std::optional<wxString> sheetName;
1131 std::optional<wxString> sheetPath;
1132
1133 if( plotAllLayersOneFile )
1134 {
1135 if( pdfJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
1136 layerName = pdfJob->GetVarOverrides().at( wxT( "LAYER" ) );
1137
1138 if( pdfJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
1139 sheetName = pdfJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
1140
1141 if( pdfJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
1142 sheetPath = pdfJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
1143 }
1144
1145 if( !pcbPlotter.Plot( outPath, pdfJob->m_plotLayerSequence,
1146 pdfJob->m_plotOnAllLayersSequence, false, plotAllLayersOneFile,
1147 layerName, sheetName, sheetPath ) )
1148 {
1150 }
1151
1152 return CLI::EXIT_CODES::OK;
1153}
1154
1155
1157{
1158 JOB_EXPORT_PCB_PS* psJob = dynamic_cast<JOB_EXPORT_PCB_PS*>( aJob );
1159
1160 if( psJob == nullptr )
1162
1163 BOARD* brd = getBoard( psJob->m_filename );
1164
1165 if( !brd )
1167
1168 TOOL_MANAGER* toolManager = getToolManager( brd );
1169
1170 if( psJob->m_checkZonesBeforePlot )
1171 {
1172 if( !toolManager->FindTool( ZONE_FILLER_TOOL_NAME ) )
1173 toolManager->RegisterTool( new ZONE_FILLER_TOOL );
1174
1175 toolManager->GetTool<ZONE_FILLER_TOOL>()->CheckAllZones( nullptr );
1176 }
1177
1178 if( psJob->m_argLayers )
1179 psJob->m_plotLayerSequence = convertLayerArg( psJob->m_argLayers.value(), brd );
1180
1181 if( psJob->m_argCommonLayers )
1182 psJob->m_plotOnAllLayersSequence = convertLayerArg( psJob->m_argCommonLayers.value(), brd );
1183
1184 if( psJob->m_plotLayerSequence.size() < 1 )
1185 {
1186 m_reporter->Report( _( "At least one layer must be specified\n" ), RPT_SEVERITY_ERROR );
1188 }
1189
1190 bool isSingle = psJob->m_genMode == JOB_EXPORT_PCB_PS::GEN_MODE::SINGLE;
1191
1192 if( isSingle )
1193 {
1194 if( psJob->GetConfiguredOutputPath().IsEmpty() )
1195 {
1196 wxFileName fn = brd->GetFileName();
1197 fn.SetName( fn.GetName() );
1199
1200 psJob->SetWorkingOutputPath( fn.GetFullName() );
1201 }
1202 }
1203
1204 wxString outPath = resolveJobOutputPath( psJob, brd, &psJob->m_drawingSheet );
1205
1206 if( !PATHS::EnsurePathExists( outPath, isSingle ) )
1207 {
1208 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1210 }
1211
1212 PCB_PLOT_PARAMS plotOpts;
1213 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, psJob, *m_reporter );
1214
1215 PCB_PLOTTER pcbPlotter( brd, m_reporter, plotOpts );
1216
1217 std::optional<wxString> layerName;
1218 std::optional<wxString> sheetName;
1219 std::optional<wxString> sheetPath;
1220
1221 if( isSingle )
1222 {
1223 if( aJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
1224 layerName = psJob->GetVarOverrides().at( wxT( "LAYER" ) );
1225
1226 if( aJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
1227 sheetName = psJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
1228
1229 if( aJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
1230 sheetPath = psJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
1231 }
1232
1233 if( !pcbPlotter.Plot( outPath, psJob->m_plotLayerSequence, psJob->m_plotOnAllLayersSequence, false, isSingle,
1234 layerName, sheetName, sheetPath ) )
1235 {
1237 }
1238
1239 return CLI::EXIT_CODES::OK;
1240}
1241
1242
1244{
1245 int exitCode = CLI::EXIT_CODES::OK;
1246 JOB_EXPORT_PCB_GERBERS* aGerberJob = dynamic_cast<JOB_EXPORT_PCB_GERBERS*>( aJob );
1247
1248 if( aGerberJob == nullptr )
1250
1251 BOARD* brd = getBoard( aGerberJob->m_filename );
1252
1253 if( !brd )
1255
1256 wxString outPath = resolveJobOutputPath( aJob, brd, &aGerberJob->m_drawingSheet );
1257
1258 if( !PATHS::EnsurePathExists( outPath, false ) )
1259 {
1260 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1262 }
1263
1264 TOOL_MANAGER* toolManager = getToolManager( brd );
1265
1266 if( aGerberJob->m_checkZonesBeforePlot )
1267 {
1268 if( !toolManager->FindTool( ZONE_FILLER_TOOL_NAME ) )
1269 toolManager->RegisterTool( new ZONE_FILLER_TOOL );
1270
1271 toolManager->GetTool<ZONE_FILLER_TOOL>()->CheckAllZones( nullptr );
1272 }
1273
1274 bool hasLayerListSpecified = false; // will be true if the user layer list is not empty
1275
1276 if( aGerberJob->m_argLayers )
1277 {
1278 if( !aGerberJob->m_argLayers.value().empty() )
1279 {
1280 aGerberJob->m_plotLayerSequence = convertLayerArg( aGerberJob->m_argLayers.value(), brd );
1281 hasLayerListSpecified = true;
1282 }
1283 else
1284 {
1286 }
1287 }
1288
1289 if( aGerberJob->m_argCommonLayers )
1290 aGerberJob->m_plotOnAllLayersSequence = convertLayerArg( aGerberJob->m_argCommonLayers.value(), brd );
1291
1292 PCB_PLOT_PARAMS boardPlotOptions = brd->GetPlotOptions();
1293 GERBER_JOBFILE_WRITER jobfile_writer( brd );
1294
1295 wxString fileExt;
1296
1297 if( aGerberJob->m_useBoardPlotParams )
1298 {
1299 // The board plot options are saved with all copper layers enabled, even those that don't
1300 // exist in the current stackup. This is done so the layers are automatically enabled in the plot
1301 // dialog when the user enables them. We need to filter out these not-enabled layers here so
1302 // we don't plot 32 layers when we only have 4, etc.
1303 LSET plotLayers = ( boardPlotOptions.GetLayerSelection() & LSET::AllNonCuMask() )
1304 | ( brd->GetEnabledLayers() & LSET::AllCuMask() );
1305 aGerberJob->m_plotLayerSequence = plotLayers.SeqStackupForPlotting();
1306 aGerberJob->m_plotOnAllLayersSequence = boardPlotOptions.GetPlotOnAllLayersSequence();
1307 }
1308 else
1309 {
1310 // default to the board enabled layers, but only if the user has not specifed a layer list
1311 // ( m_plotLayerSequence can be empty with a broken user layer list)
1312 if( aGerberJob->m_plotLayerSequence.empty() && !hasLayerListSpecified )
1314 }
1315
1316 // Ensure layers to plot are restricted to enabled layers of the board to plot
1317 LSET layersToPlot = LSET( { aGerberJob->m_plotLayerSequence } ) & brd->GetEnabledLayers();
1318
1319 for( PCB_LAYER_ID layer : layersToPlot.UIOrder() )
1320 {
1321 LSEQ plotSequence;
1322
1323 // Base layer always gets plotted first.
1324 plotSequence.push_back( layer );
1325
1326 // Now all the "include on all" layers
1327 for( PCB_LAYER_ID layer_all : aGerberJob->m_plotOnAllLayersSequence )
1328 {
1329 // Don't plot the same layer more than once;
1330 if( find( plotSequence.begin(), plotSequence.end(), layer_all ) != plotSequence.end() )
1331 continue;
1332
1333 plotSequence.push_back( layer_all );
1334 }
1335
1336 // Pick the basename from the board file
1337 wxFileName fn( brd->GetFileName() );
1338 wxString layerName = brd->GetLayerName( layer );
1339 wxString sheetName;
1340 wxString sheetPath;
1341 PCB_PLOT_PARAMS plotOpts;
1342
1343 if( aGerberJob->m_useBoardPlotParams )
1344 plotOpts = boardPlotOptions;
1345 else
1346 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, aGerberJob, *m_reporter );
1347
1348 if( plotOpts.GetUseGerberProtelExtensions() )
1349 fileExt = GetGerberProtelExtension( layer );
1350 else
1352
1353 BuildPlotFileName( &fn, outPath, layerName, fileExt );
1354 wxString fullname = fn.GetFullName();
1355
1356 if( m_progressReporter )
1357 {
1358 m_progressReporter->AdvancePhase( wxString::Format( _( "Exporting %s" ), fullname ) );
1359 m_progressReporter->KeepRefreshing();
1360 }
1361
1362 jobfile_writer.AddGbrFile( layer, fullname );
1363
1364 if( aJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
1365 layerName = aJob->GetVarOverrides().at( wxT( "LAYER" ) );
1366
1367 if( aJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
1368 sheetName = aJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
1369
1370 if( aJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
1371 sheetPath = aJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
1372
1373 // We are feeding it one layer at the start here to silence a logic check
1374 GERBER_PLOTTER* plotter;
1375 plotter = (GERBER_PLOTTER*) StartPlotBoard( brd, &plotOpts, layer, layerName,
1376 fn.GetFullPath(), sheetName, sheetPath );
1377
1378 if( plotter )
1379 {
1380 m_reporter->Report( wxString::Format( _( "Plotted to '%s'.\n" ), fn.GetFullPath() ),
1382
1383 PlotBoardLayers( brd, plotter, plotSequence, plotOpts );
1384 plotter->EndPlot();
1385 }
1386 else
1387 {
1388 m_reporter->Report( wxString::Format( _( "Failed to plot to '%s'.\n" ), fn.GetFullPath() ),
1391 }
1392
1393 delete plotter;
1394 }
1395
1396 if( aGerberJob->m_createJobsFile )
1397 {
1398 wxFileName fn( brd->GetFileName() );
1399
1400 // Build gerber job file from basename
1401 BuildPlotFileName( &fn, outPath, wxT( "job" ), FILEEXT::GerberJobFileExtension );
1402 jobfile_writer.CreateJobFile( fn.GetFullPath() );
1403 }
1404
1405 return exitCode;
1406}
1407
1408
1410{
1411 JOB_EXPORT_PCB_GENCAD* aGencadJob = dynamic_cast<JOB_EXPORT_PCB_GENCAD*>( aJob );
1412
1413 if( aGencadJob == nullptr )
1415
1416 BOARD* brd = LoadBoard( aGencadJob->m_filename, true ); // Ensure m_board is of type BOARD*
1417
1418 if( brd == nullptr )
1420
1421 GENCAD_EXPORTER exporter( brd );
1422
1423 VECTOR2I GencadOffset;
1424 VECTOR2I auxOrigin = brd->GetDesignSettings().GetAuxOrigin();
1425 GencadOffset.x = aGencadJob->m_useDrillOrigin ? auxOrigin.x : 0;
1426 GencadOffset.y = aGencadJob->m_useDrillOrigin ? auxOrigin.y : 0;
1427
1428 exporter.FlipBottomPads( aGencadJob->m_flipBottomPads );
1429 exporter.UsePinNamesUnique( aGencadJob->m_useUniquePins );
1430 exporter.UseIndividualShapes( aGencadJob->m_useIndividualShapes );
1431 exporter.SetPlotOffet( GencadOffset );
1432 exporter.StoreOriginCoordsInFile( aGencadJob->m_storeOriginCoords );
1433
1434 if( aGencadJob->GetConfiguredOutputPath().IsEmpty() )
1435 {
1436 wxFileName fn = brd->GetFileName();
1437 fn.SetName( fn.GetName() );
1438 fn.SetExt( FILEEXT::GencadFileExtension );
1439
1440 aGencadJob->SetWorkingOutputPath( fn.GetFullName() );
1441 }
1442
1443 wxString outPath = resolveJobOutputPath( aJob, brd );
1444
1445 if( !PATHS::EnsurePathExists( outPath, true ) )
1446 {
1447 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1449 }
1450
1451 if( !exporter.WriteFile( outPath ) )
1452 {
1453 m_reporter->Report( wxString::Format( _( "Failed to create file '%s'.\n" ), outPath ),
1455
1457 }
1458
1459 m_reporter->Report( _( "Successfully created genCAD file\n" ), RPT_SEVERITY_INFO );
1460
1461 return CLI::EXIT_CODES::OK;
1462}
1463
1464
1466{
1467 JOB_EXPORT_PCB_STATS* statsJob = dynamic_cast<JOB_EXPORT_PCB_STATS*>( aJob );
1468
1469 if( statsJob == nullptr )
1471
1472 BOARD* brd = getBoard( statsJob->m_filename );
1473
1474 if( !brd )
1476
1479
1484
1485 ComputeBoardStatistics( brd, options, data );
1486
1487 wxString projectName;
1488
1489 if( brd->GetProject() )
1490 projectName = brd->GetProject()->GetProjectName();
1491
1492 wxFileName boardFile = brd->GetFileName();
1493
1494 if( boardFile.GetName().IsEmpty() )
1495 boardFile = wxFileName( statsJob->m_filename );
1496
1498 UNITS_PROVIDER unitsProvider( pcbIUScale, unitsForReport );
1499
1500 wxString report;
1501
1503 report = FormatBoardStatisticsJson( data, brd, unitsProvider, projectName, boardFile.GetName() );
1504 else
1505 report = FormatBoardStatisticsReport( data, brd, unitsProvider, projectName, boardFile.GetName() );
1506
1507 if( statsJob->GetConfiguredOutputPath().IsEmpty() && statsJob->GetWorkingOutputPath().IsEmpty() )
1508 statsJob->SetDefaultOutputPath( boardFile.GetFullPath() );
1509
1510 wxString outPath = resolveJobOutputPath( aJob, brd );
1511
1512 if( !PATHS::EnsurePathExists( outPath, true ) )
1513 {
1514 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1516 }
1517
1518 FILE* outFile = wxFopen( outPath, wxS( "wt" ) );
1519
1520 if( !outFile )
1521 {
1522 m_reporter->Report( wxString::Format( _( "Failed to create file '%s'.\n" ), outPath ), RPT_SEVERITY_ERROR );
1524 }
1525
1526 if( fprintf( outFile, "%s", TO_UTF8( report ) ) < 0 )
1527 {
1528 fclose( outFile );
1529 m_reporter->Report( wxString::Format( _( "Error writing file '%s'.\n" ), outPath ), RPT_SEVERITY_ERROR );
1531 }
1532
1533 fclose( outFile );
1534
1535 m_reporter->Report( wxString::Format( _( "Wrote board statistics to '%s'.\n" ), outPath ), RPT_SEVERITY_ACTION );
1536
1537 statsJob->AddOutput( outPath );
1538
1539 return CLI::EXIT_CODES::OK;
1540}
1541
1542
1544{
1545 int exitCode = CLI::EXIT_CODES::OK;
1546 JOB_EXPORT_PCB_GERBER* aGerberJob = dynamic_cast<JOB_EXPORT_PCB_GERBER*>( aJob );
1547
1548 if( aGerberJob == nullptr )
1550
1551 BOARD* brd = getBoard( aGerberJob->m_filename );
1552
1553 if( !brd )
1555
1556 TOOL_MANAGER* toolManager = getToolManager( brd );
1557
1558 if( aGerberJob->m_argLayers )
1559 aGerberJob->m_plotLayerSequence = convertLayerArg( aGerberJob->m_argLayers.value(), brd );
1560
1561 if( aGerberJob->m_argCommonLayers )
1562 aGerberJob->m_plotOnAllLayersSequence = convertLayerArg( aGerberJob->m_argCommonLayers.value(), brd );
1563
1564 if( aGerberJob->m_plotLayerSequence.size() < 1 )
1565 {
1566 m_reporter->Report( _( "At least one layer must be specified\n" ), RPT_SEVERITY_ERROR );
1568 }
1569
1570 if( aGerberJob->GetConfiguredOutputPath().IsEmpty() )
1571 {
1572 wxFileName fn = brd->GetFileName();
1573 fn.SetName( fn.GetName() );
1575
1576 aGerberJob->SetWorkingOutputPath( fn.GetFullName() );
1577 }
1578
1579 wxString outPath = resolveJobOutputPath( aJob, brd );
1580
1581 if( aGerberJob->m_checkZonesBeforePlot )
1582 {
1583 if( !toolManager->FindTool( ZONE_FILLER_TOOL_NAME ) )
1584 toolManager->RegisterTool( new ZONE_FILLER_TOOL );
1585
1586 toolManager->GetTool<ZONE_FILLER_TOOL>()->CheckAllZones( nullptr );
1587 }
1588
1589 PCB_PLOT_PARAMS plotOpts;
1590 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, aGerberJob, *m_reporter );
1591 plotOpts.SetLayerSelection( aGerberJob->m_plotLayerSequence );
1593
1595 wxString layerName;
1596 wxString sheetName;
1597 wxString sheetPath;
1598
1599 // The first layer will be treated as the layer name for the gerber header,
1600 // the other layers will be treated equivalent to the "Plot on All Layers" option
1601 // in the GUI
1602 if( aGerberJob->m_plotLayerSequence.size() >= 1 )
1603 {
1604 layer = aGerberJob->m_plotLayerSequence.front();
1605 layerName = brd->GetLayerName( layer );
1606 }
1607
1608 if( aJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
1609 layerName = aJob->GetVarOverrides().at( wxT( "LAYER" ) );
1610
1611 if( aJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
1612 sheetName = aJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
1613
1614 if( aJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
1615 sheetPath = aJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
1616
1617 // We are feeding it one layer at the start here to silence a logic check
1618 PLOTTER* plotter = StartPlotBoard( brd, &plotOpts, layer, layerName, outPath, sheetName,
1619 sheetPath );
1620
1621 if( plotter )
1622 {
1623 PlotBoardLayers( brd, plotter, aGerberJob->m_plotLayerSequence, plotOpts );
1624 plotter->EndPlot();
1625 }
1626 else
1627 {
1628 m_reporter->Report( wxString::Format( _( "Failed to plot to '%s'.\n" ), outPath ),
1631 }
1632
1633 delete plotter;
1634
1635 return exitCode;
1636}
1637
1640
1641
1643{
1644 JOB_EXPORT_PCB_DRILL* aDrillJob = dynamic_cast<JOB_EXPORT_PCB_DRILL*>( aJob );
1645
1646 if( aDrillJob == nullptr )
1648
1649 BOARD* brd = getBoard( aDrillJob->m_filename );
1650
1651 if( !brd )
1653
1654 wxString outPath = resolveJobOutputPath( aJob, brd );
1655
1656 if( !PATHS::EnsurePathExists( outPath ) )
1657 {
1658 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1660 }
1661
1662 std::unique_ptr<GENDRILL_WRITER_BASE> drillWriter;
1663
1665 drillWriter = std::make_unique<EXCELLON_WRITER>( brd );
1666 else
1667 drillWriter = std::make_unique<GERBER_WRITER>( brd );
1668
1669 VECTOR2I offset;
1670
1672 offset = VECTOR2I( 0, 0 );
1673 else
1674 offset = brd->GetDesignSettings().GetAuxOrigin();
1675
1676 PLOT_FORMAT mapFormat = PLOT_FORMAT::PDF;
1677
1678 switch( aDrillJob->m_mapFormat )
1679 {
1684 default:
1686 }
1687
1689 {
1691 switch( aDrillJob->m_zeroFormat )
1692 {
1695 break;
1698 break;
1701 break;
1703 default:
1705 break;
1706 }
1707
1708 DRILL_PRECISION precision;
1709
1711 precision = precisionListForInches;
1712 else
1713 precision = precisionListForMetric;
1714
1715 EXCELLON_WRITER* excellonWriter = dynamic_cast<EXCELLON_WRITER*>( drillWriter.get() );
1716
1717 if( excellonWriter == nullptr )
1719
1720 excellonWriter->SetFormat( aDrillJob->m_drillUnits == JOB_EXPORT_PCB_DRILL::DRILL_UNITS::MM,
1721 zeroFmt, precision.m_Lhs, precision.m_Rhs );
1722 excellonWriter->SetOptions( aDrillJob->m_excellonMirrorY,
1723 aDrillJob->m_excellonMinimalHeader,
1724 offset, aDrillJob->m_excellonCombinePTHNPTH );
1725 excellonWriter->SetRouteModeForOvalHoles( aDrillJob->m_excellonOvalDrillRoute );
1726 excellonWriter->SetMapFileFormat( mapFormat );
1727
1728 if( !excellonWriter->CreateDrillandMapFilesSet( outPath, true, aDrillJob->m_generateMap,
1729 m_reporter ) )
1730 {
1732 }
1733 }
1735 {
1736 GERBER_WRITER* gerberWriter = dynamic_cast<GERBER_WRITER*>( drillWriter.get() );
1737
1738 if( gerberWriter == nullptr )
1740
1741 // Set gerber precision: only 5 or 6 digits for mantissa are allowed
1742 // (SetFormat() accept 5 or 6, and any other value set the precision to 5)
1743 // the integer part precision is always 4, and units always mm
1744 gerberWriter->SetFormat( aDrillJob->m_gerberPrecision );
1745 gerberWriter->SetOptions( offset );
1746 gerberWriter->SetMapFileFormat( mapFormat );
1747
1748 if( !gerberWriter->CreateDrillandMapFilesSet( outPath, true, aDrillJob->m_generateMap,
1749 aDrillJob->m_generateTenting, m_reporter ) )
1750 {
1752 }
1753 }
1754
1755 return CLI::EXIT_CODES::OK;
1756}
1757
1758
1760{
1761 JOB_EXPORT_PCB_POS* aPosJob = dynamic_cast<JOB_EXPORT_PCB_POS*>( aJob );
1762
1763 if( aPosJob == nullptr )
1765
1766 BOARD* brd = getBoard( aPosJob->m_filename );
1767
1768 if( !brd )
1770
1771 if( aPosJob->GetConfiguredOutputPath().IsEmpty() )
1772 {
1773 wxFileName fn = brd->GetFileName();
1774 fn.SetName( fn.GetName() );
1775
1778 else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::CSV )
1779 fn.SetExt( FILEEXT::CsvFileExtension );
1780 else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::GERBER )
1781 fn.SetExt( FILEEXT::GerberFileExtension );
1782
1783 aPosJob->SetWorkingOutputPath( fn.GetFullName() );
1784 }
1785
1786 wxString outPath = resolveJobOutputPath( aJob, brd );
1787
1788 if( !PATHS::EnsurePathExists( outPath, true ) )
1789 {
1790 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1792 }
1793
1796 {
1797 wxFileName fn( outPath );
1798 wxString baseName = fn.GetName();
1799
1800 auto exportPlaceFile =
1801 [&]( bool frontSide, bool backSide, const wxString& curr_outPath ) -> bool
1802 {
1803 FILE* file = wxFopen( curr_outPath, wxS( "wt" ) );
1804 wxCHECK( file, false );
1805
1806 PLACE_FILE_EXPORTER exporter( brd,
1808 aPosJob->m_smdOnly,
1810 aPosJob->m_excludeDNP,
1811 aPosJob->m_excludeBOM,
1812 frontSide,
1813 backSide,
1816 aPosJob->m_negateBottomX );
1817
1818 std::string data = exporter.GenPositionData();
1819 fputs( data.c_str(), file );
1820 fclose( file );
1821
1822 return true;
1823 };
1824
1825 if( aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH && !aPosJob->m_singleFile )
1826 {
1827 fn.SetName( PLACE_FILE_EXPORTER::DecorateFilename( baseName, true, false ) );
1828
1829 if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::CSV && !aPosJob->m_nakedFilename )
1830 fn.SetName( fn.GetName() + wxT( "-" ) + FILEEXT::FootprintPlaceFileExtension );
1831
1832 if( exportPlaceFile( true, false, fn.GetFullPath() ) )
1833 {
1834 m_reporter->Report( wxString::Format( _( "Wrote front position data to '%s'.\n" ),
1835 fn.GetFullPath() ),
1837
1838 aPosJob->AddOutput( fn.GetFullPath() );
1839 }
1840 else
1841 {
1843 }
1844
1845 fn.SetName( PLACE_FILE_EXPORTER::DecorateFilename( baseName, false, true ) );
1846
1847 if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::CSV && !aPosJob->m_nakedFilename )
1848 fn.SetName( fn.GetName() + wxT( "-" ) + FILEEXT::FootprintPlaceFileExtension );
1849
1850 if( exportPlaceFile( false, true, fn.GetFullPath() ) )
1851 {
1852 m_reporter->Report( wxString::Format( _( "Wrote back position data to '%s'.\n" ),
1853 fn.GetFullPath() ),
1855
1856 aPosJob->AddOutput( fn.GetFullPath() );
1857 }
1858 else
1859 {
1861 }
1862 }
1863 else
1864 {
1865 bool front = aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::FRONT
1867
1868 bool back = aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BACK
1870
1871 if( !aPosJob->m_nakedFilename )
1872 {
1873 fn.SetName( PLACE_FILE_EXPORTER::DecorateFilename( fn.GetName(), front, back ) );
1874
1876 fn.SetName( fn.GetName() + wxT( "-" ) + FILEEXT::FootprintPlaceFileExtension );
1877 }
1878
1879 if( exportPlaceFile( front, back, fn.GetFullPath() ) )
1880 {
1881 m_reporter->Report( wxString::Format( _( "Wrote position data to '%s'.\n" ),
1882 fn.GetFullPath() ),
1884
1885 aPosJob->AddOutput( fn.GetFullPath() );
1886 }
1887 else
1888 {
1890 }
1891 }
1892 }
1893 else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::GERBER )
1894 {
1895 PLACEFILE_GERBER_WRITER exporter( brd );
1896 PCB_LAYER_ID gbrLayer = F_Cu;
1897 wxString outPath_base = outPath;
1898
1900 || aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH )
1901 {
1902 if( aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH || !aPosJob->m_nakedFilename )
1903 outPath = exporter.GetPlaceFileName( outPath, gbrLayer );
1904
1905 if( exporter.CreatePlaceFile( outPath, gbrLayer, aPosJob->m_gerberBoardEdge,
1906 aPosJob->m_excludeDNP, aPosJob->m_excludeBOM ) >= 0 )
1907 {
1908 m_reporter->Report( wxString::Format( _( "Wrote front position data to '%s'.\n" ), outPath ),
1910
1911 aPosJob->AddOutput( outPath );
1912 }
1913 else
1914 {
1916 }
1917 }
1918
1920 || aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH )
1921 {
1922 gbrLayer = B_Cu;
1923
1924 outPath = outPath_base;
1925
1926 if( aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH || !aPosJob->m_nakedFilename )
1927 outPath = exporter.GetPlaceFileName( outPath, gbrLayer );
1928
1929 if( exporter.CreatePlaceFile( outPath, gbrLayer, aPosJob->m_gerberBoardEdge,
1930 aPosJob->m_excludeDNP, aPosJob->m_excludeBOM ) >= 0 )
1931 {
1932 m_reporter->Report( wxString::Format( _( "Wrote back position data to '%s'.\n" ), outPath ),
1934
1935 aPosJob->AddOutput( outPath );
1936 }
1937 else
1938 {
1940 }
1941 }
1942 }
1943
1944 return CLI::EXIT_CODES::OK;
1945}
1946
1947
1949{
1950 JOB_FP_UPGRADE* upgradeJob = dynamic_cast<JOB_FP_UPGRADE*>( aJob );
1951
1952 if( upgradeJob == nullptr )
1954
1956
1957 if( !upgradeJob->m_outputLibraryPath.IsEmpty() )
1958 {
1959 if( wxFile::Exists( upgradeJob->m_outputLibraryPath )
1960 || wxDir::Exists( upgradeJob->m_outputLibraryPath) )
1961 {
1962 m_reporter->Report( _( "Output path must not conflict with existing path\n" ),
1965 }
1966 }
1967 else if( fileType != PCB_IO_MGR::KICAD_SEXP )
1968 {
1969 m_reporter->Report( _( "Output path must be specified to convert legacy and non-KiCad libraries\n" ),
1971
1973 }
1974
1976 {
1977 if( !wxDir::Exists( upgradeJob->m_libraryPath ) )
1978 {
1979 m_reporter->Report( _( "Footprint library path does not exist or is not accessible\n" ),
1982 }
1983
1985 FP_CACHE fpLib( &pcb_io, upgradeJob->m_libraryPath );
1986
1987 try
1988 {
1989 fpLib.Load();
1990 }
1991 catch( ... )
1992 {
1993 m_reporter->Report( _( "Unable to load library\n" ), RPT_SEVERITY_ERROR );
1995 }
1996
1997 if( m_progressReporter )
1998 m_progressReporter->KeepRefreshing();
1999
2000 bool shouldSave = upgradeJob->m_force;
2001
2002 for( const auto& footprint : fpLib.GetFootprints() )
2003 {
2004 if( footprint.second->GetFootprint()->GetFileFormatVersionAtLoad() < SEXPR_BOARD_FILE_VERSION )
2005 shouldSave = true;
2006 }
2007
2008 if( shouldSave )
2009 {
2010 try
2011 {
2012 if( !upgradeJob->m_outputLibraryPath.IsEmpty() )
2013 fpLib.SetPath( upgradeJob->m_outputLibraryPath );
2014
2015 fpLib.Save();
2016 }
2017 catch( ... )
2018 {
2019 m_reporter->Report( _( "Unable to save library\n" ), RPT_SEVERITY_ERROR );
2021 }
2022 }
2023 else
2024 {
2025 m_reporter->Report( _( "Footprint library was not updated\n" ), RPT_SEVERITY_ERROR );
2026 }
2027 }
2028 else
2029 {
2030 if( !PCB_IO_MGR::ConvertLibrary( {}, upgradeJob->m_libraryPath,
2031 upgradeJob->m_outputLibraryPath, nullptr /* REPORTER */ ) )
2032 {
2033 m_reporter->Report( ( "Unable to convert library\n" ), RPT_SEVERITY_ERROR );
2035 }
2036 }
2037
2038 return CLI::EXIT_CODES::OK;
2039}
2040
2041
2043{
2044 JOB_FP_EXPORT_SVG* svgJob = dynamic_cast<JOB_FP_EXPORT_SVG*>( aJob );
2045
2046 if( svgJob == nullptr )
2048
2050 FP_CACHE fpLib( &pcb_io, svgJob->m_libraryPath );
2051
2052 if( svgJob->m_argLayers )
2053 {
2054 if( !svgJob->m_argLayers.value().empty() )
2055 svgJob->m_plotLayerSequence = convertLayerArg( svgJob->m_argLayers.value(), nullptr );
2056 else
2058 }
2059
2060 try
2061 {
2062 fpLib.Load();
2063 }
2064 catch( ... )
2065 {
2066 m_reporter->Report( _( "Unable to load library\n" ), RPT_SEVERITY_ERROR );
2068 }
2069
2070 wxString outPath = svgJob->GetFullOutputPath( nullptr );
2071
2072 if( !PATHS::EnsurePathExists( outPath, true ) )
2073 {
2074 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
2076 }
2077
2078 int exitCode = CLI::EXIT_CODES::OK;
2079 bool singleFpPlotted = false;
2080
2081 for( const auto& [fpName, fpCacheEntry] : fpLib.GetFootprints() )
2082 {
2083 if( m_progressReporter )
2084 {
2085 m_progressReporter->AdvancePhase( wxString::Format( _( "Exporting %s" ), fpName ) );
2086 m_progressReporter->KeepRefreshing();
2087 }
2088
2089 if( !svgJob->m_footprint.IsEmpty() )
2090 {
2091 // skip until we find the right footprint
2092 if( fpName != svgJob->m_footprint )
2093 continue;
2094 else
2095 singleFpPlotted = true;
2096 }
2097
2098 exitCode = doFpExportSvg( svgJob, fpCacheEntry->GetFootprint().get() );
2099
2100 if( exitCode != CLI::EXIT_CODES::OK )
2101 break;
2102 }
2103
2104 if( !svgJob->m_footprint.IsEmpty() && !singleFpPlotted )
2105 {
2106 m_reporter->Report( _( "The given footprint could not be found to export." ) + wxS( "\n" ),
2108 }
2109
2110 return CLI::EXIT_CODES::OK;
2111}
2112
2113
2115{
2116 // the hack for now is we create fake boards containing the footprint and plot the board
2117 // until we refactor better plot api later
2118 std::unique_ptr<BOARD> brd;
2119 brd.reset( CreateEmptyBoard() );
2120 brd->GetProject()->ApplyTextVars( aSvgJob->GetVarOverrides() );
2121 brd->SynchronizeProperties();
2122
2123 FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( aFootprint->Clone() );
2124
2125 if( fp == nullptr )
2127
2128 fp->SetLink( niluuid );
2129 fp->SetFlags( IS_NEW );
2130 fp->SetParent( brd.get() );
2131
2132 for( PAD* pad : fp->Pads() )
2133 {
2134 pad->SetLocalRatsnestVisible( false );
2135 pad->SetNetCode( 0 );
2136 }
2137
2138 fp->SetOrientation( ANGLE_0 );
2139 fp->SetPosition( VECTOR2I( 0, 0 ) );
2140
2141 brd->Add( fp, ADD_MODE::INSERT, true );
2142
2143 wxFileName outputFile;
2144 outputFile.SetPath( aSvgJob->GetFullOutputPath(nullptr) );
2145 outputFile.SetName( aFootprint->GetFPID().GetLibItemName().wx_str() );
2146 outputFile.SetExt( FILEEXT::SVGFileExtension );
2147
2148 m_reporter->Report( wxString::Format( _( "Plotting footprint '%s' to '%s'\n" ),
2149 aFootprint->GetFPID().GetLibItemName().wx_str(),
2150 outputFile.GetFullPath() ),
2152
2153 PCB_PLOT_PARAMS plotOpts;
2154 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, aSvgJob, *m_reporter );
2155
2156 // always fixed for the svg plot
2157 plotOpts.SetPlotFrameRef( false );
2158 plotOpts.SetSvgFitPageToBoard( true );
2159 plotOpts.SetMirror( false );
2160 plotOpts.SetSkipPlotNPTH_Pads( false );
2161
2162 if( plotOpts.GetSketchPadsOnFabLayers() )
2163 {
2164 plotOpts.SetPlotPadNumbers( true );
2165 }
2166
2167 PCB_PLOTTER plotter( brd.get(), m_reporter, plotOpts );
2168
2169 if( !plotter.Plot( outputFile.GetFullPath(),
2170 aSvgJob->m_plotLayerSequence,
2172 false,
2173 true,
2174 wxEmptyString, wxEmptyString,
2175 wxEmptyString ) )
2176 {
2177 m_reporter->Report( _( "Error creating svg file" ) + wxS( "\n" ), RPT_SEVERITY_ERROR );
2179 }
2180
2181 return CLI::EXIT_CODES::OK;
2182}
2183
2184
2186{
2187 JOB_PCB_DRC* drcJob = dynamic_cast<JOB_PCB_DRC*>( aJob );
2188
2189 if( drcJob == nullptr )
2191
2192 BOARD* brd = getBoard( drcJob->m_filename );
2193
2194 if( !brd )
2196
2197 if( drcJob->GetConfiguredOutputPath().IsEmpty() )
2198 {
2199 wxFileName fn = brd->GetFileName();
2200 fn.SetName( fn.GetName() + wxS( "-drc" ) );
2201
2203 fn.SetExt( FILEEXT::JsonFileExtension );
2204 else
2205 fn.SetExt( FILEEXT::ReportFileExtension );
2206
2207 drcJob->SetWorkingOutputPath( fn.GetFullName() );
2208 }
2209
2210 wxString outPath = resolveJobOutputPath( aJob, brd );
2211
2212 if( !PATHS::EnsurePathExists( outPath, true ) )
2213 {
2214 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
2216 }
2217
2218 EDA_UNITS units;
2219
2220 switch( drcJob->m_units )
2221 {
2222 case JOB_PCB_DRC::UNITS::INCH: units = EDA_UNITS::INCH; break;
2223 case JOB_PCB_DRC::UNITS::MILS: units = EDA_UNITS::MILS; break;
2224 case JOB_PCB_DRC::UNITS::MM: units = EDA_UNITS::MM; break;
2225 default: units = EDA_UNITS::MM; break;
2226 }
2227
2228 std::shared_ptr<DRC_ENGINE> drcEngine = brd->GetDesignSettings().m_DRCEngine;
2229 std::unique_ptr<NETLIST> netlist = std::make_unique<NETLIST>();
2230
2231 drcEngine->SetDrawingSheet( getDrawingSheetProxyView( brd ) );
2232
2233 // BOARD_COMMIT uses TOOL_MANAGER to grab the board internally so we must give it one
2234 TOOL_MANAGER* toolManager = getToolManager( brd );
2235
2236 BOARD_COMMIT commit( toolManager );
2237 bool checkParity = drcJob->m_parity;
2238 std::string netlist_str;
2239
2240 if( checkParity )
2241 {
2242 wxString annotateMsg = _( "Schematic parity tests require a fully annotated schematic." );
2243 netlist_str = annotateMsg;
2244
2245 // The KIFACE_NETLIST_SCHEMATIC function has some broken-ness that the schematic
2246 // frame's version does not, but it is the only one that works in CLI, so we use it
2247 // if we don't have the sch frame open.
2248 // TODO: clean this up, see https://gitlab.com/kicad/code/kicad/-/issues/19929
2249 if( m_kiway->Player( FRAME_SCH, false ) )
2250 {
2251 m_kiway->ExpressMail( FRAME_SCH, MAIL_SCH_GET_NETLIST, netlist_str );
2252 }
2253 else
2254 {
2255 wxFileName schematicPath( drcJob->m_filename );
2256 schematicPath.SetExt( FILEEXT::KiCadSchematicFileExtension );
2257
2258 if( !schematicPath.Exists() )
2259 schematicPath.SetExt( FILEEXT::LegacySchematicFileExtension );
2260
2261 if( !schematicPath.Exists() )
2262 {
2263 m_reporter->Report( _( "Failed to fetch schematic netlist for parity tests.\n" ),
2265 checkParity = false;
2266 }
2267 else
2268 {
2269 typedef bool ( *NETLIST_FN_PTR )( const wxString&, std::string& );
2270 KIFACE* eeschema = m_kiway->KiFACE( KIWAY::FACE_SCH );
2271 NETLIST_FN_PTR netlister =
2272 (NETLIST_FN_PTR) eeschema->IfaceOrAddress( KIFACE_NETLIST_SCHEMATIC );
2273 ( *netlister )( schematicPath.GetFullPath(), netlist_str );
2274 }
2275 }
2276
2277 if( netlist_str == annotateMsg )
2278 {
2279 m_reporter->Report( wxString( netlist_str ) + wxT( "\n" ), RPT_SEVERITY_ERROR );
2280 checkParity = false;
2281 }
2282 }
2283
2284 if( checkParity )
2285 {
2286 try
2287 {
2288 STRING_LINE_READER* lineReader = new STRING_LINE_READER( netlist_str,
2289 _( "Eeschema netlist" ) );
2290 KICAD_NETLIST_READER netlistReader( lineReader, netlist.get() );
2291
2292 netlistReader.LoadNetlist();
2293 }
2294 catch( const IO_ERROR& )
2295 {
2296 m_reporter->Report( _( "Failed to fetch schematic netlist for parity tests.\n" ),
2298 checkParity = false;
2299 }
2300
2301 drcEngine->SetSchematicNetlist( netlist.get() );
2302 }
2303
2304 if( drcJob->m_refillZones )
2305 {
2306 if( !toolManager->FindTool( ZONE_FILLER_TOOL_NAME ) )
2307 toolManager->RegisterTool( new ZONE_FILLER_TOOL );
2308
2309 toolManager->GetTool<ZONE_FILLER_TOOL>()->FillAllZones( nullptr, m_progressReporter, true );
2310 }
2311
2312 drcEngine->SetProgressReporter( m_progressReporter );
2313 drcEngine->SetViolationHandler(
2314 [&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
2315 const std::function<void( PCB_MARKER* )>& aPathGenerator )
2316 {
2317 PCB_MARKER* marker = new PCB_MARKER( aItem, aPos, aLayer );
2318 aPathGenerator( marker );
2319 commit.Add( marker );
2320 } );
2321
2322 brd->RecordDRCExclusions();
2323 brd->DeleteMARKERs( true, true );
2324 drcEngine->RunTests( units, drcJob->m_reportAllTrackErrors, checkParity );
2325 drcEngine->ClearViolationHandler();
2326
2327 commit.Push( _( "DRC" ), SKIP_UNDO | SKIP_SET_DIRTY );
2328
2329 // Update the exclusion status on any excluded markers that still exist.
2330 brd->ResolveDRCExclusions( false );
2331
2332 std::shared_ptr<DRC_ITEMS_PROVIDER> markersProvider = std::make_shared<DRC_ITEMS_PROVIDER>(
2334
2335 std::shared_ptr<DRC_ITEMS_PROVIDER> ratsnestProvider =
2336 std::make_shared<DRC_ITEMS_PROVIDER>( brd, MARKER_BASE::MARKER_RATSNEST );
2337
2338 std::shared_ptr<DRC_ITEMS_PROVIDER> fpWarningsProvider =
2339 std::make_shared<DRC_ITEMS_PROVIDER>( brd, MARKER_BASE::MARKER_PARITY );
2340
2341 markersProvider->SetSeverities( drcJob->m_severity );
2342 ratsnestProvider->SetSeverities( drcJob->m_severity );
2343 fpWarningsProvider->SetSeverities( drcJob->m_severity );
2344
2345 m_reporter->Report( wxString::Format( _( "Found %d violations\n" ),
2346 markersProvider->GetCount() ),
2348 m_reporter->Report( wxString::Format( _( "Found %d unconnected items\n" ),
2349 ratsnestProvider->GetCount() ),
2351
2352 if( checkParity )
2353 {
2354 m_reporter->Report( wxString::Format( _( "Found %d schematic parity issues\n" ),
2355 fpWarningsProvider->GetCount() ),
2357 }
2358
2359 DRC_REPORT reportWriter( brd, units, markersProvider, ratsnestProvider, fpWarningsProvider );
2360
2361 bool wroteReport = false;
2362
2364 wroteReport = reportWriter.WriteJsonReport( outPath );
2365 else
2366 wroteReport = reportWriter.WriteTextReport( outPath );
2367
2368 if( !wroteReport )
2369 {
2370 m_reporter->Report( wxString::Format( _( "Unable to save DRC report to %s\n" ), outPath ),
2373 }
2374
2375 m_reporter->Report( wxString::Format( _( "Saved DRC Report to %s\n" ), outPath ),
2377
2378 if( drcJob->m_refillZones && drcJob->m_saveBoard )
2379 {
2380 if( SaveBoard( drcJob->m_filename, brd, true ) )
2381 {
2382 m_reporter->Report( _( "Saved board\n" ), RPT_SEVERITY_ACTION );
2383 }
2384 else
2385 {
2386 m_reporter->Report( _( "Failed to save board.\n" ), RPT_SEVERITY_ERROR );
2387
2389 }
2390 }
2391
2392 if( drcJob->m_exitCodeViolations )
2393 {
2394 if( markersProvider->GetCount() > 0 || ratsnestProvider->GetCount() > 0
2395 || fpWarningsProvider->GetCount() > 0 )
2396 {
2398 }
2399 }
2400
2402}
2403
2404
2406{
2407 JOB_EXPORT_PCB_IPC2581* job = dynamic_cast<JOB_EXPORT_PCB_IPC2581*>( aJob );
2408
2409 if( job == nullptr )
2411
2412 BOARD* brd = getBoard( job->m_filename );
2413
2414 if( !brd )
2416
2417 if( job->GetConfiguredOutputPath().IsEmpty() )
2418 {
2419 wxFileName fn = brd->GetFileName();
2420 fn.SetName( fn.GetName() );
2421 fn.SetExt( FILEEXT::Ipc2581FileExtension );
2422
2423 job->SetWorkingOutputPath( fn.GetName() );
2424 }
2425
2426 wxString outPath = resolveJobOutputPath( aJob, brd );
2427
2428 if( !PATHS::EnsurePathExists( outPath, true ) )
2429 {
2430 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
2432 }
2433
2434 std::map<std::string, UTF8> props;
2435 props["units"] = job->m_units == JOB_EXPORT_PCB_IPC2581::IPC2581_UNITS::MM ? "mm" : "inch";
2436 props["sigfig"] = wxString::Format( "%d", job->m_precision );
2437 props["version"] = job->m_version == JOB_EXPORT_PCB_IPC2581::IPC2581_VERSION::C ? "C" : "B";
2438 props["OEMRef"] = job->m_colInternalId;
2439 props["mpn"] = job->m_colMfgPn;
2440 props["mfg"] = job->m_colMfg;
2441 props["dist"] = job->m_colDist;
2442 props["distpn"] = job->m_colDistPn;
2443
2444 wxString tempFile = wxFileName::CreateTempFileName( wxS( "pcbnew_ipc" ) );
2445 try
2446 {
2448 pi->SetProgressReporter( m_progressReporter );
2449 pi->SaveBoard( tempFile, brd, &props );
2450 }
2451 catch( const IO_ERROR& ioe )
2452 {
2453 m_reporter->Report( wxString::Format( _( "Error generating IPC-2581 file '%s'.\n%s" ),
2454 job->m_filename,
2455 ioe.What() ),
2457
2458 wxRemoveFile( tempFile );
2459
2461 }
2462
2463 if( job->m_compress )
2464 {
2465 wxFileName tempfn = outPath;
2466 tempfn.SetExt( FILEEXT::Ipc2581FileExtension );
2467 wxFileName zipfn = tempFile;
2468 zipfn.SetExt( "zip" );
2469
2470 {
2471 wxFFileOutputStream fnout( zipfn.GetFullPath() );
2472 wxZipOutputStream zip( fnout );
2473 wxFFileInputStream fnin( tempFile );
2474
2475 zip.PutNextEntry( tempfn.GetFullName() );
2476 fnin.Read( zip );
2477 }
2478
2479 wxRemoveFile( tempFile );
2480 tempFile = zipfn.GetFullPath();
2481 }
2482
2483 // If save succeeded, replace the original with what we just wrote
2484 if( !wxRenameFile( tempFile, outPath ) )
2485 {
2486 m_reporter->Report( wxString::Format( _( "Error generating IPC-2581 file '%s'.\n"
2487 "Failed to rename temporary file '%s." ),
2488 outPath,
2489 tempFile ),
2491 }
2492
2494}
2495
2496
2498{
2499 JOB_EXPORT_PCB_IPCD356* job = dynamic_cast<JOB_EXPORT_PCB_IPCD356*>( aJob );
2500
2501 if( job == nullptr )
2503
2504 BOARD* brd = getBoard( job->m_filename );
2505
2506 if( !brd )
2508
2509 if( job->GetConfiguredOutputPath().IsEmpty() )
2510 {
2511 wxFileName fn = brd->GetFileName();
2512 fn.SetName( fn.GetName() );
2513 fn.SetExt( FILEEXT::IpcD356FileExtension );
2514
2515 job->SetWorkingOutputPath( fn.GetFullName() );
2516 }
2517
2518 wxString outPath = resolveJobOutputPath( aJob, brd );
2519
2520 if( !PATHS::EnsurePathExists( outPath, true ) )
2521 {
2522 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
2524 }
2525
2526 IPC356D_WRITER exporter( brd );
2527
2528 bool success = exporter.Write( outPath );
2529
2530 if( success )
2531 {
2532 m_reporter->Report( _( "Successfully created IPC-D-356 file\n" ), RPT_SEVERITY_INFO );
2534 }
2535 else
2536 {
2537 m_reporter->Report( _( "Failed to create IPC-D-356 file\n" ), RPT_SEVERITY_ERROR );
2539 }
2540}
2541
2542
2544{
2545 JOB_EXPORT_PCB_ODB* job = dynamic_cast<JOB_EXPORT_PCB_ODB*>( aJob );
2546
2547 if( job == nullptr )
2549
2550 BOARD* brd = getBoard( job->m_filename );
2551
2552 if( !brd )
2554
2555 if( job->GetConfiguredOutputPath().IsEmpty() )
2556 {
2558 {
2559 // just basic folder name
2560 job->SetWorkingOutputPath( "odb" );
2561 }
2562 else
2563 {
2564 wxFileName fn( brd->GetFileName() );
2565 fn.SetName( fn.GetName() + wxS( "-odb" ) );
2566
2567 switch( job->m_compressionMode )
2568 {
2570 fn.SetExt( FILEEXT::ArchiveFileExtension );
2571 break;
2573 fn.SetExt( "tgz" );
2574 break;
2575 default:
2576 break;
2577 };
2578
2579 job->SetWorkingOutputPath( fn.GetFullName() );
2580 }
2581 }
2582
2583 resolveJobOutputPath( job, brd );
2584
2585 // The helper handles output path creation, so hand it a job that already has fully-resolved
2586 // token context (title block and project overrides applied above).
2588
2590}
2591
2593{
2594 JOB_PCB_UPGRADE* job = dynamic_cast<JOB_PCB_UPGRADE*>( aJob );
2595
2596 if( job == nullptr )
2598
2599 bool shouldSave = job->m_force;
2600
2601 try
2602 {
2604 BOARD* brd = getBoard( job->m_filename );
2606 shouldSave = true;
2607
2608 if( shouldSave )
2609 {
2610 pi->SaveBoard( brd->GetFileName(), brd );
2611 m_reporter->Report( _( "Successfully saved board file using the latest format\n" ), RPT_SEVERITY_INFO );
2612 }
2613 else
2614 {
2615 m_reporter->Report( _( "Board file was not updated\n" ), RPT_SEVERITY_ERROR );
2616 }
2617 }
2618 catch( const IO_ERROR& ioe )
2619 {
2620 wxString msg =
2621 wxString::Format( _( "Error saving board file '%s'.\n%s" ), job->m_filename, ioe.What().GetData() );
2622 m_reporter->Report( msg, RPT_SEVERITY_ERROR );
2624 }
2625
2627}
2628
2629// Most job handlers need to align the running job with the board before resolving any
2630// output paths with variables in them like ${REVISION}.
2631wxString PCBNEW_JOBS_HANDLER::resolveJobOutputPath( JOB* aJob, BOARD* aBoard, const wxString* aDrawingSheet )
2632{
2633 aJob->SetTitleBlock( aBoard->GetTitleBlock() );
2634
2635 if( aDrawingSheet && !aDrawingSheet->IsEmpty() )
2636 loadOverrideDrawingSheet( aBoard, *aDrawingSheet );
2637
2638 PROJECT* project = aBoard->GetProject();
2639
2640 if( project )
2641 project->ApplyTextVars( aJob->GetVarOverrides() );
2642
2643 aBoard->SynchronizeProperties();
2644
2645 return aJob->GetFullOutputPath( project );
2646}
2647
2649{
2651 &aBrd->GetPageSettings(),
2652 aBrd->GetProject(),
2653 &aBrd->GetTitleBlock(),
2654 &aBrd->GetProperties() );
2655
2656 drawingSheet->SetSheetName( std::string() );
2657 drawingSheet->SetSheetPath( std::string() );
2658 drawingSheet->SetIsFirstPage( true );
2659
2660 drawingSheet->SetFileName( TO_UTF8( aBrd->GetFileName() ) );
2661
2662 return drawingSheet;
2663}
2664
2665
2666void PCBNEW_JOBS_HANDLER::loadOverrideDrawingSheet( BOARD* aBrd, const wxString& aSheetPath )
2667{
2668 // dont bother attempting to load a empty path, if there was one
2669 if( aSheetPath.IsEmpty() )
2670 return;
2671
2672 auto loadSheet =
2673 [&]( const wxString& path ) -> bool
2674 {
2677 resolver.SetProject( aBrd->GetProject() );
2678 resolver.SetProgramBase( &Pgm() );
2679
2680 wxString filename = resolver.ResolvePath( BASE_SCREEN::m_DrawingSheetFileName,
2681 aBrd->GetProject()->GetProjectPath(),
2682 { aBrd->GetEmbeddedFiles() } );
2683 wxString msg;
2684
2685 if( !DS_DATA_MODEL::GetTheInstance().LoadDrawingSheet( filename, &msg ) )
2686 {
2687 m_reporter->Report( wxString::Format( _( "Error loading drawing sheet '%s'." ),
2688 path )
2689 + wxS( "\n" ) + msg + wxS( "\n" ),
2691 return false;
2692 }
2693
2694 return true;
2695 };
2696
2697 if( loadSheet( aSheetPath ) )
2698 return;
2699
2700 // failed loading custom path, revert back to default
2701 loadSheet( aBrd->GetProject()->GetProjectFile().m_BoardDrawingSheetFile );
2702}
@ VIEW3D_BOTTOM
Definition 3d_enums.h:81
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:112
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
#define RANGE_SCALE_3D
This defines the range that all coord will have to be rendered.
wxString FormatBoardStatisticsJson(const BOARD_STATISTICS_DATA &aData, BOARD *aBoard, const UNITS_PROVIDER &aUnitsProvider, const wxString &aProjectName, const wxString &aBoardName)
void ComputeBoardStatistics(BOARD *aBoard, const BOARD_STATISTICS_OPTIONS &aOptions, BOARD_STATISTICS_DATA &aData)
wxString FormatBoardStatisticsReport(const BOARD_STATISTICS_DATA &aData, BOARD *aBoard, const UNITS_PROVIDER &aUnitsProvider, const wxString &aProjectName, const wxString &aBoardName)
void InitializeBoardStatisticsData(BOARD_STATISTICS_DATA &aData)
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
PROJECTION_TYPE
Definition camera.h:40
static wxString m_DrawingSheetFileName
the name of the drawing sheet file, or empty to use the default drawing sheet
Definition base_screen.h:85
Helper class to handle information needed to display 3D board.
double BiuTo3dUnits() const noexcept
Board integer units To 3D units.
void SetBoard(BOARD *aBoard) noexcept
Set current board to be rendered.
EDA_3D_VIEWER_SETTINGS * m_Cfg
std::map< int, COLOR4D > m_ColorOverrides
allows to override color scheme colors
void Set3dCacheManager(S3D_CACHE *aCacheMgr) noexcept
Update the cache manager pointer.
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
std::shared_ptr< DRC_ENGINE > m_DRCEngine
const VECTOR2I & GetAuxOrigin() const
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:322
const PAGE_INFO & GetPageSettings() const
Definition board.h:758
void RecordDRCExclusions()
Scan existing markers and record data from any that are Excluded.
Definition board.cpp:332
TITLE_BLOCK & GetTitleBlock()
Definition board.h:764
BOX2I ComputeBoundingBox(bool aBoardEdgesOnly=false) const
Calculate the bounding box containing all board items (or board edge segments).
Definition board.cpp:2019
const std::map< wxString, wxString > & GetProperties() const
Definition board.h:400
const wxString & GetFileName() const
Definition board.h:359
std::vector< PCB_MARKER * > ResolveDRCExclusions(bool aCreateMarkers)
Rebuild DRC markers from the serialized data in BOARD_DESIGN_SETTINGS.
Definition board.cpp:389
int GetFileFormatVersionAtLoad() const
Definition board.h:431
const PCB_PLOT_PARAMS & GetPlotOptions() const
Definition board.h:761
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition board.cpp:692
PROJECT * GetProject() const
Definition board.h:554
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1041
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition board.cpp:924
void SynchronizeProperties()
Copy the current project's text variables into the boards property cache.
Definition board.cpp:2404
void DeleteMARKERs()
Delete all MARKERS from the board.
Definition board.cpp:1689
constexpr const Vec GetCenter() const
Definition box2.h:230
void SetProjection(PROJECTION_TYPE aProjection)
Definition camera.h:206
void RotateY_T1(float aAngleInRadians)
Definition camera.cpp:686
bool Zoom_T1(float aFactor)
Definition camera.cpp:629
bool SetCurWindowSize(const wxSize &aSize)
Update the windows size of the camera.
Definition camera.cpp:571
bool ViewCommand_T1(VIEW3D_TYPE aRequestedView)
Definition camera.cpp:110
void RotateX_T1(float aAngleInRadians)
Definition camera.cpp:680
void SetLookAtPos_T1(const SFVEC3F &aLookAtPos)
Definition camera.h:162
const SFVEC3F & GetLookAtPos_T1() const
Definition camera.h:167
void RotateZ_T1(float aAngleInRadians)
Definition camera.cpp:692
bool ParametersChanged()
Definition camera.cpp:730
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
Definition commit.h:78
static void GenerateODBPPFiles(const JOB_EXPORT_PCB_ODB &aJob, BOARD *aBoard, PCB_EDIT_FRAME *aParentFrame=nullptr, PROGRESS_REPORTER *aProgressReporter=nullptr, REPORTER *aErrorReporter=nullptr)
The dialog to create footprint position files and choose options (one or 2 files, units and force all...
A dialog to set the plot options and create plot files in various formats.
Definition dialog_plot.h:41
int ShowModal() override
bool WriteJsonReport(const wxString &aFullFileName)
bool WriteTextReport(const wxString &aFullFileName)
Helper to handle drill precision format in excellon files.
static DS_DATA_MODEL & GetTheInstance()
Return the instance of DS_DATA_MODEL used in the application.
void SetSheetPath(const std::string &aSheetPath)
Set the sheet path displayed in the title block.
void SetSheetName(const std::string &aSheetName)
Set the sheet name displayed in the title block.
void SetIsFirstPage(bool aIsFirstPage)
Change if this is first page.
void SetFileName(const std::string &aFileName)
Set the file name displayed in the title block.
std::vector< LAYER_PRESET_3D > m_LayerPresets
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:142
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.h:113
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)
wxString m_outputFile
Wrapper to expose an API for writing VRML files, without exposing all the many structures used in the...
Definition export_vrml.h:33
bool ExportVRML_File(PROJECT *aProject, wxString *aMessages, const wxString &aFullFileName, double aMMtoWRMLunit, bool aIncludeUnspecified, bool aIncludeDNP, bool aExport3DFiles, bool aUseRelativePaths, const wxString &a3D_Subdir, double aXRef, double aYRef)
Exports the board and its footprint shapes 3D (vrml files only) as a vrml file.
Provide an extensible class to resolve 3D model paths.
void SetPosition(const VECTOR2I &aPos) override
void SetLink(const KIID &aLink)
Definition footprint.h:887
void SetOrientation(const EDA_ANGLE &aNewAngle)
EDA_ITEM * Clone() const override
Invoke a function on all children.
std::deque< PAD * > & Pads()
Definition footprint.h:224
const LIB_ID & GetFPID() const
Definition footprint.h:269
void SetPath(const wxString &aPath)
void Save(FOOTPRINT *aFootprintFilter=nullptr)
Save the footprint cache or a single footprint from it to disk.
boost::ptr_map< wxString, FP_CACHE_ENTRY > & GetFootprints()
Export board to GenCAD file format.
void UseIndividualShapes(bool aUnique)
Make pad shapes unique.
void UsePinNamesUnique(bool aUnique)
Make pin names unique.
void StoreOriginCoordsInFile(bool aStore)
Store origin coordinate in GenCAD file.
void FlipBottomPads(bool aFlip)
Flip pad shapes on the bottom side.
void SetPlotOffet(VECTOR2I aOffset)
Set the coordinates offset when exporting items.
bool WriteFile(const wxString &aFullFileName)
Export a GenCAD file.
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, bool aGenTenting, 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.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
Wrapper to expose an API for writing IPC-D356 files.
Definition export_d356.h:54
bool Write(const wxString &aFilename)
Generates and writes the netlist to a given path.
void Register(const std::string &aJobTypeName, std::function< int(JOB *job)> aHandler, std::function< bool(JOB *job, wxWindow *aParent)> aConfigHandler)
JOB_DISPATCHER(KIWAY *aKiway)
PROGRESS_REPORTER * m_progressReporter
REPORTER * m_reporter
JOB_EXPORT_PCB_3D::FORMAT m_format
EXPORTER_STEP_PARAMS m_3dparams
Despite the name; also used for other formats.
wxString GetSettingsDialogTitle() const override
ODB_COMPRESSION m_compressionMode
@ ALL_LAYERS_ONE_FILE
DEPRECATED MODE.
GEN_MODE m_pdfGenMode
The background color specified in a hex string.
LSEQ m_plotOnAllLayersSequence
Used by SVG & PDF.
std::optional< wxString > m_argLayers
std::optional< wxString > m_argCommonLayers
LSEQ m_plotLayerSequence
Layers to include on all individual layer prints.
void SetDefaultOutputPath(const wxString &aReferenceName)
wxString m_libraryPath
wxString m_outputLibraryPath
bool m_saveBoard
Definition job_pcb_drc.h:36
bool m_reportAllTrackErrors
Definition job_pcb_drc.h:32
bool m_refillZones
Definition job_pcb_drc.h:35
VECTOR3D m_lightBottomIntensity
VECTOR3D m_lightTopIntensity
VECTOR3D m_lightCameraIntensity
VECTOR3D m_rotation
wxString m_filename
bool m_useBoardStackupColors
VECTOR3D m_lightSideIntensity
std::string m_appearancePreset
bool m_exitCodeViolations
Definition job_rc.h:52
int m_severity
Definition job_rc.h:49
UNITS m_units
Definition job_rc.h:48
OUTPUT_FORMAT m_format
Definition job_rc.h:50
wxString m_filename
Definition job_rc.h:47
An simple container class that lets us dispatch output jobs to kifaces.
Definition job.h:183
void AddOutput(wxString aOutputPath)
Definition job.h:215
wxString GetFullOutputPath(PROJECT *aProject) const
Returns the full output path for the job, taking into account the configured output path,...
Definition job.cpp:100
wxString GetWorkingOutputPath() const
Returns the working output path for the job, if one has been set.
Definition job.h:243
wxString GetConfiguredOutputPath() const
Returns the configured output path for the job.
Definition job.h:232
void SetTitleBlock(const TITLE_BLOCK &aTitleBlock)
Definition job.h:203
void SetWorkingOutputPath(const wxString &aPath)
Sets a transient output path for the job, it takes priority over the configured output path when GetF...
Definition job.h:238
const std::map< wxString, wxString > & GetVarOverrides() const
Definition job.h:196
Read the new s-expression based KiCad netlist format.
virtual void LoadNetlist() override
Load the contents of the netlist file into aNetlist.
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:104
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition kiway.h:291
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition kiway.cpp:395
@ FACE_SCH
eeschema DSO
Definition kiway.h:298
const UTF8 & GetLibItemName() const
Definition lib_id.h:102
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition lseq.h:47
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
LSEQ UIOrder() const
Return the copper, technical and user layers in the order shown in layer widget.
Definition lset.cpp:726
LSEQ SeqStackupForPlotting() const
Return the sequence that is typical for a bottom-to-top stack-up.
Definition lset.cpp:387
static LSET AllNonCuMask()
Return a mask holding all layer minus CU layers.
Definition lset.cpp:610
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:582
static const LSET & AllLayersMask()
Definition lset.cpp:624
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:591
static const LSET & InternalCuMask()
Return a complete set of internal copper layers which is all Cu layers except F_Cu and B_Cu.
Definition lset.cpp:560
static wxString Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition lset.cpp:188
@ MARKER_DRAWING_SHEET
Definition marker_base.h:56
Definition pad.h:54
static bool EnsurePathExists(const wxString &aPath, bool aPathToFile=false)
Attempts to create a given path if it does not exist.
Definition paths.cpp:477
DS_PROXY_VIEW_ITEM * getDrawingSheetProxyView(BOARD *aBrd)
wxString resolveJobOutputPath(JOB *aJob, BOARD *aBoard, const wxString *aDrawingSheet=nullptr)
void loadOverrideDrawingSheet(BOARD *brd, const wxString &aSheetPath)
PCBNEW_JOBS_HANDLER(KIWAY *aKiway)
TOOL_MANAGER * getToolManager(BOARD *aBrd)
BOARD * getBoard(const wxString &aPath=wxEmptyString)
std::unique_ptr< TOOL_MANAGER > m_toolManager
LSEQ convertLayerArg(wxString &aLayerString, BOARD *aBoard) const
int doFpExportSvg(JOB_FP_EXPORT_SVG *aSvgJob, const FOOTPRINT *aFootprint)
BOARD * GetBoard() const
The main frame for Pcbnew.
A #PLUGIN derivation for saving and loading Pcbnew s-expression formatted files.
static PCB_IO * PluginFind(PCB_FILE_T aFileType)
Return a #PLUGIN which the caller can use to import, export, save, or load design documents.
static bool ConvertLibrary(const std::map< std::string, UTF8 > &aOldFileProps, const wxString &aOldFilePath, const wxString &aNewFilePath, REPORTER *aReporter)
Convert a schematic symbol library to the latest KiCad format.
PCB_FILE_T
The set of file types that the PCB_IO_MGR knows about, and for which there has been a plugin written,...
Definition pcb_io_mgr.h:56
@ KICAD_SEXP
S-expression Pcbnew file format.
Definition pcb_io_mgr.h:58
static PCB_FILE_T GuessPluginTypeFromLibPath(const wxString &aLibPath, int aCtl=0)
Return a plugin type given a footprint library's libPath.
bool Plot(const wxString &aOutputPath, const LSEQ &aLayersToPlot, const LSEQ &aCommonLayers, bool aUseGerberFileExtensions, bool aOutputPathIsSingle=false, std::optional< wxString > aLayerName=std::nullopt, std::optional< wxString > aSheetName=std::nullopt, std::optional< wxString > aSheetPath=std::nullopt)
static void PlotJobToPlotOpts(PCB_PLOT_PARAMS &aOpts, JOB_EXPORT_PCB_PLOT *aJob, REPORTER &aReporter)
Translate a JOB to PCB_PLOT_PARAMS.
Parameters and options when plotting/printing a board.
LSEQ GetPlotOnAllLayersSequence() const
void SetSkipPlotNPTH_Pads(bool aSkip)
void SetLayerSelection(const LSET &aSelection)
void SetPlotOnAllLayersSequence(LSEQ aSeq)
void SetPlotFrameRef(bool aFlag)
void SetPlotPadNumbers(bool aFlag)
LSET GetLayerSelection() const
void SetMirror(bool aFlag)
bool GetSketchPadsOnFabLayers() const
bool m_PDFSingle
Generate a single PDF file for all layers.
void SetSvgFitPageToBoard(int aSvgFitPageToBoard)
bool GetUseGerberProtelExtensions() const
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:128
Used to create Gerber drill files.
const wxString GetPlaceFileName(const wxString &aFullBaseFilename, PCB_LAYER_ID aLayer) const
int CreatePlaceFile(const wxString &aFullFilename, PCB_LAYER_ID aLayer, bool aIncludeBrdEdges, bool aExcludeDNP, bool aExcludeBOM)
Create an pnp gerber file.
The ASCII format of the kicad place file is:
static wxString DecorateFilename(const wxString &aBaseName, bool aFront, bool aBack)
std::string GenPositionData()
build a string filled with the position data
Base plotter engine class.
Definition plotter.h:121
virtual bool EndPlot()=0
wxString m_BoardDrawingSheetFile
PcbNew params.
static S3D_CACHE * Get3DCacheManager(PROJECT *aProject, bool updateProjDir=false)
Return a pointer to an instance of the 3D cache manager.
Container for project specific data.
Definition project.h:65
virtual const wxString GetProjectFullName() const
Return the full path and name of the project.
Definition project.cpp:158
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition project.cpp:164
virtual const wxString GetProjectName() const
Return the short name of the project.
Definition project.cpp:176
virtual PROJECT_FILE & GetProjectFile() const
Definition project.h:204
bool Redraw(bool aIsMoving, REPORTER *aStatusReporter, REPORTER *aWarningReporter) override
Redraw the view.
void SetCurWindowSize(const wxSize &aSize) override
Before each render, the canvas will tell the render what is the size of its windows,...
PROJECT & Prj() const
A helper while we are not MDI-capable – return the one and only project.
Is a LINE_READER that reads from a multiline 8 bit wide std::string.
Definition richio.h:254
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Master controller class:
TOOL_BASE * FindTool(int aId) const
Search for a tool with given ID.
void RegisterTool(TOOL_BASE *aTool)
Add a tool to the manager set and sets it up.
void SetEnvironment(EDA_ITEM *aModel, KIGFX::VIEW *aView, KIGFX::VIEW_CONTROLS *aViewControls, APP_SETTINGS_BASE *aSettings, TOOLS_HOLDER *aFrame)
Set the work environment (model, view, view controls and the parent window).
void Pan_T1(const SFVEC3F &aDeltaOffsetInc) override
void SetT0_and_T1_current_T() override
This will set T0 and T1 with the current values.
void Interpolate(float t) override
It will update the matrix to interpolate between T0 and T1 values.
wxString wx_str() const
Definition utf8.cpp:45
Handle actions specific to filling copper zones.
wxString GetDefaultPlotExtension(PLOT_FORMAT aFormat)
Return the default plot extension for a format.
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:194
This file is part of the common library.
static DRILL_PRECISION precisionListForInches(2, 4)
static DRILL_PRECISION precisionListForMetric(3, 3)
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:411
#define IS_NEW
New item, just created.
EDA_UNITS
Definition eda_units.h:48
static FILENAME_RESOLVER * resolver
@ FRAME_PCB_EDITOR
Definition frame_type.h:42
@ FRAME_SCH
Definition frame_type.h:34
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.
static const std::string LegacySchematicFileExtension
static const std::string BrepFileExtension
static const std::string JpegFileExtension
static const std::string GerberJobFileExtension
static const std::string GerberFileExtension
static const std::string XaoFileExtension
static const std::string ReportFileExtension
static const std::string GltfBinaryFileExtension
static const std::string PngFileExtension
static const std::string FootprintPlaceFileExtension
static const std::string JsonFileExtension
static const std::string KiCadSchematicFileExtension
static const std::string CsvFileExtension
static const std::string U3DFileExtension
static const std::string PdfFileExtension
static const std::string Ipc2581FileExtension
static const std::string GencadFileExtension
static const std::string StlFileExtension
static const std::string IpcD356FileExtension
static const std::string PlyFileExtension
static const std::string StepFileExtension
static const std::string SVGFileExtension
static const std::string VrmlFileExtension
static const std::string ArchiveFileExtension
static const std::string KiCadPcbFileExtension
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition io_mgr.h:33
@ KIFACE_NETLIST_SCHEMATIC
Definition kiface_ids.h:56
KIID niluuid(0)
wxString LayerName(int aLayer)
Returns the default display name for a given layer.
Definition layer_id.cpp:31
@ LAYER_3D_BACKGROUND_TOP
Definition layer_ids.h:552
@ LAYER_3D_BACKGROUND_BOTTOM
Definition layer_ids.h:551
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ F_CrtYd
Definition layer_ids.h:116
@ B_Adhes
Definition layer_ids.h:103
@ F_Paste
Definition layer_ids.h:104
@ F_Adhes
Definition layer_ids.h:102
@ B_Mask
Definition layer_ids.h:98
@ B_Cu
Definition layer_ids.h:65
@ F_Mask
Definition layer_ids.h:97
@ B_Paste
Definition layer_ids.h:105
@ F_Fab
Definition layer_ids.h:119
@ F_SilkS
Definition layer_ids.h:100
@ B_CrtYd
Definition layer_ids.h:115
@ UNDEFINED_LAYER
Definition layer_ids.h:61
@ B_SilkS
Definition layer_ids.h:101
@ F_Cu
Definition layer_ids.h:64
@ B_Fab
Definition layer_ids.h:118
This file contains miscellaneous commonly used macros and functions.
@ MAIL_SCH_GET_NETLIST
Definition mail_type.h:49
static const int ERR_ARGS
Definition exit_codes.h:31
static const int OK
Definition exit_codes.h:30
static const int ERR_RC_VIOLATIONS
Rules check violation count was greater than 0.
Definition exit_codes.h:37
static const int ERR_INVALID_INPUT_FILE
Definition exit_codes.h:33
static const int SUCCESS
Definition exit_codes.h:29
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.
#define CTL_FOR_LIBRARY
Format output for a footprint library instead of clipboard or BOARD.
static DRILL_PRECISION precisionListForInches(2, 4)
static DRILL_PRECISION precisionListForMetric(3, 3)
SETTINGS_MANAGER * GetSettingsManager()
BOARD * CreateEmptyBoard()
Construct a default BOARD with a temporary (no filename) project.
bool SaveBoard(wxString &aFileName, BOARD *aBoard, PCB_IO_MGR::PCB_FILE_T aFormat, bool aSkipSettings)
BOARD * LoadBoard(const wxString &aFileName, bool aSetActive)
Loads a board from file This function identifies the file type by extension and determines the correc...
const wxString GetGerberProtelExtension(int aLayer)
Definition pcbplot.cpp:43
void BuildPlotFileName(wxFileName *aFilename, const wxString &aOutputDir, const wxString &aSuffix, const wxString &aExtension)
Complete a plot filename.
Definition pcbplot.cpp:379
PLOTTER * StartPlotBoard(BOARD *aBoard, const PCB_PLOT_PARAMS *aPlotOpts, int aLayer, const wxString &aLayerName, const wxString &aFullFileName, const wxString &aSheetName, const wxString &aSheetPath, const wxString &aPageName=wxT("1"), const wxString &aPageNumber=wxEmptyString, const int aPageCount=1)
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.
PGM_BASE & Pgm()
The global program "get" accessor.
Definition pgm_base.cpp:946
see class PGM_BASE
PLOT_FORMAT
The set of supported output plot formats.
Definition plotter.h:64
Plotting engines similar to ps (PostScript, Gerber, svg)
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_INFO
@ RPT_SEVERITY_ACTION
#define SKIP_SET_DIRTY
Definition sch_commit.h:42
#define SKIP_UNDO
Definition sch_commit.h:40
T * GetAppSettings(const char *aFilename)
const int scale
MODEL3D_FORMAT_TYPE fileType(const char *aFileName)
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
std::vector< KIGFX::COLOR4D > raytrace_lightColor
Implement a participant in the KIWAY alchemy.
Definition kiway.h:154
Declaration for a track ball camera.
double DEG2RAD(double deg)
Definition trigo.h:166
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
Definition of file extensions used in Kicad.
glm::vec3 SFVEC3F
Definition xv3d_types.h:44
#define ZONE_FILLER_TOOL_NAME