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 switch( aDrillJob->m_zeroFormat )
1703 {
1706 break;
1709 break;
1712 break;
1714 default:
1716 break;
1717 }
1718
1719 DRILL_PRECISION precision;
1720
1722 precision = precisionListForInches;
1723 else
1724 precision = precisionListForMetric;
1725
1726 EXCELLON_WRITER* excellonWriter = dynamic_cast<EXCELLON_WRITER*>( drillWriter.get() );
1727
1728 if( excellonWriter == nullptr )
1730
1731 excellonWriter->SetFormat( aDrillJob->m_drillUnits == JOB_EXPORT_PCB_DRILL::DRILL_UNITS::MM,
1732 zeroFmt, precision.m_Lhs, precision.m_Rhs );
1733 excellonWriter->SetOptions( aDrillJob->m_excellonMirrorY,
1734 aDrillJob->m_excellonMinimalHeader,
1735 offset, aDrillJob->m_excellonCombinePTHNPTH );
1736 excellonWriter->SetRouteModeForOvalHoles( aDrillJob->m_excellonOvalDrillRoute );
1737 excellonWriter->SetMapFileFormat( mapFormat );
1738
1739 if( !excellonWriter->CreateDrillandMapFilesSet( outPath, true, aDrillJob->m_generateMap,
1740 m_reporter ) )
1741 {
1743 }
1744
1745 if( aDrillJob->m_generateReport )
1746 {
1747 wxString reportPath = aDrillJob->ResolveOutputPath( aDrillJob->m_reportPath, true, brd->GetProject() );
1748
1749 if( !excellonWriter->GenDrillReportFile( reportPath ) )
1750 {
1752 }
1753 }
1754 }
1756 {
1757 GERBER_WRITER* gerberWriter = dynamic_cast<GERBER_WRITER*>( drillWriter.get() );
1758
1759 if( gerberWriter == nullptr )
1761
1762 // Set gerber precision: only 5 or 6 digits for mantissa are allowed
1763 // (SetFormat() accept 5 or 6, and any other value set the precision to 5)
1764 // the integer part precision is always 4, and units always mm
1765 gerberWriter->SetFormat( aDrillJob->m_gerberPrecision );
1766 gerberWriter->SetOptions( offset );
1767 gerberWriter->SetMapFileFormat( mapFormat );
1768
1769 if( !gerberWriter->CreateDrillandMapFilesSet( outPath, true, aDrillJob->m_generateMap,
1770 aDrillJob->m_generateTenting, m_reporter ) )
1771 {
1773 }
1774
1775 if( aDrillJob->m_generateReport )
1776 {
1777 wxString reportPath = aDrillJob->ResolveOutputPath( aDrillJob->m_reportPath, true, brd->GetProject() );
1778
1779 if( !gerberWriter->GenDrillReportFile( reportPath ) )
1780 {
1782 }
1783 }
1784 }
1785
1786 return CLI::EXIT_CODES::OK;
1787}
1788
1789
1791{
1792 JOB_EXPORT_PCB_POS* aPosJob = dynamic_cast<JOB_EXPORT_PCB_POS*>( aJob );
1793
1794 if( aPosJob == nullptr )
1796
1797 BOARD* brd = getBoard( aPosJob->m_filename );
1798
1799 if( !brd )
1801
1802 if( aPosJob->GetConfiguredOutputPath().IsEmpty() )
1803 {
1804 wxFileName fn = brd->GetFileName();
1805 fn.SetName( fn.GetName() );
1806
1809 else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::CSV )
1810 fn.SetExt( FILEEXT::CsvFileExtension );
1811 else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::GERBER )
1812 fn.SetExt( FILEEXT::GerberFileExtension );
1813
1814 aPosJob->SetWorkingOutputPath( fn.GetFullName() );
1815 }
1816
1817 wxString outPath = resolveJobOutputPath( aJob, brd );
1818
1819 if( !PATHS::EnsurePathExists( outPath, true ) )
1820 {
1821 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1823 }
1824
1827 {
1828 wxFileName fn( outPath );
1829 wxString baseName = fn.GetName();
1830
1831 auto exportPlaceFile =
1832 [&]( bool frontSide, bool backSide, const wxString& curr_outPath ) -> bool
1833 {
1834 FILE* file = wxFopen( curr_outPath, wxS( "wt" ) );
1835 wxCHECK( file, false );
1836
1837 PLACE_FILE_EXPORTER exporter( brd,
1839 aPosJob->m_smdOnly,
1841 aPosJob->m_excludeDNP,
1842 aPosJob->m_excludeBOM,
1843 frontSide,
1844 backSide,
1847 aPosJob->m_negateBottomX );
1848
1849 std::string data = exporter.GenPositionData();
1850 fputs( data.c_str(), file );
1851 fclose( file );
1852
1853 return true;
1854 };
1855
1856 if( aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH && !aPosJob->m_singleFile )
1857 {
1858 fn.SetName( PLACE_FILE_EXPORTER::DecorateFilename( baseName, true, false ) );
1859
1860 if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::CSV && !aPosJob->m_nakedFilename )
1861 fn.SetName( fn.GetName() + wxT( "-" ) + FILEEXT::FootprintPlaceFileExtension );
1862
1863 if( exportPlaceFile( true, false, fn.GetFullPath() ) )
1864 {
1865 m_reporter->Report( wxString::Format( _( "Wrote front position data to '%s'.\n" ),
1866 fn.GetFullPath() ),
1868
1869 aPosJob->AddOutput( fn.GetFullPath() );
1870 }
1871 else
1872 {
1874 }
1875
1876 fn.SetName( PLACE_FILE_EXPORTER::DecorateFilename( baseName, false, true ) );
1877
1878 if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::CSV && !aPosJob->m_nakedFilename )
1879 fn.SetName( fn.GetName() + wxT( "-" ) + FILEEXT::FootprintPlaceFileExtension );
1880
1881 if( exportPlaceFile( false, true, fn.GetFullPath() ) )
1882 {
1883 m_reporter->Report( wxString::Format( _( "Wrote back position data to '%s'.\n" ),
1884 fn.GetFullPath() ),
1886
1887 aPosJob->AddOutput( fn.GetFullPath() );
1888 }
1889 else
1890 {
1892 }
1893 }
1894 else
1895 {
1896 bool front = aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::FRONT
1898
1899 bool back = aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BACK
1901
1902 if( !aPosJob->m_nakedFilename )
1903 {
1904 fn.SetName( PLACE_FILE_EXPORTER::DecorateFilename( fn.GetName(), front, back ) );
1905
1907 fn.SetName( fn.GetName() + wxT( "-" ) + FILEEXT::FootprintPlaceFileExtension );
1908 }
1909
1910 if( exportPlaceFile( front, back, fn.GetFullPath() ) )
1911 {
1912 m_reporter->Report( wxString::Format( _( "Wrote position data to '%s'.\n" ),
1913 fn.GetFullPath() ),
1915
1916 aPosJob->AddOutput( fn.GetFullPath() );
1917 }
1918 else
1919 {
1921 }
1922 }
1923 }
1924 else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::GERBER )
1925 {
1926 PLACEFILE_GERBER_WRITER exporter( brd );
1927 PCB_LAYER_ID gbrLayer = F_Cu;
1928 wxString outPath_base = outPath;
1929
1931 || aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH )
1932 {
1933 if( aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH || !aPosJob->m_nakedFilename )
1934 outPath = exporter.GetPlaceFileName( outPath, gbrLayer );
1935
1936 if( exporter.CreatePlaceFile( outPath, gbrLayer, aPosJob->m_gerberBoardEdge,
1937 aPosJob->m_excludeDNP, aPosJob->m_excludeBOM ) >= 0 )
1938 {
1939 m_reporter->Report( wxString::Format( _( "Wrote front position data to '%s'.\n" ), outPath ),
1941
1942 aPosJob->AddOutput( outPath );
1943 }
1944 else
1945 {
1947 }
1948 }
1949
1951 || aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH )
1952 {
1953 gbrLayer = B_Cu;
1954
1955 outPath = outPath_base;
1956
1957 if( aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH || !aPosJob->m_nakedFilename )
1958 outPath = exporter.GetPlaceFileName( outPath, gbrLayer );
1959
1960 if( exporter.CreatePlaceFile( outPath, gbrLayer, aPosJob->m_gerberBoardEdge,
1961 aPosJob->m_excludeDNP, aPosJob->m_excludeBOM ) >= 0 )
1962 {
1963 m_reporter->Report( wxString::Format( _( "Wrote back position data to '%s'.\n" ), outPath ),
1965
1966 aPosJob->AddOutput( outPath );
1967 }
1968 else
1969 {
1971 }
1972 }
1973 }
1974
1975 return CLI::EXIT_CODES::OK;
1976}
1977
1978
1980{
1981 JOB_FP_UPGRADE* upgradeJob = dynamic_cast<JOB_FP_UPGRADE*>( aJob );
1982
1983 if( upgradeJob == nullptr )
1985
1987
1988 if( !upgradeJob->m_outputLibraryPath.IsEmpty() )
1989 {
1990 if( wxFile::Exists( upgradeJob->m_outputLibraryPath )
1991 || wxDir::Exists( upgradeJob->m_outputLibraryPath) )
1992 {
1993 m_reporter->Report( _( "Output path must not conflict with existing path\n" ),
1996 }
1997 }
1998 else if( fileType != PCB_IO_MGR::KICAD_SEXP )
1999 {
2000 m_reporter->Report( _( "Output path must be specified to convert legacy and non-KiCad libraries\n" ),
2002
2004 }
2005
2007 {
2008 if( !wxDir::Exists( upgradeJob->m_libraryPath ) )
2009 {
2010 m_reporter->Report( _( "Footprint library path does not exist or is not accessible\n" ),
2013 }
2014
2016 FP_CACHE fpLib( &pcb_io, upgradeJob->m_libraryPath );
2017
2018 try
2019 {
2020 fpLib.Load();
2021 }
2022 catch( ... )
2023 {
2024 m_reporter->Report( _( "Unable to load library\n" ), RPT_SEVERITY_ERROR );
2026 }
2027
2028 if( m_progressReporter )
2029 m_progressReporter->KeepRefreshing();
2030
2031 bool shouldSave = upgradeJob->m_force;
2032
2033 for( const auto& footprint : fpLib.GetFootprints() )
2034 {
2035 if( footprint.second->GetFootprint()->GetFileFormatVersionAtLoad() < SEXPR_BOARD_FILE_VERSION )
2036 shouldSave = true;
2037 }
2038
2039 if( shouldSave )
2040 {
2041 try
2042 {
2043 if( !upgradeJob->m_outputLibraryPath.IsEmpty() )
2044 fpLib.SetPath( upgradeJob->m_outputLibraryPath );
2045
2046 fpLib.Save();
2047 }
2048 catch( ... )
2049 {
2050 m_reporter->Report( _( "Unable to save library\n" ), RPT_SEVERITY_ERROR );
2052 }
2053 }
2054 else
2055 {
2056 m_reporter->Report( _( "Footprint library was not updated\n" ), RPT_SEVERITY_ERROR );
2057 }
2058 }
2059 else
2060 {
2061 if( !PCB_IO_MGR::ConvertLibrary( {}, upgradeJob->m_libraryPath,
2062 upgradeJob->m_outputLibraryPath, nullptr /* REPORTER */ ) )
2063 {
2064 m_reporter->Report( ( "Unable to convert library\n" ), RPT_SEVERITY_ERROR );
2066 }
2067 }
2068
2069 return CLI::EXIT_CODES::OK;
2070}
2071
2072
2074{
2075 JOB_FP_EXPORT_SVG* svgJob = dynamic_cast<JOB_FP_EXPORT_SVG*>( aJob );
2076
2077 if( svgJob == nullptr )
2079
2081 FP_CACHE fpLib( &pcb_io, svgJob->m_libraryPath );
2082
2083 if( svgJob->m_argLayers )
2084 {
2085 if( !svgJob->m_argLayers.value().empty() )
2086 svgJob->m_plotLayerSequence = convertLayerArg( svgJob->m_argLayers.value(), nullptr );
2087 else
2089 }
2090
2091 try
2092 {
2093 fpLib.Load();
2094 }
2095 catch( ... )
2096 {
2097 m_reporter->Report( _( "Unable to load library\n" ), RPT_SEVERITY_ERROR );
2099 }
2100
2101 wxString outPath = svgJob->GetFullOutputPath( nullptr );
2102
2103 if( !PATHS::EnsurePathExists( outPath, true ) )
2104 {
2105 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
2107 }
2108
2109 int exitCode = CLI::EXIT_CODES::OK;
2110 bool singleFpPlotted = false;
2111
2112 for( const auto& [fpName, fpCacheEntry] : fpLib.GetFootprints() )
2113 {
2114 if( m_progressReporter )
2115 {
2116 m_progressReporter->AdvancePhase( wxString::Format( _( "Exporting %s" ), fpName ) );
2117 m_progressReporter->KeepRefreshing();
2118 }
2119
2120 if( !svgJob->m_footprint.IsEmpty() )
2121 {
2122 // skip until we find the right footprint
2123 if( fpName != svgJob->m_footprint )
2124 continue;
2125 else
2126 singleFpPlotted = true;
2127 }
2128
2129 exitCode = doFpExportSvg( svgJob, fpCacheEntry->GetFootprint().get() );
2130
2131 if( exitCode != CLI::EXIT_CODES::OK )
2132 break;
2133 }
2134
2135 if( !svgJob->m_footprint.IsEmpty() && !singleFpPlotted )
2136 {
2137 m_reporter->Report( _( "The given footprint could not be found to export." ) + wxS( "\n" ),
2139 }
2140
2141 return CLI::EXIT_CODES::OK;
2142}
2143
2144
2146{
2147 // the hack for now is we create fake boards containing the footprint and plot the board
2148 // until we refactor better plot api later
2149 std::unique_ptr<BOARD> brd;
2150 brd.reset( CreateEmptyBoard() );
2151 brd->GetProject()->ApplyTextVars( aSvgJob->GetVarOverrides() );
2152 brd->SynchronizeProperties();
2153
2154 FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( aFootprint->Clone() );
2155
2156 if( fp == nullptr )
2158
2159 fp->SetLink( niluuid );
2160 fp->SetFlags( IS_NEW );
2161 fp->SetParent( brd.get() );
2162
2163 for( PAD* pad : fp->Pads() )
2164 {
2165 pad->SetLocalRatsnestVisible( false );
2166 pad->SetNetCode( 0 );
2167 }
2168
2169 fp->SetOrientation( ANGLE_0 );
2170 fp->SetPosition( VECTOR2I( 0, 0 ) );
2171
2172 brd->Add( fp, ADD_MODE::INSERT, true );
2173
2174 wxFileName outputFile;
2175 outputFile.SetPath( aSvgJob->GetFullOutputPath(nullptr) );
2176 outputFile.SetName( aFootprint->GetFPID().GetLibItemName().wx_str() );
2177 outputFile.SetExt( FILEEXT::SVGFileExtension );
2178
2179 m_reporter->Report( wxString::Format( _( "Plotting footprint '%s' to '%s'\n" ),
2180 aFootprint->GetFPID().GetLibItemName().wx_str(),
2181 outputFile.GetFullPath() ),
2183
2184 PCB_PLOT_PARAMS plotOpts;
2185 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, aSvgJob, *m_reporter );
2186
2187 // always fixed for the svg plot
2188 plotOpts.SetPlotFrameRef( false );
2189 plotOpts.SetSvgFitPageToBoard( true );
2190 plotOpts.SetMirror( false );
2191 plotOpts.SetSkipPlotNPTH_Pads( false );
2192
2193 if( plotOpts.GetSketchPadsOnFabLayers() )
2194 {
2195 plotOpts.SetPlotPadNumbers( true );
2196 }
2197
2198 PCB_PLOTTER plotter( brd.get(), m_reporter, plotOpts );
2199
2200 if( !plotter.Plot( outputFile.GetFullPath(),
2201 aSvgJob->m_plotLayerSequence,
2203 false,
2204 true,
2205 wxEmptyString, wxEmptyString,
2206 wxEmptyString ) )
2207 {
2208 m_reporter->Report( _( "Error creating svg file" ) + wxS( "\n" ), RPT_SEVERITY_ERROR );
2210 }
2211
2212 return CLI::EXIT_CODES::OK;
2213}
2214
2215
2217{
2218 JOB_PCB_DRC* drcJob = dynamic_cast<JOB_PCB_DRC*>( aJob );
2219
2220 if( drcJob == nullptr )
2222
2223 BOARD* brd = getBoard( drcJob->m_filename );
2224
2225 if( !brd )
2227
2228 if( drcJob->GetConfiguredOutputPath().IsEmpty() )
2229 {
2230 wxFileName fn = brd->GetFileName();
2231 fn.SetName( fn.GetName() + wxS( "-drc" ) );
2232
2234 fn.SetExt( FILEEXT::JsonFileExtension );
2235 else
2236 fn.SetExt( FILEEXT::ReportFileExtension );
2237
2238 drcJob->SetWorkingOutputPath( fn.GetFullName() );
2239 }
2240
2241 wxString outPath = resolveJobOutputPath( aJob, brd );
2242
2243 if( !PATHS::EnsurePathExists( outPath, true ) )
2244 {
2245 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
2247 }
2248
2249 EDA_UNITS units;
2250
2251 switch( drcJob->m_units )
2252 {
2253 case JOB_PCB_DRC::UNITS::INCH: units = EDA_UNITS::INCH; break;
2254 case JOB_PCB_DRC::UNITS::MILS: units = EDA_UNITS::MILS; break;
2255 case JOB_PCB_DRC::UNITS::MM: units = EDA_UNITS::MM; break;
2256 default: units = EDA_UNITS::MM; break;
2257 }
2258
2259 std::shared_ptr<DRC_ENGINE> drcEngine = brd->GetDesignSettings().m_DRCEngine;
2260 std::unique_ptr<NETLIST> netlist = std::make_unique<NETLIST>();
2261
2262 drcEngine->SetDrawingSheet( getDrawingSheetProxyView( brd ) );
2263
2264 // BOARD_COMMIT uses TOOL_MANAGER to grab the board internally so we must give it one
2265 TOOL_MANAGER* toolManager = getToolManager( brd );
2266
2267 BOARD_COMMIT commit( toolManager );
2268 bool checkParity = drcJob->m_parity;
2269 std::string netlist_str;
2270
2271 if( checkParity )
2272 {
2273 wxString annotateMsg = _( "Schematic parity tests require a fully annotated schematic." );
2274 netlist_str = annotateMsg;
2275
2276 // The KIFACE_NETLIST_SCHEMATIC function has some broken-ness that the schematic
2277 // frame's version does not, but it is the only one that works in CLI, so we use it
2278 // if we don't have the sch frame open.
2279 // TODO: clean this up, see https://gitlab.com/kicad/code/kicad/-/issues/19929
2280 if( m_kiway->Player( FRAME_SCH, false ) )
2281 {
2282 m_kiway->ExpressMail( FRAME_SCH, MAIL_SCH_GET_NETLIST, netlist_str );
2283 }
2284 else
2285 {
2286 wxFileName schematicPath( drcJob->m_filename );
2287 schematicPath.SetExt( FILEEXT::KiCadSchematicFileExtension );
2288
2289 if( !schematicPath.Exists() )
2290 schematicPath.SetExt( FILEEXT::LegacySchematicFileExtension );
2291
2292 if( !schematicPath.Exists() )
2293 {
2294 m_reporter->Report( _( "Failed to fetch schematic netlist for parity tests.\n" ),
2296 checkParity = false;
2297 }
2298 else
2299 {
2300 typedef bool ( *NETLIST_FN_PTR )( const wxString&, std::string& );
2301 KIFACE* eeschema = m_kiway->KiFACE( KIWAY::FACE_SCH );
2302 NETLIST_FN_PTR netlister =
2303 (NETLIST_FN_PTR) eeschema->IfaceOrAddress( KIFACE_NETLIST_SCHEMATIC );
2304 ( *netlister )( schematicPath.GetFullPath(), netlist_str );
2305 }
2306 }
2307
2308 if( netlist_str == annotateMsg )
2309 {
2310 m_reporter->Report( wxString( netlist_str ) + wxT( "\n" ), RPT_SEVERITY_ERROR );
2311 checkParity = false;
2312 }
2313 }
2314
2315 if( checkParity )
2316 {
2317 try
2318 {
2319 STRING_LINE_READER* lineReader = new STRING_LINE_READER( netlist_str,
2320 _( "Eeschema netlist" ) );
2321 KICAD_NETLIST_READER netlistReader( lineReader, netlist.get() );
2322
2323 netlistReader.LoadNetlist();
2324 }
2325 catch( const IO_ERROR& )
2326 {
2327 m_reporter->Report( _( "Failed to fetch schematic netlist for parity tests.\n" ),
2329 checkParity = false;
2330 }
2331
2332 drcEngine->SetSchematicNetlist( netlist.get() );
2333 }
2334
2335 if( drcJob->m_refillZones )
2336 {
2337 if( !toolManager->FindTool( ZONE_FILLER_TOOL_NAME ) )
2338 toolManager->RegisterTool( new ZONE_FILLER_TOOL );
2339
2340 toolManager->GetTool<ZONE_FILLER_TOOL>()->FillAllZones( nullptr, m_progressReporter, true );
2341 }
2342
2343 drcEngine->SetProgressReporter( m_progressReporter );
2344 drcEngine->SetViolationHandler(
2345 [&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
2346 const std::function<void( PCB_MARKER* )>& aPathGenerator )
2347 {
2348 PCB_MARKER* marker = new PCB_MARKER( aItem, aPos, aLayer );
2349 aPathGenerator( marker );
2350 commit.Add( marker );
2351 } );
2352
2353 brd->RecordDRCExclusions();
2354 brd->DeleteMARKERs( true, true );
2355 drcEngine->RunTests( units, drcJob->m_reportAllTrackErrors, checkParity );
2356 drcEngine->ClearViolationHandler();
2357
2358 commit.Push( _( "DRC" ), SKIP_UNDO | SKIP_SET_DIRTY );
2359
2360 // Update the exclusion status on any excluded markers that still exist.
2361 brd->ResolveDRCExclusions( false );
2362
2363 std::shared_ptr<DRC_ITEMS_PROVIDER> markersProvider = std::make_shared<DRC_ITEMS_PROVIDER>(
2365
2366 std::shared_ptr<DRC_ITEMS_PROVIDER> ratsnestProvider =
2367 std::make_shared<DRC_ITEMS_PROVIDER>( brd, MARKER_BASE::MARKER_RATSNEST );
2368
2369 std::shared_ptr<DRC_ITEMS_PROVIDER> fpWarningsProvider =
2370 std::make_shared<DRC_ITEMS_PROVIDER>( brd, MARKER_BASE::MARKER_PARITY );
2371
2372 markersProvider->SetSeverities( drcJob->m_severity );
2373 ratsnestProvider->SetSeverities( drcJob->m_severity );
2374 fpWarningsProvider->SetSeverities( drcJob->m_severity );
2375
2376 m_reporter->Report( wxString::Format( _( "Found %d violations\n" ),
2377 markersProvider->GetCount() ),
2379 m_reporter->Report( wxString::Format( _( "Found %d unconnected items\n" ),
2380 ratsnestProvider->GetCount() ),
2382
2383 if( checkParity )
2384 {
2385 m_reporter->Report( wxString::Format( _( "Found %d schematic parity issues\n" ),
2386 fpWarningsProvider->GetCount() ),
2388 }
2389
2390 DRC_REPORT reportWriter( brd, units, markersProvider, ratsnestProvider, fpWarningsProvider );
2391
2392 bool wroteReport = false;
2393
2395 wroteReport = reportWriter.WriteJsonReport( outPath );
2396 else
2397 wroteReport = reportWriter.WriteTextReport( outPath );
2398
2399 if( !wroteReport )
2400 {
2401 m_reporter->Report( wxString::Format( _( "Unable to save DRC report to %s\n" ), outPath ),
2404 }
2405
2406 m_reporter->Report( wxString::Format( _( "Saved DRC Report to %s\n" ), outPath ),
2408
2409 if( drcJob->m_refillZones && drcJob->m_saveBoard )
2410 {
2411 if( SaveBoard( drcJob->m_filename, brd, true ) )
2412 {
2413 m_reporter->Report( _( "Saved board\n" ), RPT_SEVERITY_ACTION );
2414 }
2415 else
2416 {
2417 m_reporter->Report( _( "Failed to save board.\n" ), RPT_SEVERITY_ERROR );
2418
2420 }
2421 }
2422
2423 if( drcJob->m_exitCodeViolations )
2424 {
2425 if( markersProvider->GetCount() > 0 || ratsnestProvider->GetCount() > 0
2426 || fpWarningsProvider->GetCount() > 0 )
2427 {
2429 }
2430 }
2431
2433}
2434
2435
2437{
2438 JOB_EXPORT_PCB_IPC2581* job = dynamic_cast<JOB_EXPORT_PCB_IPC2581*>( aJob );
2439
2440 if( job == nullptr )
2442
2443 BOARD* brd = getBoard( job->m_filename );
2444
2445 if( !brd )
2447
2448 if( job->GetConfiguredOutputPath().IsEmpty() )
2449 {
2450 wxFileName fn = brd->GetFileName();
2451 fn.SetName( fn.GetName() );
2452 fn.SetExt( FILEEXT::Ipc2581FileExtension );
2453
2454 job->SetWorkingOutputPath( fn.GetName() );
2455 }
2456
2457 wxString outPath = resolveJobOutputPath( aJob, brd );
2458
2459 if( !PATHS::EnsurePathExists( outPath, true ) )
2460 {
2461 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
2463 }
2464
2465 std::map<std::string, UTF8> props;
2466 props["units"] = job->m_units == JOB_EXPORT_PCB_IPC2581::IPC2581_UNITS::MM ? "mm" : "inch";
2467 props["sigfig"] = wxString::Format( "%d", job->m_precision );
2468 props["version"] = job->m_version == JOB_EXPORT_PCB_IPC2581::IPC2581_VERSION::C ? "C" : "B";
2469 props["OEMRef"] = job->m_colInternalId;
2470 props["mpn"] = job->m_colMfgPn;
2471 props["mfg"] = job->m_colMfg;
2472 props["dist"] = job->m_colDist;
2473 props["distpn"] = job->m_colDistPn;
2474
2475 wxString tempFile = wxFileName::CreateTempFileName( wxS( "pcbnew_ipc" ) );
2476 try
2477 {
2479 pi->SetProgressReporter( m_progressReporter );
2480 pi->SaveBoard( tempFile, brd, &props );
2481 }
2482 catch( const IO_ERROR& ioe )
2483 {
2484 m_reporter->Report( wxString::Format( _( "Error generating IPC-2581 file '%s'.\n%s" ),
2485 job->m_filename,
2486 ioe.What() ),
2488
2489 wxRemoveFile( tempFile );
2490
2492 }
2493
2494 if( job->m_compress )
2495 {
2496 wxFileName tempfn = outPath;
2497 tempfn.SetExt( FILEEXT::Ipc2581FileExtension );
2498 wxFileName zipfn = tempFile;
2499 zipfn.SetExt( "zip" );
2500
2501 {
2502 wxFFileOutputStream fnout( zipfn.GetFullPath() );
2503 wxZipOutputStream zip( fnout );
2504 wxFFileInputStream fnin( tempFile );
2505
2506 zip.PutNextEntry( tempfn.GetFullName() );
2507 fnin.Read( zip );
2508 }
2509
2510 wxRemoveFile( tempFile );
2511 tempFile = zipfn.GetFullPath();
2512 }
2513
2514 // If save succeeded, replace the original with what we just wrote
2515 if( !wxRenameFile( tempFile, outPath ) )
2516 {
2517 m_reporter->Report( wxString::Format( _( "Error generating IPC-2581 file '%s'.\n"
2518 "Failed to rename temporary file '%s." ),
2519 outPath,
2520 tempFile ),
2522 }
2523
2525}
2526
2527
2529{
2530 JOB_EXPORT_PCB_IPCD356* job = dynamic_cast<JOB_EXPORT_PCB_IPCD356*>( aJob );
2531
2532 if( job == nullptr )
2534
2535 BOARD* brd = getBoard( job->m_filename );
2536
2537 if( !brd )
2539
2540 if( job->GetConfiguredOutputPath().IsEmpty() )
2541 {
2542 wxFileName fn = brd->GetFileName();
2543 fn.SetName( fn.GetName() );
2544 fn.SetExt( FILEEXT::IpcD356FileExtension );
2545
2546 job->SetWorkingOutputPath( fn.GetFullName() );
2547 }
2548
2549 wxString outPath = resolveJobOutputPath( aJob, brd );
2550
2551 if( !PATHS::EnsurePathExists( outPath, true ) )
2552 {
2553 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
2555 }
2556
2557 IPC356D_WRITER exporter( brd );
2558
2559 bool success = exporter.Write( outPath );
2560
2561 if( success )
2562 {
2563 m_reporter->Report( _( "Successfully created IPC-D-356 file\n" ), RPT_SEVERITY_INFO );
2565 }
2566 else
2567 {
2568 m_reporter->Report( _( "Failed to create IPC-D-356 file\n" ), RPT_SEVERITY_ERROR );
2570 }
2571}
2572
2573
2575{
2576 JOB_EXPORT_PCB_ODB* job = dynamic_cast<JOB_EXPORT_PCB_ODB*>( aJob );
2577
2578 if( job == nullptr )
2580
2581 BOARD* brd = getBoard( job->m_filename );
2582
2583 if( !brd )
2585
2586 if( job->GetConfiguredOutputPath().IsEmpty() )
2587 {
2589 {
2590 // just basic folder name
2591 job->SetWorkingOutputPath( "odb" );
2592 }
2593 else
2594 {
2595 wxFileName fn( brd->GetFileName() );
2596 fn.SetName( fn.GetName() + wxS( "-odb" ) );
2597
2598 switch( job->m_compressionMode )
2599 {
2601 fn.SetExt( FILEEXT::ArchiveFileExtension );
2602 break;
2604 fn.SetExt( "tgz" );
2605 break;
2606 default:
2607 break;
2608 };
2609
2610 job->SetWorkingOutputPath( fn.GetFullName() );
2611 }
2612 }
2613
2614 resolveJobOutputPath( job, brd );
2615
2616 // The helper handles output path creation, so hand it a job that already has fully-resolved
2617 // token context (title block and project overrides applied above).
2619
2621}
2622
2624{
2625 JOB_PCB_UPGRADE* job = dynamic_cast<JOB_PCB_UPGRADE*>( aJob );
2626
2627 if( job == nullptr )
2629
2630 bool shouldSave = job->m_force;
2631
2632 try
2633 {
2635 BOARD* brd = getBoard( job->m_filename );
2637 shouldSave = true;
2638
2639 if( shouldSave )
2640 {
2641 pi->SaveBoard( brd->GetFileName(), brd );
2642 m_reporter->Report( _( "Successfully saved board file using the latest format\n" ), RPT_SEVERITY_INFO );
2643 }
2644 else
2645 {
2646 m_reporter->Report( _( "Board file was not updated\n" ), RPT_SEVERITY_ERROR );
2647 }
2648 }
2649 catch( const IO_ERROR& ioe )
2650 {
2651 wxString msg =
2652 wxString::Format( _( "Error saving board file '%s'.\n%s" ), job->m_filename, ioe.What().GetData() );
2653 m_reporter->Report( msg, RPT_SEVERITY_ERROR );
2655 }
2656
2658}
2659
2660// Most job handlers need to align the running job with the board before resolving any
2661// output paths with variables in them like ${REVISION}.
2662wxString PCBNEW_JOBS_HANDLER::resolveJobOutputPath( JOB* aJob, BOARD* aBoard, const wxString* aDrawingSheet )
2663{
2664 aJob->SetTitleBlock( aBoard->GetTitleBlock() );
2665
2666 if( aDrawingSheet && !aDrawingSheet->IsEmpty() )
2667 loadOverrideDrawingSheet( aBoard, *aDrawingSheet );
2668
2669 PROJECT* project = aBoard->GetProject();
2670
2671 if( project )
2672 project->ApplyTextVars( aJob->GetVarOverrides() );
2673
2674 aBoard->SynchronizeProperties();
2675
2676 return aJob->GetFullOutputPath( project );
2677}
2678
2679
2681{
2683 &aBrd->GetPageSettings(),
2684 aBrd->GetProject(),
2685 &aBrd->GetTitleBlock(),
2686 &aBrd->GetProperties() );
2687
2688 drawingSheet->SetSheetName( std::string() );
2689 drawingSheet->SetSheetPath( std::string() );
2690 drawingSheet->SetIsFirstPage( true );
2691
2692 drawingSheet->SetFileName( TO_UTF8( aBrd->GetFileName() ) );
2693
2694 return drawingSheet;
2695}
2696
2697
2698void PCBNEW_JOBS_HANDLER::loadOverrideDrawingSheet( BOARD* aBrd, const wxString& aSheetPath )
2699{
2700 // dont bother attempting to load a empty path, if there was one
2701 if( aSheetPath.IsEmpty() )
2702 return;
2703
2704 auto loadSheet =
2705 [&]( const wxString& path ) -> bool
2706 {
2709 resolver.SetProject( aBrd->GetProject() );
2710 resolver.SetProgramBase( &Pgm() );
2711
2712 wxString filename = resolver.ResolvePath( BASE_SCREEN::m_DrawingSheetFileName,
2713 aBrd->GetProject()->GetProjectPath(),
2714 { aBrd->GetEmbeddedFiles() } );
2715 wxString msg;
2716
2717 if( !DS_DATA_MODEL::GetTheInstance().LoadDrawingSheet( filename, &msg ) )
2718 {
2719 m_reporter->Report( wxString::Format( _( "Error loading drawing sheet '%s'." ),
2720 path )
2721 + wxS( "\n" ) + msg + wxS( "\n" ),
2723 return false;
2724 }
2725
2726 return true;
2727 };
2728
2729 if( loadSheet( aSheetPath ) )
2730 return;
2731
2732 // failed loading custom path, revert back to default
2733 loadSheet( aBrd->GetProject()->GetProjectFile().m_BoardDrawingSheetFile );
2734}
@ 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:2072
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:2447
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)
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:204
bool Redraw(bool aIsMoving, REPORTER *aStatusReporter, REPORTER *aWarningReporter) override
Redraw the view.
void SetCurWindowSize(const wxSize &aSize) override
Before each render, the canvas will tell the render what is the size of its windows,...
PROJECT & Prj() const
A helper while we are not MDI-capable – return the one and only project.
Is a LINE_READER that reads from a multiline 8 bit wide std::string.
Definition richio.h:254
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Master controller class:
TOOL_BASE * FindTool(int aId) const
Search for a tool with given ID.
void RegisterTool(TOOL_BASE *aTool)
Add a tool to the manager set and sets it up.
void SetEnvironment(EDA_ITEM *aModel, KIGFX::VIEW *aView, KIGFX::VIEW_CONTROLS *aViewControls, APP_SETTINGS_BASE *aSettings, TOOLS_HOLDER *aFrame)
Set the work environment (model, view, view controls and the parent window).
void Pan_T1(const SFVEC3F &aDeltaOffsetInc) override
void SetT0_and_T1_current_T() override
This will set T0 and T1 with the current values.
void Interpolate(float t) override
It will update the matrix to interpolate between T0 and T1 values.
wxString wx_str() const
Definition utf8.cpp:45
Handle actions specific to filling copper zones.
wxString GetDefaultPlotExtension(PLOT_FORMAT aFormat)
Return the default plot extension for a format.
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp: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