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>
92#include <kiplatform/io.h>
99#include <dialogs/dialog_plot.h>
104#include <paths.h>
106
108#include <locale_io.h>
109#include <confirm.h>
110
111
112#ifdef _WIN32
113#ifdef TRANSPARENT
114#undef TRANSPARENT
115#endif
116#endif
117
118
120 JOB_DISPATCHER( aKiway ),
121 m_cliBoard( nullptr ),
122 m_toolManager( nullptr )
123{
124 Register( "3d", std::bind( &PCBNEW_JOBS_HANDLER::JobExportStep, this, std::placeholders::_1 ),
125 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
126 {
127 JOB_EXPORT_PCB_3D* svgJob = dynamic_cast<JOB_EXPORT_PCB_3D*>( job );
128
129 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
130 false ) );
131
132 wxCHECK( svgJob && editFrame, false );
133
134 DIALOG_EXPORT_STEP dlg( editFrame, aParent, "", svgJob );
135 return dlg.ShowModal() == wxID_OK;
136 } );
137 Register( "render",
138 std::bind( &PCBNEW_JOBS_HANDLER::JobExportRender, this, std::placeholders::_1 ),
139 []( JOB* job, wxWindow* aParent ) -> bool
140 {
141 JOB_PCB_RENDER* renderJob = dynamic_cast<JOB_PCB_RENDER*>( job );
142
143 wxCHECK( renderJob, false );
144
145 DIALOG_RENDER_JOB dlg( aParent, renderJob );
146 return dlg.ShowModal() == wxID_OK;
147 } );
148 Register( "upgrade", std::bind( &PCBNEW_JOBS_HANDLER::JobUpgrade, this, std::placeholders::_1 ),
149 []( JOB* job, wxWindow* aParent ) -> bool
150 {
151 return true;
152 } );
153 Register( "svg", std::bind( &PCBNEW_JOBS_HANDLER::JobExportSvg, this, std::placeholders::_1 ),
154 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
155 {
156 JOB_EXPORT_PCB_SVG* svgJob = dynamic_cast<JOB_EXPORT_PCB_SVG*>( job );
157
158 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
159 false ) );
160
161 wxCHECK( svgJob && editFrame, false );
162
163 DIALOG_PLOT dlg( editFrame, aParent, svgJob );
164 return dlg.ShowModal() == wxID_OK;
165 } );
166 Register( "gencad",
167 std::bind( &PCBNEW_JOBS_HANDLER::JobExportGencad, this, std::placeholders::_1 ),
168 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
169 {
170 JOB_EXPORT_PCB_GENCAD* gencadJob = dynamic_cast<JOB_EXPORT_PCB_GENCAD*>( job );
171
172 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
173 false ) );
174
175 wxCHECK( gencadJob && editFrame, false );
176
177 DIALOG_GENCAD_EXPORT_OPTIONS dlg( editFrame, gencadJob->GetSettingsDialogTitle(), gencadJob );
178 return dlg.ShowModal() == wxID_OK;
179 } );
180 Register( "dxf", std::bind( &PCBNEW_JOBS_HANDLER::JobExportDxf, this, std::placeholders::_1 ),
181 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
182 {
183 JOB_EXPORT_PCB_DXF* dxfJob = dynamic_cast<JOB_EXPORT_PCB_DXF*>( job );
184
185 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
186 false ) );
187
188 wxCHECK( dxfJob && editFrame, false );
189
190 DIALOG_PLOT dlg( editFrame, aParent, dxfJob );
191 return dlg.ShowModal() == wxID_OK;
192 } );
193 Register( "pdf", std::bind( &PCBNEW_JOBS_HANDLER::JobExportPdf, this, std::placeholders::_1 ),
194 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
195 {
196 JOB_EXPORT_PCB_PDF* pdfJob = dynamic_cast<JOB_EXPORT_PCB_PDF*>( job );
197
198 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
199 false ) );
200
201 wxCHECK( pdfJob && editFrame, false );
202
203 DIALOG_PLOT dlg( editFrame, aParent, pdfJob );
204 return dlg.ShowModal() == wxID_OK;
205 } );
206 Register( "ps", std::bind( &PCBNEW_JOBS_HANDLER::JobExportPs, this, std::placeholders::_1 ),
207 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
208 {
209 JOB_EXPORT_PCB_PS* psJob = dynamic_cast<JOB_EXPORT_PCB_PS*>( job );
210
211 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
212 false ) );
213
214 wxCHECK( psJob && editFrame, false );
215
216 DIALOG_PLOT dlg( editFrame, aParent, psJob );
217 return dlg.ShowModal() == wxID_OK;
218 } );
219 Register( "stats",
220 std::bind( &PCBNEW_JOBS_HANDLER::JobExportStats, this, std::placeholders::_1 ),
221 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
222 {
223 JOB_EXPORT_PCB_STATS* statsJob = dynamic_cast<JOB_EXPORT_PCB_STATS*>( job );
224
225 PCB_EDIT_FRAME* editFrame =
226 dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR, false ) );
227
228 wxCHECK( statsJob && editFrame, false );
229
230 if( statsJob->m_filename.IsEmpty() && editFrame->GetBoard() )
231 {
232 wxFileName boardName = editFrame->GetBoard()->GetFileName();
233 statsJob->m_filename = boardName.GetFullPath();
234 }
235
236 wxWindow* parent = aParent ? aParent : static_cast<wxWindow*>( editFrame );
237
238 DIALOG_BOARD_STATS_JOB dlg( parent, statsJob );
239
240 return dlg.ShowModal() == wxID_OK;
241 } );
242 Register( "gerber",
243 std::bind( &PCBNEW_JOBS_HANDLER::JobExportGerber, this, std::placeholders::_1 ),
244 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
245 {
246 JOB_EXPORT_PCB_GERBER* gJob = dynamic_cast<JOB_EXPORT_PCB_GERBER*>( job );
247
248 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
249 false ) );
250
251 wxCHECK( gJob && editFrame, false );
252
253 DIALOG_PLOT dlg( editFrame, aParent, gJob );
254 return dlg.ShowModal() == wxID_OK;
255 } );
256 Register( "gerbers",
257 std::bind( &PCBNEW_JOBS_HANDLER::JobExportGerbers, this, std::placeholders::_1 ),
258 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
259 {
260 JOB_EXPORT_PCB_GERBERS* gJob = dynamic_cast<JOB_EXPORT_PCB_GERBERS*>( job );
261
262 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
263 false ) );
264
265 wxCHECK( gJob && editFrame, false );
266
267 DIALOG_PLOT dlg( editFrame, aParent, gJob );
268 return dlg.ShowModal() == wxID_OK;
269 } );
270 Register( "hpgl",
271 [&]( JOB* aJob )
272 {
273 m_reporter->Report( _( "Plotting to HPGL is no longer supported as of KiCad 10.0.\n" ),
276 },
277 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
278 {
279 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
280 false ) );
281
282 wxCHECK( editFrame, false );
283
284 DisplayErrorMessage( editFrame,
285 _( "Plotting to HPGL is no longer supported as of KiCad 10.0." ) );
286 return false;
287 } );
288 Register( "drill",
289 std::bind( &PCBNEW_JOBS_HANDLER::JobExportDrill, this, std::placeholders::_1 ),
290 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
291 {
292 JOB_EXPORT_PCB_DRILL* drillJob = dynamic_cast<JOB_EXPORT_PCB_DRILL*>( job );
293
294 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
295 false ) );
296
297 wxCHECK( drillJob && editFrame, false );
298
299 DIALOG_GENDRILL dlg( editFrame, drillJob, aParent );
300 return dlg.ShowModal() == wxID_OK;
301 } );
302 Register( "pos", std::bind( &PCBNEW_JOBS_HANDLER::JobExportPos, this, std::placeholders::_1 ),
303 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
304 {
305 JOB_EXPORT_PCB_POS* posJob = dynamic_cast<JOB_EXPORT_PCB_POS*>( job );
306
307 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
308 false ) );
309
310 wxCHECK( posJob && editFrame, false );
311
312 DIALOG_GEN_FOOTPRINT_POSITION dlg( posJob, editFrame, aParent );
313 return dlg.ShowModal() == wxID_OK;
314 } );
315 Register( "fpupgrade",
316 std::bind( &PCBNEW_JOBS_HANDLER::JobExportFpUpgrade, this, std::placeholders::_1 ),
317 []( JOB* job, wxWindow* aParent ) -> bool
318 {
319 return true;
320 } );
321 Register( "fpsvg",
322 std::bind( &PCBNEW_JOBS_HANDLER::JobExportFpSvg, this, std::placeholders::_1 ),
323 []( JOB* job, wxWindow* aParent ) -> bool
324 {
325 return true;
326 } );
327 Register( "drc", std::bind( &PCBNEW_JOBS_HANDLER::JobExportDrc, this, std::placeholders::_1 ),
328 []( JOB* job, wxWindow* aParent ) -> bool
329 {
330 JOB_PCB_DRC* drcJob = dynamic_cast<JOB_PCB_DRC*>( job );
331
332 wxCHECK( drcJob, false );
333
334 DIALOG_DRC_JOB_CONFIG dlg( aParent, drcJob );
335 return dlg.ShowModal() == wxID_OK;
336 } );
337 Register( "ipc2581",
338 std::bind( &PCBNEW_JOBS_HANDLER::JobExportIpc2581, this, std::placeholders::_1 ),
339 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
340 {
341 JOB_EXPORT_PCB_IPC2581* ipcJob = dynamic_cast<JOB_EXPORT_PCB_IPC2581*>( job );
342
343 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
344 false ) );
345
346 wxCHECK( ipcJob && editFrame, false );
347
348 DIALOG_EXPORT_2581 dlg( ipcJob, editFrame, aParent );
349 return dlg.ShowModal() == wxID_OK;
350 } );
351 Register( "ipcd356",
352 std::bind( &PCBNEW_JOBS_HANDLER::JobExportIpcD356, this, std::placeholders::_1 ),
353 []( JOB* job, wxWindow* aParent ) -> bool
354 {
355 return true;
356 } );
357 Register( "odb",
358 std::bind( &PCBNEW_JOBS_HANDLER::JobExportOdb, this, std::placeholders::_1 ),
359 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
360 {
361 JOB_EXPORT_PCB_ODB* odbJob = dynamic_cast<JOB_EXPORT_PCB_ODB*>( job );
362
363 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
364 false ) );
365
366 wxCHECK( odbJob && editFrame, false );
367
368 DIALOG_EXPORT_ODBPP dlg( odbJob, editFrame, aParent );
369 return dlg.ShowModal() == wxID_OK;
370 } );
371}
372
373
377
378
380{
381 TOOL_MANAGER* toolManager = nullptr;
382 if( Pgm().IsGUI() )
383 {
384 // we assume the PCB we are working on here is the one in the frame
385 // so use the frame's tool manager
386 PCB_EDIT_FRAME* editFrame = (PCB_EDIT_FRAME*) m_kiway->Player( FRAME_PCB_EDITOR, false );
387 if( editFrame )
388 toolManager = editFrame->GetToolManager();
389 }
390 else
391 {
392 if( m_toolManager == nullptr )
393 {
394 m_toolManager = std::make_unique<TOOL_MANAGER>();
395 }
396
397 toolManager = m_toolManager.get();
398
399 toolManager->SetEnvironment( aBrd, nullptr, nullptr, Kiface().KifaceSettings(), nullptr );
400 }
401 return toolManager;
402}
403
404
405BOARD* PCBNEW_JOBS_HANDLER::getBoard( const wxString& aPath )
406{
407 BOARD* brd = nullptr;
408
409 if( !Pgm().IsGUI() && Pgm().GetSettingsManager().IsProjectOpen() )
410 {
411 wxString pcbPath = aPath;
412
413 if( pcbPath.IsEmpty() )
414 {
415 wxFileName path = Pgm().GetSettingsManager().Prj().GetProjectFullName();
417 path.MakeAbsolute();
418 pcbPath = path.GetFullPath();
419 }
420
421 if( !m_cliBoard )
422 m_cliBoard = LoadBoard( pcbPath, true );
423
424 brd = m_cliBoard;
425 }
426 else if( Pgm().IsGUI() && Pgm().GetSettingsManager().IsProjectOpen() )
427 {
428 PCB_EDIT_FRAME* editFrame = (PCB_EDIT_FRAME*) m_kiway->Player( FRAME_PCB_EDITOR, false );
429
430 if( editFrame )
431 brd = editFrame->GetBoard();
432 }
433 else
434 {
435 brd = LoadBoard( aPath, true );
436 }
437
438 if( !brd )
439 m_reporter->Report( _( "Failed to load board\n" ), RPT_SEVERITY_ERROR );
440
441 return brd;
442}
443
444
445LSEQ PCBNEW_JOBS_HANDLER::convertLayerArg( wxString& aLayerString, BOARD* aBoard ) const
446{
447 std::map<wxString, LSET> layerUserMasks;
448 std::map<wxString, LSET> layerMasks;
449 std::map<wxString, LSET> layerGuiMasks;
450
451 // Build list of layer names and their layer mask:
452 for( PCB_LAYER_ID layer : LSET::AllLayersMask() )
453 {
454 // Add user layer name
455 if( aBoard )
456 layerUserMasks[ aBoard->GetLayerName( layer ) ] = LSET( { layer } );
457
458 // Add layer name used in pcb files
459 layerMasks[ LSET::Name( layer ) ] = LSET( { layer } );
460 // Add layer name using GUI canonical layer name
461 layerGuiMasks[ LayerName( layer ) ] = LSET( { layer } );
462 }
463
464 // Add list of grouped layer names used in pcb files
465 layerMasks[ wxT( "*" ) ] = LSET::AllLayersMask();
466 layerMasks[ wxT( "*.Cu" ) ] = LSET::AllCuMask();
467 layerMasks[ wxT( "*In.Cu" ) ] = LSET::InternalCuMask();
468 layerMasks[ wxT( "F&B.Cu" ) ] = LSET( { F_Cu, B_Cu } );
469 layerMasks[ wxT( "*.Adhes" ) ] = LSET( { B_Adhes, F_Adhes } );
470 layerMasks[ wxT( "*.Paste" ) ] = LSET( { B_Paste, F_Paste } );
471 layerMasks[ wxT( "*.Mask" ) ] = LSET( { B_Mask, F_Mask } );
472 layerMasks[ wxT( "*.SilkS" ) ] = LSET( { B_SilkS, F_SilkS } );
473 layerMasks[ wxT( "*.Fab" ) ] = LSET( { B_Fab, F_Fab } );
474 layerMasks[ wxT( "*.CrtYd" ) ] = LSET( { B_CrtYd, F_CrtYd } );
475
476 // Add list of grouped layer names using GUI canonical layer names
477 layerGuiMasks[ wxT( "*.Adhesive" ) ] = LSET( { B_Adhes, F_Adhes } );
478 layerGuiMasks[ wxT( "*.Silkscreen" ) ] = LSET( { B_SilkS, F_SilkS } );
479 layerGuiMasks[ wxT( "*.Courtyard" ) ] = LSET( { B_CrtYd, F_CrtYd } );
480
481 LSEQ layerMask;
482
483 auto pushLayers =
484 [&]( const LSET& layerSet )
485 {
486 for( PCB_LAYER_ID layer : layerSet.Seq() )
487 layerMask.push_back( layer );
488 };
489
490 if( !aLayerString.IsEmpty() )
491 {
492 wxStringTokenizer layerTokens( aLayerString, "," );
493
494 while( layerTokens.HasMoreTokens() )
495 {
496 std::string token = TO_UTF8( layerTokens.GetNextToken().Trim( true ).Trim( false ) );
497
498 if( layerUserMasks.contains( token ) )
499 pushLayers( layerUserMasks.at( token ) );
500 else if( layerMasks.count( token ) )
501 pushLayers( layerMasks.at( token ) );
502 else if( layerGuiMasks.count( token ) )
503 pushLayers( layerGuiMasks.at( token ) );
504 else
505 m_reporter->Report( wxString::Format( _( "Invalid layer name '%s'\n" ), token ) );
506 }
507 }
508
509 return layerMask;
510}
511
512
514{
515 JOB_EXPORT_PCB_3D* aStepJob = dynamic_cast<JOB_EXPORT_PCB_3D*>( aJob );
516
517 if( aStepJob == nullptr )
519
520 BOARD* brd = getBoard( aStepJob->m_filename );
521
522 if( !brd )
524
525 if( aStepJob->GetConfiguredOutputPath().IsEmpty() )
526 {
527 wxFileName fn = brd->GetFileName();
528 fn.SetName( fn.GetName() );
529
530 switch( aStepJob->m_format )
531 {
541 default:
542 m_reporter->Report( _( "Unknown export format" ), RPT_SEVERITY_ERROR );
543 return CLI::EXIT_CODES::ERR_UNKNOWN; // shouldnt have gotten here
544 }
545
546 aStepJob->SetWorkingOutputPath( fn.GetFullName() );
547 }
548
549 wxString outPath = resolveJobOutputPath( aJob, brd );
550
551 if( !PATHS::EnsurePathExists( outPath, true ) )
552 {
553 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
555 }
556
558 {
559
560 double scale = 0.0;
561 switch ( aStepJob->m_vrmlUnits )
562 {
563 case JOB_EXPORT_PCB_3D::VRML_UNITS::MM: scale = 1.0; break;
564 case JOB_EXPORT_PCB_3D::VRML_UNITS::METERS: scale = 0.001; break;
565 case JOB_EXPORT_PCB_3D::VRML_UNITS::TENTHS: scale = 10.0 / 25.4; break;
566 case JOB_EXPORT_PCB_3D::VRML_UNITS::INCH: scale = 1.0 / 25.4; break;
567 }
568
569 EXPORTER_VRML vrmlExporter( brd );
570 wxString messages;
571
572 double originX = pcbIUScale.IUTomm( aStepJob->m_3dparams.m_Origin.x );
573 double originY = pcbIUScale.IUTomm( aStepJob->m_3dparams.m_Origin.y );
574
575 if( !aStepJob->m_hasUserOrigin )
576 {
577 BOX2I bbox = brd->ComputeBoundingBox( true );
578 originX = pcbIUScale.IUTomm( bbox.GetCenter().x );
579 originY = pcbIUScale.IUTomm( bbox.GetCenter().y );
580 }
581
582 bool success = vrmlExporter.ExportVRML_File( brd->GetProject(),
583 &messages,
584 outPath,
585 scale,
587 aStepJob->m_3dparams.m_IncludeDNP,
588 !aStepJob->m_vrmlModelDir.IsEmpty(),
589 aStepJob->m_vrmlRelativePaths,
590 aStepJob->m_vrmlModelDir,
591 originX,
592 originY );
593
594 if ( success )
595 {
596 m_reporter->Report( wxString::Format( _( "Successfully exported VRML to %s" ),
597 outPath ),
599 }
600 else
601 {
602 m_reporter->Report( _( "Error exporting VRML" ), RPT_SEVERITY_ERROR );
604 }
605 }
606 else
607 {
608 EXPORTER_STEP_PARAMS params = aStepJob->m_3dparams;
609
610 switch( aStepJob->m_format )
611 {
621 default:
622 m_reporter->Report( _( "Unknown export format" ), RPT_SEVERITY_ERROR );
623 return CLI::EXIT_CODES::ERR_UNKNOWN; // shouldnt have gotten here
624 }
625
626 EXPORTER_STEP stepExporter( brd, params, m_reporter );
627 stepExporter.m_outputFile = aStepJob->GetFullOutputPath( brd->GetProject() );
628
629 if( !stepExporter.Export() )
631 }
632
633 return CLI::EXIT_CODES::OK;
634}
635
636
638{
639 JOB_PCB_RENDER* aRenderJob = dynamic_cast<JOB_PCB_RENDER*>( aJob );
640
641 if( aRenderJob == nullptr )
643
644 // Reject width and height being invalid
645 // Final bit of sanity because this can blow things up
646 if( aRenderJob->m_width <= 0 || aRenderJob->m_height <= 0 )
647 {
648 m_reporter->Report( _( "Invalid image dimensions" ), RPT_SEVERITY_ERROR );
650 }
651
652 BOARD* brd = getBoard( aRenderJob->m_filename );
653
654 if( !brd )
656
657 if( aRenderJob->GetConfiguredOutputPath().IsEmpty() )
658 {
659 wxFileName fn = brd->GetFileName();
660
661 switch( aRenderJob->m_format )
662 {
665 default:
666 m_reporter->Report( _( "Unknown export format" ), RPT_SEVERITY_ERROR );
667 return CLI::EXIT_CODES::ERR_UNKNOWN; // shouldnt have gotten here
668 }
669
670 // set the name to board name + "side", its lazy but its hard to generate anything truely unique
671 // incase someone is doing this in a jobset with multiple jobs, they should be setting the output themselves
672 // or we do a hash based on all the options
673 fn.SetName( wxString::Format( "%s-%d", fn.GetName(), static_cast<int>( aRenderJob->m_side ) ) );
674
675 aRenderJob->SetWorkingOutputPath( fn.GetFullName() );
676 }
677
678 wxString outPath = resolveJobOutputPath( aJob, brd );
679
680 if( !PATHS::EnsurePathExists( outPath, true ) )
681 {
682 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
684 }
685
686 BOARD_ADAPTER boardAdapter;
687
688 boardAdapter.SetBoard( brd );
689 boardAdapter.m_IsBoardView = false;
690
692
694 {
695 cfg.m_Render = userCfg->m_Render;
696 cfg.m_Camera = userCfg->m_Camera;
697 cfg.m_LayerPresets = userCfg->m_LayerPresets;
698 }
699
700 if( aRenderJob->m_appearancePreset.empty() )
701 {
702 // Force display 3D models
704 cfg.m_Render.show_footprints_dnp = true;
708 }
709
710 if( aRenderJob->m_quality == JOB_PCB_RENDER::QUALITY::BASIC )
711 {
712 // Silkscreen is pixelated without antialiasing
714
715 cfg.m_Render.raytrace_backfloor = aRenderJob->m_floor;
716 cfg.m_Render.raytrace_post_processing = aRenderJob->m_floor;
717
719 cfg.m_Render.raytrace_reflections = false;
720 cfg.m_Render.raytrace_shadows = aRenderJob->m_floor;
721
722 // Better colors
724
725 // Tracks below soldermask are not visible without refractions
728 }
729 else if( aRenderJob->m_quality == JOB_PCB_RENDER::QUALITY::HIGH )
730 {
732 cfg.m_Render.raytrace_backfloor = true;
736 cfg.m_Render.raytrace_shadows = true;
739 }
740 else if( aRenderJob->m_quality == JOB_PCB_RENDER::QUALITY::JOB_SETTINGS )
741 {
743 cfg.m_Render.raytrace_backfloor = aRenderJob->m_floor;
746 }
747
749 aRenderJob->m_lightTopIntensity.y,
750 aRenderJob->m_lightTopIntensity.z, 1.0 );
751
753 aRenderJob->m_lightBottomIntensity.y,
754 aRenderJob->m_lightBottomIntensity.z, 1.0 );
755
757 aRenderJob->m_lightCameraIntensity.y,
758 aRenderJob->m_lightCameraIntensity.z, 1.0 );
759
760 COLOR4D lightColor( aRenderJob->m_lightSideIntensity.x,
761 aRenderJob->m_lightSideIntensity.y,
762 aRenderJob->m_lightSideIntensity.z, 1.0 );
763
765 lightColor, lightColor, lightColor, lightColor,
766 lightColor, lightColor, lightColor, lightColor,
767 };
768
769 int sideElevation = aRenderJob->m_lightSideElevation;
770
772 sideElevation, sideElevation, sideElevation, sideElevation,
773 -sideElevation, -sideElevation, -sideElevation, -sideElevation,
774 };
775
777 45, 135, 225, 315, 45, 135, 225, 315,
778 };
779
780 cfg.m_CurrentPreset = aRenderJob->m_appearancePreset;
782 boardAdapter.m_Cfg = &cfg;
783
784 // Apply the preset's layer visibility and colors to the render settings
785 if( !aRenderJob->m_appearancePreset.empty() )
786 {
787 wxString presetName = wxString::FromUTF8( aRenderJob->m_appearancePreset );
788
789 if( presetName == FOLLOW_PCB || presetName == FOLLOW_PLOT_SETTINGS )
790 {
791 boardAdapter.SetVisibleLayers( boardAdapter.GetVisibleLayers() );
792 }
793 else if( LAYER_PRESET_3D* preset = cfg.FindPreset( presetName ) )
794 {
795 boardAdapter.SetVisibleLayers( preset->layers );
796 boardAdapter.SetLayerColors( preset->colors );
797
798 if( preset->name.Lower() == _( "legacy colors" ) )
799 cfg.m_UseStackupColors = false;
800 }
801 }
802
805 && aRenderJob->m_format == JOB_PCB_RENDER::FORMAT::PNG ) )
806 {
807 boardAdapter.m_ColorOverrides[LAYER_3D_BACKGROUND_TOP] = COLOR4D( 1.0, 1.0, 1.0, 0.0 );
808 boardAdapter.m_ColorOverrides[LAYER_3D_BACKGROUND_BOTTOM] = COLOR4D( 1.0, 1.0, 1.0, 0.0 );
809 }
810
812
813 static std::map<JOB_PCB_RENDER::SIDE, VIEW3D_TYPE> s_viewCmdMap = {
820 };
821
824
825 wxSize windowSize( aRenderJob->m_width, aRenderJob->m_height );
826 TRACK_BALL camera( 2 * RANGE_SCALE_3D );
827
828 camera.SetProjection( projection );
829 camera.SetCurWindowSize( windowSize );
830
831 RENDER_3D_RAYTRACE_RAM raytrace( boardAdapter, camera );
832 raytrace.SetCurWindowSize( windowSize );
833
834 for( bool first = true; raytrace.Redraw( false, m_reporter, m_reporter ); first = false )
835 {
836 if( first )
837 {
838 const float cmTo3D = boardAdapter.BiuTo3dUnits() * pcbIUScale.mmToIU( 10.0 );
839
840 // First redraw resets lookat point to the board center, so set up the camera here
841 camera.ViewCommand_T1( s_viewCmdMap[aRenderJob->m_side] );
842
843 camera.SetLookAtPos_T1( camera.GetLookAtPos_T1() + SFVEC3F( aRenderJob->m_pivot.x,
844 aRenderJob->m_pivot.y,
845 aRenderJob->m_pivot.z ) * cmTo3D );
846
847 camera.Pan_T1( SFVEC3F( aRenderJob->m_pan.x, aRenderJob->m_pan.y, aRenderJob->m_pan.z ) );
848
849 camera.Zoom_T1( aRenderJob->m_zoom );
850
851 camera.RotateX_T1( DEG2RAD( aRenderJob->m_rotation.x ) );
852 camera.RotateY_T1( DEG2RAD( aRenderJob->m_rotation.y ) );
853 camera.RotateZ_T1( DEG2RAD( aRenderJob->m_rotation.z ) );
854
855 camera.Interpolate( 1.0f );
856 camera.SetT0_and_T1_current_T();
857 camera.ParametersChanged();
858 }
859 }
860
861 uint8_t* rgbaBuffer = raytrace.GetBuffer();
862 wxSize realSize = raytrace.GetRealBufferSize();
863 bool success = !!rgbaBuffer;
864
865 if( rgbaBuffer )
866 {
867 const unsigned int wxh = realSize.x * realSize.y;
868
869 unsigned char* rgbBuffer = (unsigned char*) malloc( wxh * 3 );
870 unsigned char* alphaBuffer = (unsigned char*) malloc( wxh );
871
872 unsigned char* rgbaPtr = rgbaBuffer;
873 unsigned char* rgbPtr = rgbBuffer;
874 unsigned char* alphaPtr = alphaBuffer;
875
876 for( int y = 0; y < realSize.y; y++ )
877 {
878 for( int x = 0; x < realSize.x; x++ )
879 {
880 rgbPtr[0] = rgbaPtr[0];
881 rgbPtr[1] = rgbaPtr[1];
882 rgbPtr[2] = rgbaPtr[2];
883 alphaPtr[0] = rgbaPtr[3];
884
885 rgbaPtr += 4;
886 rgbPtr += 3;
887 alphaPtr += 1;
888 }
889 }
890
891 wxImage image( realSize );
892 image.SetData( rgbBuffer );
893 image.SetAlpha( alphaBuffer );
894 image = image.Mirror( false );
895
896 image.SetOption( wxIMAGE_OPTION_QUALITY, 90 );
897 image.SaveFile( outPath, aRenderJob->m_format == JOB_PCB_RENDER::FORMAT::PNG ? wxBITMAP_TYPE_PNG
898 : wxBITMAP_TYPE_JPEG );
899 }
900
901 if( success )
902 {
903 m_reporter->Report( _( "Successfully created 3D render image" ) + wxS( "\n" ), RPT_SEVERITY_INFO );
904 return CLI::EXIT_CODES::OK;
905 }
906 else
907 {
908 m_reporter->Report( _( "Error creating 3D render image" ) + wxS( "\n" ), RPT_SEVERITY_ERROR );
910 }
911}
912
913
915{
916 JOB_EXPORT_PCB_SVG* aSvgJob = dynamic_cast<JOB_EXPORT_PCB_SVG*>( aJob );
917
918 if( aSvgJob == nullptr )
920
921 BOARD* brd = getBoard( aSvgJob->m_filename );
922 TOOL_MANAGER* toolManager = getToolManager( brd );
923
924 if( !brd )
926
928 {
929 if( aSvgJob->GetConfiguredOutputPath().IsEmpty() )
930 {
931 wxFileName fn = brd->GetFileName();
932 fn.SetName( fn.GetName() );
934
935 aSvgJob->SetWorkingOutputPath( fn.GetFullName() );
936 }
937 }
938
939 wxString outPath = resolveJobOutputPath( aJob, brd, &aSvgJob->m_drawingSheet );
940
942 {
943 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
945 }
946
947 if( aSvgJob->m_checkZonesBeforePlot )
948 {
949 if( !toolManager->FindTool( ZONE_FILLER_TOOL_NAME ) )
950 toolManager->RegisterTool( new ZONE_FILLER_TOOL );
951
952 toolManager->GetTool<ZONE_FILLER_TOOL>()->FillAllZones( nullptr, m_progressReporter, true );
953 }
954
955 if( aSvgJob->m_argLayers )
956 aSvgJob->m_plotLayerSequence = convertLayerArg( aSvgJob->m_argLayers.value(), brd );
957
958 if( aSvgJob->m_argCommonLayers )
959 aSvgJob->m_plotOnAllLayersSequence = convertLayerArg( aSvgJob->m_argCommonLayers.value(), brd );
960
961 if( aSvgJob->m_plotLayerSequence.size() < 1 )
962 {
963 m_reporter->Report( _( "At least one layer must be specified\n" ), RPT_SEVERITY_ERROR );
965 }
966
967 PCB_PLOT_PARAMS plotOpts;
968 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, aSvgJob, *m_reporter );
969
970 PCB_PLOTTER plotter( brd, m_reporter, plotOpts );
971
972 std::optional<wxString> layerName;
973 std::optional<wxString> sheetName;
974 std::optional<wxString> sheetPath;
975
977 {
978 if( aJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
979 layerName = aSvgJob->GetVarOverrides().at( wxT( "LAYER" ) );
980
981 if( aJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
982 sheetName = aSvgJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
983
984 if( aJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
985 sheetPath = aSvgJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
986 }
987
988 if( !plotter.Plot( outPath, aSvgJob->m_plotLayerSequence, aSvgJob->m_plotOnAllLayersSequence,
990 layerName, sheetName, sheetPath ) )
991 {
993 }
994
995 return CLI::EXIT_CODES::OK;
996}
997
998
1000{
1001 JOB_EXPORT_PCB_DXF* aDxfJob = dynamic_cast<JOB_EXPORT_PCB_DXF*>( aJob );
1002
1003 if( aDxfJob == nullptr )
1005
1006 BOARD* brd = getBoard( aDxfJob->m_filename );
1007
1008 if( !brd )
1010
1011 TOOL_MANAGER* toolManager = getToolManager( brd );
1012
1013 if( aDxfJob->m_checkZonesBeforePlot )
1014 {
1015 if( !toolManager->FindTool( ZONE_FILLER_TOOL_NAME ) )
1016 toolManager->RegisterTool( new ZONE_FILLER_TOOL );
1017
1018 toolManager->GetTool<ZONE_FILLER_TOOL>()->FillAllZones( nullptr, m_progressReporter, true );
1019 }
1020
1021 if( aDxfJob->m_argLayers )
1022 aDxfJob->m_plotLayerSequence = convertLayerArg( aDxfJob->m_argLayers.value(), brd );
1023
1024 if( aDxfJob->m_argCommonLayers )
1025 aDxfJob->m_plotOnAllLayersSequence = convertLayerArg( aDxfJob->m_argCommonLayers.value(), brd );
1026
1027 if( aDxfJob->m_plotLayerSequence.size() < 1 )
1028 {
1029 m_reporter->Report( _( "At least one layer must be specified\n" ), RPT_SEVERITY_ERROR );
1031 }
1032
1034 {
1035 if( aDxfJob->GetConfiguredOutputPath().IsEmpty() )
1036 {
1037 wxFileName fn = brd->GetFileName();
1038 fn.SetName( fn.GetName() );
1040
1041 aDxfJob->SetWorkingOutputPath( fn.GetFullName() );
1042 }
1043 }
1044
1045 wxString outPath = resolveJobOutputPath( aJob, brd, &aDxfJob->m_drawingSheet );
1046
1048 {
1049 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1051 }
1052
1053 PCB_PLOT_PARAMS plotOpts;
1054 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, aDxfJob, *m_reporter);
1055
1056 PCB_PLOTTER plotter( brd, m_reporter, plotOpts );
1057
1058 std::optional<wxString> layerName;
1059 std::optional<wxString> sheetName;
1060 std::optional<wxString> sheetPath;
1061
1063 {
1064 if( aJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
1065 layerName = aDxfJob->GetVarOverrides().at( wxT( "LAYER" ) );
1066
1067 if( aJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
1068 sheetName = aDxfJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
1069
1070 if( aJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
1071 sheetPath = aDxfJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
1072 }
1073
1074 if( !plotter.Plot( outPath, aDxfJob->m_plotLayerSequence, aDxfJob->m_plotOnAllLayersSequence,
1076 layerName, sheetName, sheetPath ) )
1077 {
1079 }
1080
1081 return CLI::EXIT_CODES::OK;
1082}
1083
1084
1086{
1087 bool plotAllLayersOneFile = false;
1088 JOB_EXPORT_PCB_PDF* pdfJob = dynamic_cast<JOB_EXPORT_PCB_PDF*>( aJob );
1089
1090 if( pdfJob == nullptr )
1092
1093 BOARD* brd = getBoard( pdfJob->m_filename );
1094
1095 if( !brd )
1097
1098 TOOL_MANAGER* toolManager = getToolManager( brd );
1099
1100 if( pdfJob->m_checkZonesBeforePlot )
1101 {
1102 if( !toolManager->FindTool( ZONE_FILLER_TOOL_NAME ) )
1103 toolManager->RegisterTool( new ZONE_FILLER_TOOL );
1104
1105 toolManager->GetTool<ZONE_FILLER_TOOL>()->FillAllZones( nullptr, m_progressReporter, true );
1106 }
1107
1108 if( pdfJob->m_argLayers )
1109 pdfJob->m_plotLayerSequence = convertLayerArg( pdfJob->m_argLayers.value(), brd );
1110
1111 if( pdfJob->m_argCommonLayers )
1112 pdfJob->m_plotOnAllLayersSequence = convertLayerArg( pdfJob->m_argCommonLayers.value(), brd );
1113
1115 plotAllLayersOneFile = true;
1116
1117 if( pdfJob->m_plotLayerSequence.size() < 1 )
1118 {
1119 m_reporter->Report( _( "At least one layer must be specified\n" ), RPT_SEVERITY_ERROR );
1121 }
1122
1123 const bool outputIsSingle = plotAllLayersOneFile || pdfJob->m_pdfSingle;
1124
1125 if( outputIsSingle && pdfJob->GetConfiguredOutputPath().IsEmpty() )
1126 {
1127 wxFileName fn = brd->GetFileName();
1128 fn.SetName( fn.GetName() );
1130
1131 pdfJob->SetWorkingOutputPath( fn.GetFullName() );
1132 }
1133
1134 wxString outPath = resolveJobOutputPath( pdfJob, brd, &pdfJob->m_drawingSheet );
1135
1136 PCB_PLOT_PARAMS plotOpts;
1137 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, pdfJob, *m_reporter );
1138
1139 PCB_PLOTTER pcbPlotter( brd, m_reporter, plotOpts );
1140
1141 if( !PATHS::EnsurePathExists( outPath, outputIsSingle ) )
1142 {
1143 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1145 }
1146
1147 std::optional<wxString> layerName;
1148 std::optional<wxString> sheetName;
1149 std::optional<wxString> sheetPath;
1150
1151 if( plotAllLayersOneFile )
1152 {
1153 if( pdfJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
1154 layerName = pdfJob->GetVarOverrides().at( wxT( "LAYER" ) );
1155
1156 if( pdfJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
1157 sheetName = pdfJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
1158
1159 if( pdfJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
1160 sheetPath = pdfJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
1161 }
1162
1163 if( !pcbPlotter.Plot( outPath, pdfJob->m_plotLayerSequence,
1164 pdfJob->m_plotOnAllLayersSequence, false, outputIsSingle,
1165 layerName, sheetName, sheetPath ) )
1166 {
1168 }
1169
1170 return CLI::EXIT_CODES::OK;
1171}
1172
1173
1175{
1176 JOB_EXPORT_PCB_PS* psJob = dynamic_cast<JOB_EXPORT_PCB_PS*>( aJob );
1177
1178 if( psJob == nullptr )
1180
1181 BOARD* brd = getBoard( psJob->m_filename );
1182
1183 if( !brd )
1185
1186 TOOL_MANAGER* toolManager = getToolManager( brd );
1187
1188 if( psJob->m_checkZonesBeforePlot )
1189 {
1190 if( !toolManager->FindTool( ZONE_FILLER_TOOL_NAME ) )
1191 toolManager->RegisterTool( new ZONE_FILLER_TOOL );
1192
1193 toolManager->GetTool<ZONE_FILLER_TOOL>()->FillAllZones( nullptr, m_progressReporter, true );
1194 }
1195
1196 if( psJob->m_argLayers )
1197 psJob->m_plotLayerSequence = convertLayerArg( psJob->m_argLayers.value(), brd );
1198
1199 if( psJob->m_argCommonLayers )
1200 psJob->m_plotOnAllLayersSequence = convertLayerArg( psJob->m_argCommonLayers.value(), brd );
1201
1202 if( psJob->m_plotLayerSequence.size() < 1 )
1203 {
1204 m_reporter->Report( _( "At least one layer must be specified\n" ), RPT_SEVERITY_ERROR );
1206 }
1207
1208 bool isSingle = psJob->m_genMode == JOB_EXPORT_PCB_PS::GEN_MODE::SINGLE;
1209
1210 if( isSingle )
1211 {
1212 if( psJob->GetConfiguredOutputPath().IsEmpty() )
1213 {
1214 wxFileName fn = brd->GetFileName();
1215 fn.SetName( fn.GetName() );
1217
1218 psJob->SetWorkingOutputPath( fn.GetFullName() );
1219 }
1220 }
1221
1222 wxString outPath = resolveJobOutputPath( psJob, brd, &psJob->m_drawingSheet );
1223
1224 if( !PATHS::EnsurePathExists( outPath, isSingle ) )
1225 {
1226 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1228 }
1229
1230 PCB_PLOT_PARAMS plotOpts;
1231 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, psJob, *m_reporter );
1232
1233 PCB_PLOTTER pcbPlotter( brd, m_reporter, plotOpts );
1234
1235 std::optional<wxString> layerName;
1236 std::optional<wxString> sheetName;
1237 std::optional<wxString> sheetPath;
1238
1239 if( isSingle )
1240 {
1241 if( aJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
1242 layerName = psJob->GetVarOverrides().at( wxT( "LAYER" ) );
1243
1244 if( aJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
1245 sheetName = psJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
1246
1247 if( aJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
1248 sheetPath = psJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
1249 }
1250
1251 if( !pcbPlotter.Plot( outPath, psJob->m_plotLayerSequence, psJob->m_plotOnAllLayersSequence, false, isSingle,
1252 layerName, sheetName, sheetPath ) )
1253 {
1255 }
1256
1257 return CLI::EXIT_CODES::OK;
1258}
1259
1260
1262{
1263 int exitCode = CLI::EXIT_CODES::OK;
1264 JOB_EXPORT_PCB_GERBERS* aGerberJob = dynamic_cast<JOB_EXPORT_PCB_GERBERS*>( aJob );
1265
1266 if( aGerberJob == nullptr )
1268
1269 BOARD* brd = getBoard( aGerberJob->m_filename );
1270
1271 if( !brd )
1273
1274 wxString outPath = resolveJobOutputPath( aJob, brd, &aGerberJob->m_drawingSheet );
1275
1276 if( !PATHS::EnsurePathExists( outPath, false ) )
1277 {
1278 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1280 }
1281
1282 TOOL_MANAGER* toolManager = getToolManager( brd );
1283
1284 if( aGerberJob->m_checkZonesBeforePlot )
1285 {
1286 if( !toolManager->FindTool( ZONE_FILLER_TOOL_NAME ) )
1287 toolManager->RegisterTool( new ZONE_FILLER_TOOL );
1288
1289 toolManager->GetTool<ZONE_FILLER_TOOL>()->FillAllZones( nullptr, m_progressReporter, true );
1290 }
1291
1292 bool hasLayerListSpecified = false; // will be true if the user layer list is not empty
1293
1294 if( aGerberJob->m_argLayers )
1295 {
1296 if( !aGerberJob->m_argLayers.value().empty() )
1297 {
1298 aGerberJob->m_plotLayerSequence = convertLayerArg( aGerberJob->m_argLayers.value(), brd );
1299 hasLayerListSpecified = true;
1300 }
1301 else
1302 {
1304 }
1305 }
1306
1307 if( aGerberJob->m_argCommonLayers )
1308 aGerberJob->m_plotOnAllLayersSequence = convertLayerArg( aGerberJob->m_argCommonLayers.value(), brd );
1309
1310 PCB_PLOT_PARAMS boardPlotOptions = brd->GetPlotOptions();
1311 GERBER_JOBFILE_WRITER jobfile_writer( brd );
1312
1313 wxString fileExt;
1314
1315 if( aGerberJob->m_useBoardPlotParams )
1316 {
1317 // The board plot options are saved with all copper layers enabled, even those that don't
1318 // exist in the current stackup. This is done so the layers are automatically enabled in the plot
1319 // dialog when the user enables them. We need to filter out these not-enabled layers here so
1320 // we don't plot 32 layers when we only have 4, etc.
1321 LSET plotLayers = ( boardPlotOptions.GetLayerSelection() & LSET::AllNonCuMask() )
1322 | ( brd->GetEnabledLayers() & LSET::AllCuMask() );
1323 aGerberJob->m_plotLayerSequence = plotLayers.SeqStackupForPlotting();
1324 aGerberJob->m_plotOnAllLayersSequence = boardPlotOptions.GetPlotOnAllLayersSequence();
1325 }
1326 else
1327 {
1328 // default to the board enabled layers, but only if the user has not specifed a layer list
1329 // ( m_plotLayerSequence can be empty with a broken user layer list)
1330 if( aGerberJob->m_plotLayerSequence.empty() && !hasLayerListSpecified )
1332 }
1333
1334 // Ensure layers to plot are restricted to enabled layers of the board to plot
1335 LSET layersToPlot = LSET( { aGerberJob->m_plotLayerSequence } ) & brd->GetEnabledLayers();
1336
1337 for( PCB_LAYER_ID layer : layersToPlot.UIOrder() )
1338 {
1339 LSEQ plotSequence;
1340
1341 // Base layer always gets plotted first.
1342 plotSequence.push_back( layer );
1343
1344 // Now all the "include on all" layers
1345 for( PCB_LAYER_ID layer_all : aGerberJob->m_plotOnAllLayersSequence )
1346 {
1347 // Don't plot the same layer more than once;
1348 if( find( plotSequence.begin(), plotSequence.end(), layer_all ) != plotSequence.end() )
1349 continue;
1350
1351 plotSequence.push_back( layer_all );
1352 }
1353
1354 // Pick the basename from the board file
1355 wxFileName fn( brd->GetFileName() );
1356 wxString layerName = brd->GetLayerName( layer );
1357 wxString sheetName;
1358 wxString sheetPath;
1359 PCB_PLOT_PARAMS plotOpts;
1360
1361 if( aGerberJob->m_useBoardPlotParams )
1362 plotOpts = boardPlotOptions;
1363 else
1364 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, aGerberJob, *m_reporter );
1365
1366 if( plotOpts.GetUseGerberProtelExtensions() )
1367 fileExt = GetGerberProtelExtension( layer );
1368 else
1370
1371 BuildPlotFileName( &fn, outPath, layerName, fileExt );
1372 wxString fullname = fn.GetFullName();
1373
1374 if( m_progressReporter )
1375 {
1376 m_progressReporter->AdvancePhase( wxString::Format( _( "Exporting %s" ), fullname ) );
1377 m_progressReporter->KeepRefreshing();
1378 }
1379
1380 jobfile_writer.AddGbrFile( layer, fullname );
1381
1382 if( aJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
1383 layerName = aJob->GetVarOverrides().at( wxT( "LAYER" ) );
1384
1385 if( aJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
1386 sheetName = aJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
1387
1388 if( aJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
1389 sheetPath = aJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
1390
1391 // We are feeding it one layer at the start here to silence a logic check
1392 GERBER_PLOTTER* plotter;
1393 plotter = (GERBER_PLOTTER*) StartPlotBoard( brd, &plotOpts, layer, layerName,
1394 fn.GetFullPath(), sheetName, sheetPath );
1395
1396 if( plotter )
1397 {
1398 m_reporter->Report( wxString::Format( _( "Plotted to '%s'.\n" ), fn.GetFullPath() ),
1400
1401 PlotBoardLayers( brd, plotter, plotSequence, plotOpts );
1402 plotter->EndPlot();
1403 }
1404 else
1405 {
1406 m_reporter->Report( wxString::Format( _( "Failed to plot to '%s'.\n" ), fn.GetFullPath() ),
1409 }
1410
1411 delete plotter;
1412 }
1413
1414 if( aGerberJob->m_createJobsFile )
1415 {
1416 wxFileName fn( brd->GetFileName() );
1417
1418 // Build gerber job file from basename
1419 BuildPlotFileName( &fn, outPath, wxT( "job" ), FILEEXT::GerberJobFileExtension );
1420 jobfile_writer.CreateJobFile( fn.GetFullPath() );
1421 }
1422
1423 return exitCode;
1424}
1425
1426
1428{
1429 JOB_EXPORT_PCB_GENCAD* aGencadJob = dynamic_cast<JOB_EXPORT_PCB_GENCAD*>( aJob );
1430
1431 if( aGencadJob == nullptr )
1433
1434 BOARD* brd = LoadBoard( aGencadJob->m_filename, true ); // Ensure m_board is of type BOARD*
1435
1436 if( brd == nullptr )
1438
1439 GENCAD_EXPORTER exporter( brd );
1440
1441 VECTOR2I GencadOffset;
1442 VECTOR2I auxOrigin = brd->GetDesignSettings().GetAuxOrigin();
1443 GencadOffset.x = aGencadJob->m_useDrillOrigin ? auxOrigin.x : 0;
1444 GencadOffset.y = aGencadJob->m_useDrillOrigin ? auxOrigin.y : 0;
1445
1446 exporter.FlipBottomPads( aGencadJob->m_flipBottomPads );
1447 exporter.UsePinNamesUnique( aGencadJob->m_useUniquePins );
1448 exporter.UseIndividualShapes( aGencadJob->m_useIndividualShapes );
1449 exporter.SetPlotOffet( GencadOffset );
1450 exporter.StoreOriginCoordsInFile( aGencadJob->m_storeOriginCoords );
1451
1452 if( aGencadJob->GetConfiguredOutputPath().IsEmpty() )
1453 {
1454 wxFileName fn = brd->GetFileName();
1455 fn.SetName( fn.GetName() );
1456 fn.SetExt( FILEEXT::GencadFileExtension );
1457
1458 aGencadJob->SetWorkingOutputPath( fn.GetFullName() );
1459 }
1460
1461 wxString outPath = resolveJobOutputPath( aJob, brd );
1462
1463 if( !PATHS::EnsurePathExists( outPath, true ) )
1464 {
1465 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1467 }
1468
1469 if( !exporter.WriteFile( outPath ) )
1470 {
1471 m_reporter->Report( wxString::Format( _( "Failed to create file '%s'.\n" ), outPath ),
1473
1475 }
1476
1477 m_reporter->Report( _( "Successfully created genCAD file\n" ), RPT_SEVERITY_INFO );
1478
1479 return CLI::EXIT_CODES::OK;
1480}
1481
1482
1484{
1485 JOB_EXPORT_PCB_STATS* statsJob = dynamic_cast<JOB_EXPORT_PCB_STATS*>( aJob );
1486
1487 if( statsJob == nullptr )
1489
1490 BOARD* brd = getBoard( statsJob->m_filename );
1491
1492 if( !brd )
1494
1497
1502
1503 ComputeBoardStatistics( brd, options, data );
1504
1505 wxString projectName;
1506
1507 if( brd->GetProject() )
1508 projectName = brd->GetProject()->GetProjectName();
1509
1510 wxFileName boardFile = brd->GetFileName();
1511
1512 if( boardFile.GetName().IsEmpty() )
1513 boardFile = wxFileName( statsJob->m_filename );
1514
1516 UNITS_PROVIDER unitsProvider( pcbIUScale, unitsForReport );
1517
1518 wxString report;
1519
1521 report = FormatBoardStatisticsJson( data, brd, unitsProvider, projectName, boardFile.GetName() );
1522 else
1523 report = FormatBoardStatisticsReport( data, brd, unitsProvider, projectName, boardFile.GetName() );
1524
1525 if( statsJob->GetConfiguredOutputPath().IsEmpty() && statsJob->GetWorkingOutputPath().IsEmpty() )
1526 statsJob->SetDefaultOutputPath( boardFile.GetFullPath() );
1527
1528 wxString outPath = resolveJobOutputPath( aJob, brd );
1529
1530 if( !PATHS::EnsurePathExists( outPath, true ) )
1531 {
1532 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1534 }
1535
1536 FILE* outFile = wxFopen( outPath, wxS( "wt" ) );
1537
1538 if( !outFile )
1539 {
1540 m_reporter->Report( wxString::Format( _( "Failed to create file '%s'.\n" ), outPath ), RPT_SEVERITY_ERROR );
1542 }
1543
1544 if( fprintf( outFile, "%s", TO_UTF8( report ) ) < 0 )
1545 {
1546 fclose( outFile );
1547 m_reporter->Report( wxString::Format( _( "Error writing file '%s'.\n" ), outPath ), RPT_SEVERITY_ERROR );
1549 }
1550
1551 fclose( outFile );
1552
1553 m_reporter->Report( wxString::Format( _( "Wrote board statistics to '%s'.\n" ), outPath ), RPT_SEVERITY_ACTION );
1554
1555 statsJob->AddOutput( outPath );
1556
1557 return CLI::EXIT_CODES::OK;
1558}
1559
1560
1562{
1563 int exitCode = CLI::EXIT_CODES::OK;
1564 JOB_EXPORT_PCB_GERBER* aGerberJob = dynamic_cast<JOB_EXPORT_PCB_GERBER*>( aJob );
1565
1566 if( aGerberJob == nullptr )
1568
1569 BOARD* brd = getBoard( aGerberJob->m_filename );
1570
1571 if( !brd )
1573
1574 TOOL_MANAGER* toolManager = getToolManager( brd );
1575
1576 if( aGerberJob->m_argLayers )
1577 aGerberJob->m_plotLayerSequence = convertLayerArg( aGerberJob->m_argLayers.value(), brd );
1578
1579 if( aGerberJob->m_argCommonLayers )
1580 aGerberJob->m_plotOnAllLayersSequence = convertLayerArg( aGerberJob->m_argCommonLayers.value(), brd );
1581
1582 if( aGerberJob->m_plotLayerSequence.size() < 1 )
1583 {
1584 m_reporter->Report( _( "At least one layer must be specified\n" ), RPT_SEVERITY_ERROR );
1586 }
1587
1588 if( aGerberJob->GetConfiguredOutputPath().IsEmpty() )
1589 {
1590 wxFileName fn = brd->GetFileName();
1591 fn.SetName( fn.GetName() );
1593
1594 aGerberJob->SetWorkingOutputPath( fn.GetFullName() );
1595 }
1596
1597 wxString outPath = resolveJobOutputPath( aJob, brd );
1598
1599 if( aGerberJob->m_checkZonesBeforePlot )
1600 {
1601 if( !toolManager->FindTool( ZONE_FILLER_TOOL_NAME ) )
1602 toolManager->RegisterTool( new ZONE_FILLER_TOOL );
1603
1604 toolManager->GetTool<ZONE_FILLER_TOOL>()->FillAllZones( nullptr, m_progressReporter, true );
1605 }
1606
1607 PCB_PLOT_PARAMS plotOpts;
1608 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, aGerberJob, *m_reporter );
1609 plotOpts.SetLayerSelection( aGerberJob->m_plotLayerSequence );
1611
1613 wxString layerName;
1614 wxString sheetName;
1615 wxString sheetPath;
1616
1617 // The first layer will be treated as the layer name for the gerber header,
1618 // the other layers will be treated equivalent to the "Plot on All Layers" option
1619 // in the GUI
1620 if( aGerberJob->m_plotLayerSequence.size() >= 1 )
1621 {
1622 layer = aGerberJob->m_plotLayerSequence.front();
1623 layerName = brd->GetLayerName( layer );
1624 }
1625
1626 if( aJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
1627 layerName = aJob->GetVarOverrides().at( wxT( "LAYER" ) );
1628
1629 if( aJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
1630 sheetName = aJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
1631
1632 if( aJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
1633 sheetPath = aJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
1634
1635 // We are feeding it one layer at the start here to silence a logic check
1636 PLOTTER* plotter = StartPlotBoard( brd, &plotOpts, layer, layerName, outPath, sheetName,
1637 sheetPath );
1638
1639 if( plotter )
1640 {
1641 PlotBoardLayers( brd, plotter, aGerberJob->m_plotLayerSequence, plotOpts );
1642 plotter->EndPlot();
1643 }
1644 else
1645 {
1646 m_reporter->Report( wxString::Format( _( "Failed to plot to '%s'.\n" ), outPath ),
1649 }
1650
1651 delete plotter;
1652
1653 return exitCode;
1654}
1655
1658
1659
1661{
1662 JOB_EXPORT_PCB_DRILL* aDrillJob = dynamic_cast<JOB_EXPORT_PCB_DRILL*>( aJob );
1663
1664 if( aDrillJob == nullptr )
1666
1667 BOARD* brd = getBoard( aDrillJob->m_filename );
1668
1669 if( !brd )
1671
1672 wxString outPath = resolveJobOutputPath( aJob, brd );
1673
1674 if( !PATHS::EnsurePathExists( outPath ) )
1675 {
1676 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1678 }
1679
1680 std::unique_ptr<GENDRILL_WRITER_BASE> drillWriter;
1681
1683 drillWriter = std::make_unique<EXCELLON_WRITER>( brd );
1684 else
1685 drillWriter = std::make_unique<GERBER_WRITER>( brd );
1686
1687 VECTOR2I offset;
1688
1690 offset = VECTOR2I( 0, 0 );
1691 else
1692 offset = brd->GetDesignSettings().GetAuxOrigin();
1693
1694 PLOT_FORMAT mapFormat = PLOT_FORMAT::PDF;
1695
1696 switch( aDrillJob->m_mapFormat )
1697 {
1702 default:
1704 }
1705
1706
1707 if( aDrillJob->m_generateReport && aDrillJob->m_reportPath.IsEmpty() )
1708 {
1709 wxFileName fn = outPath;
1710 fn.SetFullName( brd->GetFileName() );
1711 fn.SetName( fn.GetName() + "-drill" );
1712 fn.SetExt( FILEEXT::ReportFileExtension );
1713
1714 aDrillJob->m_reportPath = fn.GetFullPath();
1715 }
1716
1718 {
1720
1721 switch( aDrillJob->m_zeroFormat )
1722 {
1725 break;
1726
1729 break;
1730
1733 break;
1734
1736 default:
1738 break;
1739 }
1740
1741 DRILL_PRECISION precision;
1742
1744 precision = precisionListForInches;
1745 else
1746 precision = precisionListForMetric;
1747
1748 EXCELLON_WRITER* excellonWriter = dynamic_cast<EXCELLON_WRITER*>( drillWriter.get() );
1749
1750 if( excellonWriter == nullptr )
1752
1753 excellonWriter->SetFormat( aDrillJob->m_drillUnits == JOB_EXPORT_PCB_DRILL::DRILL_UNITS::MM,
1754 zeroFmt, precision.m_Lhs, precision.m_Rhs );
1755 excellonWriter->SetOptions( aDrillJob->m_excellonMirrorY,
1756 aDrillJob->m_excellonMinimalHeader,
1757 offset, aDrillJob->m_excellonCombinePTHNPTH );
1758 excellonWriter->SetRouteModeForOvalHoles( aDrillJob->m_excellonOvalDrillRoute );
1759 excellonWriter->SetMapFileFormat( mapFormat );
1760
1761 if( !excellonWriter->CreateDrillandMapFilesSet( outPath, true, aDrillJob->m_generateMap,
1762 m_reporter ) )
1763 {
1765 }
1766
1767 if( aDrillJob->m_generateReport )
1768 {
1769 wxString reportPath = aDrillJob->ResolveOutputPath( aDrillJob->m_reportPath, true, brd->GetProject() );
1770
1771 if( !excellonWriter->GenDrillReportFile( reportPath ) )
1772 {
1774 }
1775 }
1776 }
1778 {
1779 GERBER_WRITER* gerberWriter = dynamic_cast<GERBER_WRITER*>( drillWriter.get() );
1780
1781 if( gerberWriter == nullptr )
1783
1784 // Set gerber precision: only 5 or 6 digits for mantissa are allowed
1785 // (SetFormat() accept 5 or 6, and any other value set the precision to 5)
1786 // the integer part precision is always 4, and units always mm
1787 gerberWriter->SetFormat( aDrillJob->m_gerberPrecision );
1788 gerberWriter->SetOptions( offset );
1789 gerberWriter->SetMapFileFormat( mapFormat );
1790
1791 if( !gerberWriter->CreateDrillandMapFilesSet( outPath, true, aDrillJob->m_generateMap,
1792 aDrillJob->m_generateTenting, m_reporter ) )
1793 {
1795 }
1796
1797 if( aDrillJob->m_generateReport )
1798 {
1799 wxString reportPath = aDrillJob->ResolveOutputPath( aDrillJob->m_reportPath, true, brd->GetProject() );
1800
1801 if( !gerberWriter->GenDrillReportFile( reportPath ) )
1802 {
1804 }
1805 }
1806 }
1807
1808 return CLI::EXIT_CODES::OK;
1809}
1810
1811
1813{
1814 JOB_EXPORT_PCB_POS* aPosJob = dynamic_cast<JOB_EXPORT_PCB_POS*>( aJob );
1815
1816 if( aPosJob == nullptr )
1818
1819 BOARD* brd = getBoard( aPosJob->m_filename );
1820
1821 if( !brd )
1823
1824 if( aPosJob->GetConfiguredOutputPath().IsEmpty() )
1825 {
1826 wxFileName fn = brd->GetFileName();
1827 fn.SetName( fn.GetName() );
1828
1831 else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::CSV )
1832 fn.SetExt( FILEEXT::CsvFileExtension );
1833 else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::GERBER )
1834 fn.SetExt( FILEEXT::GerberFileExtension );
1835
1836 aPosJob->SetWorkingOutputPath( fn.GetFullName() );
1837 }
1838
1839 wxString outPath = resolveJobOutputPath( aJob, brd );
1840
1841 if( !PATHS::EnsurePathExists( outPath, true ) )
1842 {
1843 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1845 }
1846
1849 {
1850 wxFileName fn( outPath );
1851 wxString baseName = fn.GetName();
1852
1853 auto exportPlaceFile =
1854 [&]( bool frontSide, bool backSide, const wxString& curr_outPath ) -> bool
1855 {
1856 FILE* file = wxFopen( curr_outPath, wxS( "wt" ) );
1857 wxCHECK( file, false );
1858
1859 PLACE_FILE_EXPORTER exporter( brd,
1861 aPosJob->m_smdOnly,
1863 aPosJob->m_excludeDNP,
1864 aPosJob->m_excludeBOM,
1865 frontSide,
1866 backSide,
1869 aPosJob->m_negateBottomX );
1870
1871 // Set variant for variant-aware DNP/BOM/position file filtering
1872 exporter.SetVariant( aPosJob->m_variant );
1873
1874 std::string data = exporter.GenPositionData();
1875 fputs( data.c_str(), file );
1876 fclose( file );
1877
1878 return true;
1879 };
1880
1881 if( aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH && !aPosJob->m_singleFile )
1882 {
1883 fn.SetName( PLACE_FILE_EXPORTER::DecorateFilename( baseName, true, false ) );
1884
1885 if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::CSV && !aPosJob->m_nakedFilename )
1886 fn.SetName( fn.GetName() + wxT( "-" ) + FILEEXT::FootprintPlaceFileExtension );
1887
1888 if( exportPlaceFile( true, false, fn.GetFullPath() ) )
1889 {
1890 m_reporter->Report( wxString::Format( _( "Wrote front position data to '%s'.\n" ),
1891 fn.GetFullPath() ),
1893
1894 aPosJob->AddOutput( fn.GetFullPath() );
1895 }
1896 else
1897 {
1899 }
1900
1901 fn.SetName( PLACE_FILE_EXPORTER::DecorateFilename( baseName, false, true ) );
1902
1903 if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::CSV && !aPosJob->m_nakedFilename )
1904 fn.SetName( fn.GetName() + wxT( "-" ) + FILEEXT::FootprintPlaceFileExtension );
1905
1906 if( exportPlaceFile( false, true, fn.GetFullPath() ) )
1907 {
1908 m_reporter->Report( wxString::Format( _( "Wrote back position data to '%s'.\n" ),
1909 fn.GetFullPath() ),
1911
1912 aPosJob->AddOutput( fn.GetFullPath() );
1913 }
1914 else
1915 {
1917 }
1918 }
1919 else
1920 {
1921 bool front = aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::FRONT
1923
1924 bool back = aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BACK
1926
1927 if( !aPosJob->m_nakedFilename )
1928 {
1929 fn.SetName( PLACE_FILE_EXPORTER::DecorateFilename( fn.GetName(), front, back ) );
1930
1932 fn.SetName( fn.GetName() + wxT( "-" ) + FILEEXT::FootprintPlaceFileExtension );
1933 }
1934
1935 if( exportPlaceFile( front, back, fn.GetFullPath() ) )
1936 {
1937 m_reporter->Report( wxString::Format( _( "Wrote position data to '%s'.\n" ),
1938 fn.GetFullPath() ),
1940
1941 aPosJob->AddOutput( fn.GetFullPath() );
1942 }
1943 else
1944 {
1946 }
1947 }
1948 }
1949 else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::GERBER )
1950 {
1951 PLACEFILE_GERBER_WRITER exporter( brd );
1952
1953 // Set variant for variant-aware DNP/BOM/position file filtering
1954 exporter.SetVariant( aPosJob->m_variant );
1955
1956 PCB_LAYER_ID gbrLayer = F_Cu;
1957 wxString outPath_base = outPath;
1958
1960 || aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH )
1961 {
1962 if( aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH || !aPosJob->m_nakedFilename )
1963 outPath = exporter.GetPlaceFileName( outPath, gbrLayer );
1964
1965 if( exporter.CreatePlaceFile( outPath, gbrLayer, aPosJob->m_gerberBoardEdge,
1966 aPosJob->m_excludeDNP, aPosJob->m_excludeBOM ) >= 0 )
1967 {
1968 m_reporter->Report( wxString::Format( _( "Wrote front position data to '%s'.\n" ), outPath ),
1970
1971 aPosJob->AddOutput( outPath );
1972 }
1973 else
1974 {
1976 }
1977 }
1978
1980 || aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH )
1981 {
1982 gbrLayer = B_Cu;
1983
1984 outPath = outPath_base;
1985
1986 if( aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH || !aPosJob->m_nakedFilename )
1987 outPath = exporter.GetPlaceFileName( outPath, gbrLayer );
1988
1989 if( exporter.CreatePlaceFile( outPath, gbrLayer, aPosJob->m_gerberBoardEdge,
1990 aPosJob->m_excludeDNP, aPosJob->m_excludeBOM ) >= 0 )
1991 {
1992 m_reporter->Report( wxString::Format( _( "Wrote back position data to '%s'.\n" ), outPath ),
1994
1995 aPosJob->AddOutput( outPath );
1996 }
1997 else
1998 {
2000 }
2001 }
2002 }
2003
2004 return CLI::EXIT_CODES::OK;
2005}
2006
2007
2009{
2010 JOB_FP_UPGRADE* upgradeJob = dynamic_cast<JOB_FP_UPGRADE*>( aJob );
2011
2012 if( upgradeJob == nullptr )
2014
2016
2017 if( !upgradeJob->m_outputLibraryPath.IsEmpty() )
2018 {
2019 if( wxFile::Exists( upgradeJob->m_outputLibraryPath )
2020 || wxDir::Exists( upgradeJob->m_outputLibraryPath) )
2021 {
2022 m_reporter->Report( _( "Output path must not conflict with existing path\n" ),
2025 }
2026 }
2027 else if( fileType != PCB_IO_MGR::KICAD_SEXP )
2028 {
2029 m_reporter->Report( _( "Output path must be specified to convert legacy and non-KiCad libraries\n" ),
2031
2033 }
2034
2036 {
2037 if( !wxDir::Exists( upgradeJob->m_libraryPath ) )
2038 {
2039 m_reporter->Report( _( "Footprint library path does not exist or is not accessible\n" ),
2042 }
2043
2045 FP_CACHE fpLib( &pcb_io, upgradeJob->m_libraryPath );
2046
2047 try
2048 {
2049 fpLib.Load();
2050 }
2051 catch( ... )
2052 {
2053 m_reporter->Report( _( "Unable to load library\n" ), RPT_SEVERITY_ERROR );
2055 }
2056
2057 if( m_progressReporter )
2058 m_progressReporter->KeepRefreshing();
2059
2060 bool shouldSave = upgradeJob->m_force;
2061
2062 for( const auto& footprint : fpLib.GetFootprints() )
2063 {
2064 if( footprint.second->GetFootprint()->GetFileFormatVersionAtLoad() < SEXPR_BOARD_FILE_VERSION )
2065 shouldSave = true;
2066 }
2067
2068 if( shouldSave )
2069 {
2070 try
2071 {
2072 if( !upgradeJob->m_outputLibraryPath.IsEmpty() )
2073 fpLib.SetPath( upgradeJob->m_outputLibraryPath );
2074
2075 fpLib.Save();
2076 }
2077 catch( ... )
2078 {
2079 m_reporter->Report( _( "Unable to save library\n" ), RPT_SEVERITY_ERROR );
2081 }
2082 }
2083 else
2084 {
2085 m_reporter->Report( _( "Footprint library was not updated\n" ), RPT_SEVERITY_ERROR );
2086 }
2087 }
2088 else
2089 {
2090 if( !PCB_IO_MGR::ConvertLibrary( {}, upgradeJob->m_libraryPath,
2091 upgradeJob->m_outputLibraryPath, nullptr /* REPORTER */ ) )
2092 {
2093 m_reporter->Report( ( "Unable to convert library\n" ), RPT_SEVERITY_ERROR );
2095 }
2096 }
2097
2098 return CLI::EXIT_CODES::OK;
2099}
2100
2101
2103{
2104 JOB_FP_EXPORT_SVG* svgJob = dynamic_cast<JOB_FP_EXPORT_SVG*>( aJob );
2105
2106 if( svgJob == nullptr )
2108
2110 FP_CACHE fpLib( &pcb_io, svgJob->m_libraryPath );
2111
2112 if( svgJob->m_argLayers )
2113 {
2114 if( !svgJob->m_argLayers.value().empty() )
2115 svgJob->m_plotLayerSequence = convertLayerArg( svgJob->m_argLayers.value(), nullptr );
2116 else
2118 }
2119
2120 try
2121 {
2122 fpLib.Load();
2123 }
2124 catch( ... )
2125 {
2126 m_reporter->Report( _( "Unable to load library\n" ), RPT_SEVERITY_ERROR );
2128 }
2129
2130 wxString outPath = svgJob->GetFullOutputPath( nullptr );
2131
2132 if( !PATHS::EnsurePathExists( outPath, true ) )
2133 {
2134 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
2136 }
2137
2138 int exitCode = CLI::EXIT_CODES::OK;
2139 bool singleFpPlotted = false;
2140
2141 for( const auto& [fpName, fpCacheEntry] : fpLib.GetFootprints() )
2142 {
2143 if( m_progressReporter )
2144 {
2145 m_progressReporter->AdvancePhase( wxString::Format( _( "Exporting %s" ), fpName ) );
2146 m_progressReporter->KeepRefreshing();
2147 }
2148
2149 if( !svgJob->m_footprint.IsEmpty() )
2150 {
2151 // skip until we find the right footprint
2152 if( fpName != svgJob->m_footprint )
2153 continue;
2154 else
2155 singleFpPlotted = true;
2156 }
2157
2158 exitCode = doFpExportSvg( svgJob, fpCacheEntry->GetFootprint().get() );
2159
2160 if( exitCode != CLI::EXIT_CODES::OK )
2161 break;
2162 }
2163
2164 if( !svgJob->m_footprint.IsEmpty() && !singleFpPlotted )
2165 {
2166 m_reporter->Report( _( "The given footprint could not be found to export." ) + wxS( "\n" ),
2168 }
2169
2170 return CLI::EXIT_CODES::OK;
2171}
2172
2173
2175{
2176 // the hack for now is we create fake boards containing the footprint and plot the board
2177 // until we refactor better plot api later
2178 std::unique_ptr<BOARD> brd;
2179 brd.reset( CreateEmptyBoard() );
2180 brd->GetProject()->ApplyTextVars( aSvgJob->GetVarOverrides() );
2181 brd->SynchronizeProperties();
2182
2183 FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( aFootprint->Clone() );
2184
2185 if( fp == nullptr )
2187
2188 fp->SetLink( niluuid );
2189 fp->SetFlags( IS_NEW );
2190 fp->SetParent( brd.get() );
2191
2192 for( PAD* pad : fp->Pads() )
2193 {
2194 pad->SetLocalRatsnestVisible( false );
2195 pad->SetNetCode( 0 );
2196 }
2197
2198 fp->SetOrientation( ANGLE_0 );
2199 fp->SetPosition( VECTOR2I( 0, 0 ) );
2200
2201 brd->Add( fp, ADD_MODE::INSERT, true );
2202
2203 wxFileName outputFile;
2204 outputFile.SetPath( aSvgJob->GetFullOutputPath(nullptr) );
2205 outputFile.SetName( aFootprint->GetFPID().GetLibItemName().wx_str() );
2206 outputFile.SetExt( FILEEXT::SVGFileExtension );
2207
2208 m_reporter->Report( wxString::Format( _( "Plotting footprint '%s' to '%s'\n" ),
2209 aFootprint->GetFPID().GetLibItemName().wx_str(),
2210 outputFile.GetFullPath() ),
2212
2213 PCB_PLOT_PARAMS plotOpts;
2214 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, aSvgJob, *m_reporter );
2215
2216 // always fixed for the svg plot
2217 plotOpts.SetPlotFrameRef( false );
2218 plotOpts.SetSvgFitPageToBoard( true );
2219 plotOpts.SetMirror( false );
2220 plotOpts.SetSkipPlotNPTH_Pads( false );
2221
2222 if( plotOpts.GetSketchPadsOnFabLayers() )
2223 {
2224 plotOpts.SetPlotPadNumbers( true );
2225 }
2226
2227 PCB_PLOTTER plotter( brd.get(), m_reporter, plotOpts );
2228
2229 if( !plotter.Plot( outputFile.GetFullPath(),
2230 aSvgJob->m_plotLayerSequence,
2232 false,
2233 true,
2234 wxEmptyString, wxEmptyString,
2235 wxEmptyString ) )
2236 {
2237 m_reporter->Report( _( "Error creating svg file" ) + wxS( "\n" ), RPT_SEVERITY_ERROR );
2239 }
2240
2241 return CLI::EXIT_CODES::OK;
2242}
2243
2244
2246{
2247 JOB_PCB_DRC* drcJob = dynamic_cast<JOB_PCB_DRC*>( aJob );
2248
2249 if( drcJob == nullptr )
2251
2252 BOARD* brd = getBoard( drcJob->m_filename );
2253
2254 if( !brd )
2256
2257 if( drcJob->GetConfiguredOutputPath().IsEmpty() )
2258 {
2259 wxFileName fn = brd->GetFileName();
2260 fn.SetName( fn.GetName() + wxS( "-drc" ) );
2261
2263 fn.SetExt( FILEEXT::JsonFileExtension );
2264 else
2265 fn.SetExt( FILEEXT::ReportFileExtension );
2266
2267 drcJob->SetWorkingOutputPath( fn.GetFullName() );
2268 }
2269
2270 wxString outPath = resolveJobOutputPath( aJob, brd );
2271
2272 if( !PATHS::EnsurePathExists( outPath, true ) )
2273 {
2274 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
2276 }
2277
2278 EDA_UNITS units;
2279
2280 switch( drcJob->m_units )
2281 {
2282 case JOB_PCB_DRC::UNITS::INCH: units = EDA_UNITS::INCH; break;
2283 case JOB_PCB_DRC::UNITS::MILS: units = EDA_UNITS::MILS; break;
2284 case JOB_PCB_DRC::UNITS::MM: units = EDA_UNITS::MM; break;
2285 default: units = EDA_UNITS::MM; break;
2286 }
2287
2288 std::shared_ptr<DRC_ENGINE> drcEngine = brd->GetDesignSettings().m_DRCEngine;
2289 std::unique_ptr<NETLIST> netlist = std::make_unique<NETLIST>();
2290
2291 drcEngine->SetDrawingSheet( getDrawingSheetProxyView( brd ) );
2292
2293 // BOARD_COMMIT uses TOOL_MANAGER to grab the board internally so we must give it one
2294 TOOL_MANAGER* toolManager = getToolManager( brd );
2295
2296 BOARD_COMMIT commit( toolManager );
2297 bool checkParity = drcJob->m_parity;
2298 std::string netlist_str;
2299
2300 if( checkParity )
2301 {
2302 wxString annotateMsg = _( "Schematic parity tests require a fully annotated schematic." );
2303 netlist_str = annotateMsg;
2304
2305 // The KIFACE_NETLIST_SCHEMATIC function has some broken-ness that the schematic
2306 // frame's version does not, but it is the only one that works in CLI, so we use it
2307 // if we don't have the sch frame open.
2308 // TODO: clean this up, see https://gitlab.com/kicad/code/kicad/-/issues/19929
2309 if( m_kiway->Player( FRAME_SCH, false ) )
2310 {
2311 m_kiway->ExpressMail( FRAME_SCH, MAIL_SCH_GET_NETLIST, netlist_str );
2312 }
2313 else
2314 {
2315 wxFileName schematicPath( drcJob->m_filename );
2316 schematicPath.SetExt( FILEEXT::KiCadSchematicFileExtension );
2317
2318 if( !schematicPath.Exists() )
2319 schematicPath.SetExt( FILEEXT::LegacySchematicFileExtension );
2320
2321 if( !schematicPath.Exists() )
2322 {
2323 m_reporter->Report( _( "Failed to fetch schematic netlist for parity tests.\n" ),
2325 checkParity = false;
2326 }
2327 else
2328 {
2329 typedef bool ( *NETLIST_FN_PTR )( const wxString&, std::string& );
2330 KIFACE* eeschema = m_kiway->KiFACE( KIWAY::FACE_SCH );
2331 NETLIST_FN_PTR netlister =
2332 (NETLIST_FN_PTR) eeschema->IfaceOrAddress( KIFACE_NETLIST_SCHEMATIC );
2333 ( *netlister )( schematicPath.GetFullPath(), netlist_str );
2334 }
2335 }
2336
2337 if( netlist_str == annotateMsg )
2338 {
2339 m_reporter->Report( wxString( netlist_str ) + wxT( "\n" ), RPT_SEVERITY_ERROR );
2340 checkParity = false;
2341 }
2342 }
2343
2344 if( checkParity )
2345 {
2346 try
2347 {
2348 STRING_LINE_READER* lineReader = new STRING_LINE_READER( netlist_str,
2349 _( "Eeschema netlist" ) );
2350 KICAD_NETLIST_READER netlistReader( lineReader, netlist.get() );
2351
2352 netlistReader.LoadNetlist();
2353 }
2354 catch( const IO_ERROR& )
2355 {
2356 m_reporter->Report( _( "Failed to fetch schematic netlist for parity tests.\n" ),
2358 checkParity = false;
2359 }
2360
2361 drcEngine->SetSchematicNetlist( netlist.get() );
2362 }
2363
2364 if( drcJob->m_refillZones )
2365 {
2366 if( !toolManager->FindTool( ZONE_FILLER_TOOL_NAME ) )
2367 toolManager->RegisterTool( new ZONE_FILLER_TOOL );
2368
2369 toolManager->GetTool<ZONE_FILLER_TOOL>()->FillAllZones( nullptr, m_progressReporter, true );
2370 }
2371
2372 drcEngine->SetProgressReporter( m_progressReporter );
2373 drcEngine->SetViolationHandler(
2374 [&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
2375 const std::function<void( PCB_MARKER* )>& aPathGenerator )
2376 {
2377 PCB_MARKER* marker = new PCB_MARKER( aItem, aPos, aLayer );
2378 aPathGenerator( marker );
2379 commit.Add( marker );
2380 } );
2381
2382 brd->RecordDRCExclusions();
2383 brd->DeleteMARKERs( true, true );
2384 drcEngine->RunTests( units, drcJob->m_reportAllTrackErrors, checkParity );
2385 drcEngine->ClearViolationHandler();
2386
2387 commit.Push( _( "DRC" ), SKIP_UNDO | SKIP_SET_DIRTY );
2388
2389 // Update the exclusion status on any excluded markers that still exist.
2390 brd->ResolveDRCExclusions( false );
2391
2392 std::shared_ptr<DRC_ITEMS_PROVIDER> markersProvider = std::make_shared<DRC_ITEMS_PROVIDER>(
2394
2395 std::shared_ptr<DRC_ITEMS_PROVIDER> ratsnestProvider =
2396 std::make_shared<DRC_ITEMS_PROVIDER>( brd, MARKER_BASE::MARKER_RATSNEST );
2397
2398 std::shared_ptr<DRC_ITEMS_PROVIDER> fpWarningsProvider =
2399 std::make_shared<DRC_ITEMS_PROVIDER>( brd, MARKER_BASE::MARKER_PARITY );
2400
2401 markersProvider->SetSeverities( drcJob->m_severity );
2402 ratsnestProvider->SetSeverities( drcJob->m_severity );
2403 fpWarningsProvider->SetSeverities( drcJob->m_severity );
2404
2405 m_reporter->Report( wxString::Format( _( "Found %d violations\n" ),
2406 markersProvider->GetCount() ),
2408 m_reporter->Report( wxString::Format( _( "Found %d unconnected items\n" ),
2409 ratsnestProvider->GetCount() ),
2411
2412 if( checkParity )
2413 {
2414 m_reporter->Report( wxString::Format( _( "Found %d schematic parity issues\n" ),
2415 fpWarningsProvider->GetCount() ),
2417 }
2418
2419 DRC_REPORT reportWriter( brd, units, markersProvider, ratsnestProvider, fpWarningsProvider );
2420
2421 bool wroteReport = false;
2422
2424 wroteReport = reportWriter.WriteJsonReport( outPath );
2425 else
2426 wroteReport = reportWriter.WriteTextReport( outPath );
2427
2428 if( !wroteReport )
2429 {
2430 m_reporter->Report( wxString::Format( _( "Unable to save DRC report to %s\n" ), outPath ),
2433 }
2434
2435 m_reporter->Report( wxString::Format( _( "Saved DRC Report to %s\n" ), outPath ),
2437
2438 if( drcJob->m_refillZones && drcJob->m_saveBoard )
2439 {
2440 if( SaveBoard( drcJob->m_filename, brd, true ) )
2441 {
2442 m_reporter->Report( _( "Saved board\n" ), RPT_SEVERITY_ACTION );
2443 }
2444 else
2445 {
2446 m_reporter->Report( _( "Failed to save board.\n" ), RPT_SEVERITY_ERROR );
2447
2449 }
2450 }
2451
2452 if( drcJob->m_exitCodeViolations )
2453 {
2454 if( markersProvider->GetCount() > 0 || ratsnestProvider->GetCount() > 0
2455 || fpWarningsProvider->GetCount() > 0 )
2456 {
2458 }
2459 }
2460
2462}
2463
2464
2466{
2467 JOB_EXPORT_PCB_IPC2581* job = dynamic_cast<JOB_EXPORT_PCB_IPC2581*>( aJob );
2468
2469 if( job == nullptr )
2471
2472 BOARD* brd = getBoard( job->m_filename );
2473
2474 if( !brd )
2476
2477 if( job->GetConfiguredOutputPath().IsEmpty() )
2478 {
2479 wxFileName fn = brd->GetFileName();
2480 fn.SetName( fn.GetName() );
2481 fn.SetExt( FILEEXT::Ipc2581FileExtension );
2482
2483 job->SetWorkingOutputPath( fn.GetName() );
2484 }
2485
2486 wxString outPath = resolveJobOutputPath( aJob, brd );
2487
2488 if( !PATHS::EnsurePathExists( outPath, true ) )
2489 {
2490 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
2492 }
2493
2494 std::map<std::string, UTF8> props;
2495 props["units"] = job->m_units == JOB_EXPORT_PCB_IPC2581::IPC2581_UNITS::MM ? "mm" : "inch";
2496 props["sigfig"] = wxString::Format( "%d", job->m_precision );
2497 props["version"] = job->m_version == JOB_EXPORT_PCB_IPC2581::IPC2581_VERSION::C ? "C" : "B";
2498 props["OEMRef"] = job->m_colInternalId;
2499 props["mpn"] = job->m_colMfgPn;
2500 props["mfg"] = job->m_colMfg;
2501 props["dist"] = job->m_colDist;
2502 props["distpn"] = job->m_colDistPn;
2503
2504 wxString tempFile = wxFileName::CreateTempFileName( wxS( "pcbnew_ipc" ) );
2505 try
2506 {
2508 pi->SetProgressReporter( m_progressReporter );
2509 pi->SaveBoard( tempFile, brd, &props );
2510 }
2511 catch( const IO_ERROR& ioe )
2512 {
2513 m_reporter->Report( wxString::Format( _( "Error generating IPC-2581 file '%s'.\n%s" ),
2514 job->m_filename,
2515 ioe.What() ),
2517
2518 wxRemoveFile( tempFile );
2519
2521 }
2522
2523 if( job->m_compress )
2524 {
2525 wxFileName tempfn = outPath;
2526 tempfn.SetExt( FILEEXT::Ipc2581FileExtension );
2527 wxFileName zipfn = tempFile;
2528 zipfn.SetExt( "zip" );
2529
2530 {
2531 wxFFileOutputStream fnout( zipfn.GetFullPath() );
2532
2533 // Use a large I/O buffer to improve compatibility with cloud-synced folders.
2534 // See KIPLATFORM::IO::CLOUD_SYNC_BUFFER_SIZE comment for details.
2535 if( FILE* fp = fnout.GetFile()->fp() )
2536 setvbuf( fp, nullptr, _IOFBF, KIPLATFORM::IO::CLOUD_SYNC_BUFFER_SIZE );
2537
2538 wxZipOutputStream zip( fnout );
2539 wxFFileInputStream fnin( tempFile );
2540
2541 zip.PutNextEntry( tempfn.GetFullName() );
2542 fnin.Read( zip );
2543 }
2544
2545 wxRemoveFile( tempFile );
2546 tempFile = zipfn.GetFullPath();
2547 }
2548
2549 // If save succeeded, replace the original with what we just wrote
2550 if( !wxRenameFile( tempFile, outPath ) )
2551 {
2552 m_reporter->Report( wxString::Format( _( "Error generating IPC-2581 file '%s'.\n"
2553 "Failed to rename temporary file '%s." ),
2554 outPath,
2555 tempFile ),
2557 }
2558
2560}
2561
2562
2564{
2565 JOB_EXPORT_PCB_IPCD356* job = dynamic_cast<JOB_EXPORT_PCB_IPCD356*>( aJob );
2566
2567 if( job == nullptr )
2569
2570 BOARD* brd = getBoard( job->m_filename );
2571
2572 if( !brd )
2574
2575 if( job->GetConfiguredOutputPath().IsEmpty() )
2576 {
2577 wxFileName fn = brd->GetFileName();
2578 fn.SetName( fn.GetName() );
2579 fn.SetExt( FILEEXT::IpcD356FileExtension );
2580
2581 job->SetWorkingOutputPath( fn.GetFullName() );
2582 }
2583
2584 wxString outPath = resolveJobOutputPath( aJob, brd );
2585
2586 if( !PATHS::EnsurePathExists( outPath, true ) )
2587 {
2588 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
2590 }
2591
2592 IPC356D_WRITER exporter( brd );
2593
2594 bool success = exporter.Write( outPath );
2595
2596 if( success )
2597 {
2598 m_reporter->Report( _( "Successfully created IPC-D-356 file\n" ), RPT_SEVERITY_INFO );
2600 }
2601 else
2602 {
2603 m_reporter->Report( _( "Failed to create IPC-D-356 file\n" ), RPT_SEVERITY_ERROR );
2605 }
2606}
2607
2608
2610{
2611 JOB_EXPORT_PCB_ODB* job = dynamic_cast<JOB_EXPORT_PCB_ODB*>( aJob );
2612
2613 if( job == nullptr )
2615
2616 BOARD* brd = getBoard( job->m_filename );
2617
2618 if( !brd )
2620
2621 if( job->GetConfiguredOutputPath().IsEmpty() )
2622 {
2624 {
2625 // just basic folder name
2626 job->SetWorkingOutputPath( "odb" );
2627 }
2628 else
2629 {
2630 wxFileName fn( brd->GetFileName() );
2631 fn.SetName( fn.GetName() + wxS( "-odb" ) );
2632
2633 switch( job->m_compressionMode )
2634 {
2636 fn.SetExt( FILEEXT::ArchiveFileExtension );
2637 break;
2638
2640 fn.SetExt( "tgz" );
2641 break;
2642
2643 default:
2644 break;
2645 };
2646
2647 job->SetWorkingOutputPath( fn.GetFullName() );
2648 }
2649 }
2650
2651 resolveJobOutputPath( job, brd );
2652
2653 // The helper handles output path creation, so hand it a job that already has fully-resolved
2654 // token context (title block and project overrides applied above).
2656
2658}
2659
2661{
2662 JOB_PCB_UPGRADE* job = dynamic_cast<JOB_PCB_UPGRADE*>( aJob );
2663
2664 if( job == nullptr )
2666
2667 bool shouldSave = job->m_force;
2668
2669 try
2670 {
2672 BOARD* brd = getBoard( job->m_filename );
2674 shouldSave = true;
2675
2676 if( shouldSave )
2677 {
2678 pi->SaveBoard( brd->GetFileName(), brd );
2679 m_reporter->Report( _( "Successfully saved board file using the latest format\n" ), RPT_SEVERITY_INFO );
2680 }
2681 else
2682 {
2683 m_reporter->Report( _( "Board file was not updated\n" ), RPT_SEVERITY_ERROR );
2684 }
2685 }
2686 catch( const IO_ERROR& ioe )
2687 {
2688 wxString msg =
2689 wxString::Format( _( "Error saving board file '%s'.\n%s" ), job->m_filename, ioe.What().GetData() );
2690 m_reporter->Report( msg, RPT_SEVERITY_ERROR );
2692 }
2693
2695}
2696
2697// Most job handlers need to align the running job with the board before resolving any
2698// output paths with variables in them like ${REVISION}.
2699wxString PCBNEW_JOBS_HANDLER::resolveJobOutputPath( JOB* aJob, BOARD* aBoard, const wxString* aDrawingSheet )
2700{
2701 aJob->SetTitleBlock( aBoard->GetTitleBlock() );
2702
2703 if( aDrawingSheet && !aDrawingSheet->IsEmpty() )
2704 loadOverrideDrawingSheet( aBoard, *aDrawingSheet );
2705
2706 PROJECT* project = aBoard->GetProject();
2707
2708 if( project )
2709 project->ApplyTextVars( aJob->GetVarOverrides() );
2710
2711 aBoard->SynchronizeProperties();
2712
2713 return aJob->GetFullOutputPath( project );
2714}
2715
2716
2718{
2720 &aBrd->GetPageSettings(),
2721 aBrd->GetProject(),
2722 &aBrd->GetTitleBlock(),
2723 &aBrd->GetProperties() );
2724
2725 drawingSheet->SetSheetName( std::string() );
2726 drawingSheet->SetSheetPath( std::string() );
2727 drawingSheet->SetIsFirstPage( true );
2728
2729 drawingSheet->SetFileName( TO_UTF8( aBrd->GetFileName() ) );
2730
2731 return drawingSheet;
2732}
2733
2734
2735void PCBNEW_JOBS_HANDLER::loadOverrideDrawingSheet( BOARD* aBrd, const wxString& aSheetPath )
2736{
2737 // dont bother attempting to load a empty path, if there was one
2738 if( aSheetPath.IsEmpty() )
2739 return;
2740
2741 auto loadSheet =
2742 [&]( const wxString& path ) -> bool
2743 {
2746 resolver.SetProject( aBrd->GetProject() );
2747 resolver.SetProgramBase( &Pgm() );
2748
2749 wxString filename = resolver.ResolvePath( BASE_SCREEN::m_DrawingSheetFileName,
2750 aBrd->GetProject()->GetProjectPath(),
2751 { aBrd->GetEmbeddedFiles() } );
2752 wxString msg;
2753
2754 if( !DS_DATA_MODEL::GetTheInstance().LoadDrawingSheet( filename, &msg ) )
2755 {
2756 m_reporter->Report( wxString::Format( _( "Error loading drawing sheet '%s'." ),
2757 path )
2758 + wxS( "\n" ) + msg + wxS( "\n" ),
2760 return false;
2761 }
2762
2763 return true;
2764 };
2765
2766 if( loadSheet( aSheetPath ) )
2767 return;
2768
2769 // failed loading custom path, revert back to default
2770 loadSheet( aBrd->GetProject()->GetProjectFile().m_BoardDrawingSheetFile );
2771}
@ 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 SetVisibleLayers(const std::bitset< LAYER_3D_END > &aLayers)
std::bitset< LAYER_3D_END > GetVisibleLayers() const
void SetBoard(BOARD *aBoard) noexcept
Set current board to be rendered.
void SetLayerColors(const std::map< int, COLOR4D > &aColors)
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:799
void RecordDRCExclusions()
Scan existing markers and record data from any that are Excluded.
Definition board.cpp:331
TITLE_BLOCK & GetTitleBlock()
Definition board.h:805
BOX2I ComputeBoundingBox(bool aBoardEdgesOnly=false) const
Calculate the bounding box containing all board items (or board edge segments).
Definition board.cpp:2111
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:388
int GetFileFormatVersionAtLoad() const
Definition board.h:456
const PCB_PLOT_PARAMS & GetPlotOptions() const
Definition board.h:802
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition board.cpp:730
PROJECT * GetProject() const
Definition board.h:579
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1084
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition board.cpp:969
void SynchronizeProperties()
Copy the current project's text variables into the boards property cache.
Definition board.cpp:2486
void DeleteMARKERs()
Delete all MARKERS from the board.
Definition board.cpp:1720
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.
LAYER_PRESET_3D * FindPreset(const wxString &aName)
std::vector< LAYER_PRESET_3D > m_LayerPresets
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:147
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:1076
void SetOrientation(const EDA_ANGLE &aNewAngle)
EDA_ITEM * Clone() const override
Invoke a function on all children.
std::deque< PAD * > & Pads()
Definition footprint.h:306
const LIB_ID & GetFPID() const
Definition footprint.h:351
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.
bool GenDrillReportFile(const wxString &aFullFileName, REPORTER *aReporter=nullptr)
Create a plain text report file giving a list of drill values and drill count for through holes,...
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.
bool m_pdfSingle
This is a hack to deal with cli having the wrong behavior We will deprecate out the wrong behavior,...
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.
wxString m_variant
Variant name for variant-aware filtering.
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
wxString ResolveOutputPath(const wxString &aPath, bool aPathIsDirectory, PROJECT *aProject) const
Definition job.cpp:100
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:150
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:105
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition kiway.h:295
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition kiway.cpp:407
@ FACE_SCH
eeschema DSO
Definition kiway.h:302
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:743
LSEQ SeqStackupForPlotting() const
Return the sequence that is typical for a bottom-to-top stack-up.
Definition lset.cpp:404
static LSET AllNonCuMask()
Return a mask holding all layer minus CU layers.
Definition lset.cpp:627
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:599
static const LSET & AllLayersMask()
Definition lset.cpp:641
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:608
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:577
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:55
static bool EnsurePathExists(const wxString &aPath, bool aPathToFile=false)
Attempts to create a given path if it does not exist.
Definition paths.cpp:508
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 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_IO * FindPlugin(PCB_FILE_T aFileType)
Return a #PLUGIN which the caller can use to import, export, save, or load design documents.
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
void SetSvgFitPageToBoard(int aSvgFitPageToBoard)
bool GetUseGerberProtelExtensions() const
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:132
Used to create Gerber drill files.
const wxString GetPlaceFileName(const wxString &aFullBaseFilename, PCB_LAYER_ID aLayer) const
void SetVariant(const wxString &aVariant)
Set the variant name for variant-aware filtering.
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
void SetVariant(const wxString &aVariant)
Set the variant name for variant-aware DNP filtering.
Base plotter engine class.
Definition plotter.h:136
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:165
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition project.cpp:171
virtual const wxString GetProjectName() const
Return the short name of the project.
Definition project.cpp:183
virtual PROJECT_FILE & GetProjectFile() const
Definition project.h:203
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:226
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:202
This file is part of the common library.
static DRILL_PRECISION precisionListForInches(2, 4)
static DRILL_PRECISION precisionListForMetric(3, 3)
#define _(s)
#define FOLLOW_PLOT_SETTINGS
#define FOLLOW_PCB
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:42
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:553
@ LAYER_3D_BACKGROUND_BOTTOM
Definition layer_ids.h:552
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
static constexpr size_t CLOUD_SYNC_BUFFER_SIZE
Buffer size for file I/O operations on cloud-synced folders.
Definition io.h:41
#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.
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:156
std::string path
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