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