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>()->FillAllZones( nullptr, m_progressReporter, true );
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>()->FillAllZones( nullptr, m_progressReporter, true );
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>()->FillAllZones( nullptr, m_progressReporter, true );
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 const bool outputIsSingle = plotAllLayersOneFile || pdfJob->m_pdfSingle;
1104
1105 if( outputIsSingle && pdfJob->GetConfiguredOutputPath().IsEmpty() )
1106 {
1107 wxFileName fn = brd->GetFileName();
1108 fn.SetName( fn.GetName() );
1110
1111 pdfJob->SetWorkingOutputPath( fn.GetFullName() );
1112 }
1113
1114 wxString outPath = resolveJobOutputPath( pdfJob, brd, &pdfJob->m_drawingSheet );
1115
1116 PCB_PLOT_PARAMS plotOpts;
1117 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, pdfJob, *m_reporter );
1118
1119 PCB_PLOTTER pcbPlotter( brd, m_reporter, plotOpts );
1120
1121 if( !PATHS::EnsurePathExists( outPath, outputIsSingle ) )
1122 {
1123 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1125 }
1126
1127 std::optional<wxString> layerName;
1128 std::optional<wxString> sheetName;
1129 std::optional<wxString> sheetPath;
1130
1131 if( plotAllLayersOneFile )
1132 {
1133 if( pdfJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
1134 layerName = pdfJob->GetVarOverrides().at( wxT( "LAYER" ) );
1135
1136 if( pdfJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
1137 sheetName = pdfJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
1138
1139 if( pdfJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
1140 sheetPath = pdfJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
1141 }
1142
1143 if( !pcbPlotter.Plot( outPath, pdfJob->m_plotLayerSequence,
1144 pdfJob->m_plotOnAllLayersSequence, false, outputIsSingle,
1145 layerName, sheetName, sheetPath ) )
1146 {
1148 }
1149
1150 return CLI::EXIT_CODES::OK;
1151}
1152
1153
1155{
1156 JOB_EXPORT_PCB_PS* psJob = dynamic_cast<JOB_EXPORT_PCB_PS*>( aJob );
1157
1158 if( psJob == nullptr )
1160
1161 BOARD* brd = getBoard( psJob->m_filename );
1162
1163 if( !brd )
1165
1166 TOOL_MANAGER* toolManager = getToolManager( brd );
1167
1168 if( psJob->m_checkZonesBeforePlot )
1169 {
1170 if( !toolManager->FindTool( ZONE_FILLER_TOOL_NAME ) )
1171 toolManager->RegisterTool( new ZONE_FILLER_TOOL );
1172
1173 toolManager->GetTool<ZONE_FILLER_TOOL>()->FillAllZones( nullptr, m_progressReporter, true );
1174 }
1175
1176 if( psJob->m_argLayers )
1177 psJob->m_plotLayerSequence = convertLayerArg( psJob->m_argLayers.value(), brd );
1178
1179 if( psJob->m_argCommonLayers )
1180 psJob->m_plotOnAllLayersSequence = convertLayerArg( psJob->m_argCommonLayers.value(), brd );
1181
1182 if( psJob->m_plotLayerSequence.size() < 1 )
1183 {
1184 m_reporter->Report( _( "At least one layer must be specified\n" ), RPT_SEVERITY_ERROR );
1186 }
1187
1188 bool isSingle = psJob->m_genMode == JOB_EXPORT_PCB_PS::GEN_MODE::SINGLE;
1189
1190 if( isSingle )
1191 {
1192 if( psJob->GetConfiguredOutputPath().IsEmpty() )
1193 {
1194 wxFileName fn = brd->GetFileName();
1195 fn.SetName( fn.GetName() );
1197
1198 psJob->SetWorkingOutputPath( fn.GetFullName() );
1199 }
1200 }
1201
1202 wxString outPath = resolveJobOutputPath( psJob, brd, &psJob->m_drawingSheet );
1203
1204 if( !PATHS::EnsurePathExists( outPath, isSingle ) )
1205 {
1206 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1208 }
1209
1210 PCB_PLOT_PARAMS plotOpts;
1211 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, psJob, *m_reporter );
1212
1213 PCB_PLOTTER pcbPlotter( brd, m_reporter, plotOpts );
1214
1215 std::optional<wxString> layerName;
1216 std::optional<wxString> sheetName;
1217 std::optional<wxString> sheetPath;
1218
1219 if( isSingle )
1220 {
1221 if( aJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
1222 layerName = psJob->GetVarOverrides().at( wxT( "LAYER" ) );
1223
1224 if( aJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
1225 sheetName = psJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
1226
1227 if( aJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
1228 sheetPath = psJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
1229 }
1230
1231 if( !pcbPlotter.Plot( outPath, psJob->m_plotLayerSequence, psJob->m_plotOnAllLayersSequence, false, isSingle,
1232 layerName, sheetName, sheetPath ) )
1233 {
1235 }
1236
1237 return CLI::EXIT_CODES::OK;
1238}
1239
1240
1242{
1243 int exitCode = CLI::EXIT_CODES::OK;
1244 JOB_EXPORT_PCB_GERBERS* aGerberJob = dynamic_cast<JOB_EXPORT_PCB_GERBERS*>( aJob );
1245
1246 if( aGerberJob == nullptr )
1248
1249 BOARD* brd = getBoard( aGerberJob->m_filename );
1250
1251 if( !brd )
1253
1254 wxString outPath = resolveJobOutputPath( aJob, brd, &aGerberJob->m_drawingSheet );
1255
1256 if( !PATHS::EnsurePathExists( outPath, false ) )
1257 {
1258 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1260 }
1261
1262 TOOL_MANAGER* toolManager = getToolManager( brd );
1263
1264 if( aGerberJob->m_checkZonesBeforePlot )
1265 {
1266 if( !toolManager->FindTool( ZONE_FILLER_TOOL_NAME ) )
1267 toolManager->RegisterTool( new ZONE_FILLER_TOOL );
1268
1269 toolManager->GetTool<ZONE_FILLER_TOOL>()->FillAllZones( nullptr, m_progressReporter, true );
1270 }
1271
1272 bool hasLayerListSpecified = false; // will be true if the user layer list is not empty
1273
1274 if( aGerberJob->m_argLayers )
1275 {
1276 if( !aGerberJob->m_argLayers.value().empty() )
1277 {
1278 aGerberJob->m_plotLayerSequence = convertLayerArg( aGerberJob->m_argLayers.value(), brd );
1279 hasLayerListSpecified = true;
1280 }
1281 else
1282 {
1284 }
1285 }
1286
1287 if( aGerberJob->m_argCommonLayers )
1288 aGerberJob->m_plotOnAllLayersSequence = convertLayerArg( aGerberJob->m_argCommonLayers.value(), brd );
1289
1290 PCB_PLOT_PARAMS boardPlotOptions = brd->GetPlotOptions();
1291 GERBER_JOBFILE_WRITER jobfile_writer( brd );
1292
1293 wxString fileExt;
1294
1295 if( aGerberJob->m_useBoardPlotParams )
1296 {
1297 // The board plot options are saved with all copper layers enabled, even those that don't
1298 // exist in the current stackup. This is done so the layers are automatically enabled in the plot
1299 // dialog when the user enables them. We need to filter out these not-enabled layers here so
1300 // we don't plot 32 layers when we only have 4, etc.
1301 LSET plotLayers = ( boardPlotOptions.GetLayerSelection() & LSET::AllNonCuMask() )
1302 | ( brd->GetEnabledLayers() & LSET::AllCuMask() );
1303 aGerberJob->m_plotLayerSequence = plotLayers.SeqStackupForPlotting();
1304 aGerberJob->m_plotOnAllLayersSequence = boardPlotOptions.GetPlotOnAllLayersSequence();
1305 }
1306 else
1307 {
1308 // default to the board enabled layers, but only if the user has not specifed a layer list
1309 // ( m_plotLayerSequence can be empty with a broken user layer list)
1310 if( aGerberJob->m_plotLayerSequence.empty() && !hasLayerListSpecified )
1312 }
1313
1314 // Ensure layers to plot are restricted to enabled layers of the board to plot
1315 LSET layersToPlot = LSET( { aGerberJob->m_plotLayerSequence } ) & brd->GetEnabledLayers();
1316
1317 for( PCB_LAYER_ID layer : layersToPlot.UIOrder() )
1318 {
1319 LSEQ plotSequence;
1320
1321 // Base layer always gets plotted first.
1322 plotSequence.push_back( layer );
1323
1324 // Now all the "include on all" layers
1325 for( PCB_LAYER_ID layer_all : aGerberJob->m_plotOnAllLayersSequence )
1326 {
1327 // Don't plot the same layer more than once;
1328 if( find( plotSequence.begin(), plotSequence.end(), layer_all ) != plotSequence.end() )
1329 continue;
1330
1331 plotSequence.push_back( layer_all );
1332 }
1333
1334 // Pick the basename from the board file
1335 wxFileName fn( brd->GetFileName() );
1336 wxString layerName = brd->GetLayerName( layer );
1337 wxString sheetName;
1338 wxString sheetPath;
1339 PCB_PLOT_PARAMS plotOpts;
1340
1341 if( aGerberJob->m_useBoardPlotParams )
1342 plotOpts = boardPlotOptions;
1343 else
1344 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, aGerberJob, *m_reporter );
1345
1346 if( plotOpts.GetUseGerberProtelExtensions() )
1347 fileExt = GetGerberProtelExtension( layer );
1348 else
1350
1351 BuildPlotFileName( &fn, outPath, layerName, fileExt );
1352 wxString fullname = fn.GetFullName();
1353
1354 if( m_progressReporter )
1355 {
1356 m_progressReporter->AdvancePhase( wxString::Format( _( "Exporting %s" ), fullname ) );
1357 m_progressReporter->KeepRefreshing();
1358 }
1359
1360 jobfile_writer.AddGbrFile( layer, fullname );
1361
1362 if( aJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
1363 layerName = aJob->GetVarOverrides().at( wxT( "LAYER" ) );
1364
1365 if( aJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
1366 sheetName = aJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
1367
1368 if( aJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
1369 sheetPath = aJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
1370
1371 // We are feeding it one layer at the start here to silence a logic check
1372 GERBER_PLOTTER* plotter;
1373 plotter = (GERBER_PLOTTER*) StartPlotBoard( brd, &plotOpts, layer, layerName,
1374 fn.GetFullPath(), sheetName, sheetPath );
1375
1376 if( plotter )
1377 {
1378 m_reporter->Report( wxString::Format( _( "Plotted to '%s'.\n" ), fn.GetFullPath() ),
1380
1381 PlotBoardLayers( brd, plotter, plotSequence, plotOpts );
1382 plotter->EndPlot();
1383 }
1384 else
1385 {
1386 m_reporter->Report( wxString::Format( _( "Failed to plot to '%s'.\n" ), fn.GetFullPath() ),
1389 }
1390
1391 delete plotter;
1392 }
1393
1394 if( aGerberJob->m_createJobsFile )
1395 {
1396 wxFileName fn( brd->GetFileName() );
1397
1398 // Build gerber job file from basename
1399 BuildPlotFileName( &fn, outPath, wxT( "job" ), FILEEXT::GerberJobFileExtension );
1400 jobfile_writer.CreateJobFile( fn.GetFullPath() );
1401 }
1402
1403 return exitCode;
1404}
1405
1406
1408{
1409 JOB_EXPORT_PCB_GENCAD* aGencadJob = dynamic_cast<JOB_EXPORT_PCB_GENCAD*>( aJob );
1410
1411 if( aGencadJob == nullptr )
1413
1414 BOARD* brd = LoadBoard( aGencadJob->m_filename, true ); // Ensure m_board is of type BOARD*
1415
1416 if( brd == nullptr )
1418
1419 GENCAD_EXPORTER exporter( brd );
1420
1421 VECTOR2I GencadOffset;
1422 VECTOR2I auxOrigin = brd->GetDesignSettings().GetAuxOrigin();
1423 GencadOffset.x = aGencadJob->m_useDrillOrigin ? auxOrigin.x : 0;
1424 GencadOffset.y = aGencadJob->m_useDrillOrigin ? auxOrigin.y : 0;
1425
1426 exporter.FlipBottomPads( aGencadJob->m_flipBottomPads );
1427 exporter.UsePinNamesUnique( aGencadJob->m_useUniquePins );
1428 exporter.UseIndividualShapes( aGencadJob->m_useIndividualShapes );
1429 exporter.SetPlotOffet( GencadOffset );
1430 exporter.StoreOriginCoordsInFile( aGencadJob->m_storeOriginCoords );
1431
1432 if( aGencadJob->GetConfiguredOutputPath().IsEmpty() )
1433 {
1434 wxFileName fn = brd->GetFileName();
1435 fn.SetName( fn.GetName() );
1436 fn.SetExt( FILEEXT::GencadFileExtension );
1437
1438 aGencadJob->SetWorkingOutputPath( fn.GetFullName() );
1439 }
1440
1441 wxString outPath = resolveJobOutputPath( aJob, brd );
1442
1443 if( !PATHS::EnsurePathExists( outPath, true ) )
1444 {
1445 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1447 }
1448
1449 if( !exporter.WriteFile( outPath ) )
1450 {
1451 m_reporter->Report( wxString::Format( _( "Failed to create file '%s'.\n" ), outPath ),
1453
1455 }
1456
1457 m_reporter->Report( _( "Successfully created genCAD file\n" ), RPT_SEVERITY_INFO );
1458
1459 return CLI::EXIT_CODES::OK;
1460}
1461
1462
1464{
1465 JOB_EXPORT_PCB_STATS* statsJob = dynamic_cast<JOB_EXPORT_PCB_STATS*>( aJob );
1466
1467 if( statsJob == nullptr )
1469
1470 BOARD* brd = getBoard( statsJob->m_filename );
1471
1472 if( !brd )
1474
1477
1482
1483 ComputeBoardStatistics( brd, options, data );
1484
1485 wxString projectName;
1486
1487 if( brd->GetProject() )
1488 projectName = brd->GetProject()->GetProjectName();
1489
1490 wxFileName boardFile = brd->GetFileName();
1491
1492 if( boardFile.GetName().IsEmpty() )
1493 boardFile = wxFileName( statsJob->m_filename );
1494
1496 UNITS_PROVIDER unitsProvider( pcbIUScale, unitsForReport );
1497
1498 wxString report;
1499
1501 report = FormatBoardStatisticsJson( data, brd, unitsProvider, projectName, boardFile.GetName() );
1502 else
1503 report = FormatBoardStatisticsReport( data, brd, unitsProvider, projectName, boardFile.GetName() );
1504
1505 if( statsJob->GetConfiguredOutputPath().IsEmpty() && statsJob->GetWorkingOutputPath().IsEmpty() )
1506 statsJob->SetDefaultOutputPath( boardFile.GetFullPath() );
1507
1508 wxString outPath = resolveJobOutputPath( aJob, brd );
1509
1510 if( !PATHS::EnsurePathExists( outPath, true ) )
1511 {
1512 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1514 }
1515
1516 FILE* outFile = wxFopen( outPath, wxS( "wt" ) );
1517
1518 if( !outFile )
1519 {
1520 m_reporter->Report( wxString::Format( _( "Failed to create file '%s'.\n" ), outPath ), RPT_SEVERITY_ERROR );
1522 }
1523
1524 if( fprintf( outFile, "%s", TO_UTF8( report ) ) < 0 )
1525 {
1526 fclose( outFile );
1527 m_reporter->Report( wxString::Format( _( "Error writing file '%s'.\n" ), outPath ), RPT_SEVERITY_ERROR );
1529 }
1530
1531 fclose( outFile );
1532
1533 m_reporter->Report( wxString::Format( _( "Wrote board statistics to '%s'.\n" ), outPath ), RPT_SEVERITY_ACTION );
1534
1535 statsJob->AddOutput( outPath );
1536
1537 return CLI::EXIT_CODES::OK;
1538}
1539
1540
1542{
1543 int exitCode = CLI::EXIT_CODES::OK;
1544 JOB_EXPORT_PCB_GERBER* aGerberJob = dynamic_cast<JOB_EXPORT_PCB_GERBER*>( aJob );
1545
1546 if( aGerberJob == nullptr )
1548
1549 BOARD* brd = getBoard( aGerberJob->m_filename );
1550
1551 if( !brd )
1553
1554 TOOL_MANAGER* toolManager = getToolManager( brd );
1555
1556 if( aGerberJob->m_argLayers )
1557 aGerberJob->m_plotLayerSequence = convertLayerArg( aGerberJob->m_argLayers.value(), brd );
1558
1559 if( aGerberJob->m_argCommonLayers )
1560 aGerberJob->m_plotOnAllLayersSequence = convertLayerArg( aGerberJob->m_argCommonLayers.value(), brd );
1561
1562 if( aGerberJob->m_plotLayerSequence.size() < 1 )
1563 {
1564 m_reporter->Report( _( "At least one layer must be specified\n" ), RPT_SEVERITY_ERROR );
1566 }
1567
1568 if( aGerberJob->GetConfiguredOutputPath().IsEmpty() )
1569 {
1570 wxFileName fn = brd->GetFileName();
1571 fn.SetName( fn.GetName() );
1573
1574 aGerberJob->SetWorkingOutputPath( fn.GetFullName() );
1575 }
1576
1577 wxString outPath = resolveJobOutputPath( aJob, brd );
1578
1579 if( aGerberJob->m_checkZonesBeforePlot )
1580 {
1581 if( !toolManager->FindTool( ZONE_FILLER_TOOL_NAME ) )
1582 toolManager->RegisterTool( new ZONE_FILLER_TOOL );
1583
1584 toolManager->GetTool<ZONE_FILLER_TOOL>()->FillAllZones( nullptr, m_progressReporter, true );
1585 }
1586
1587 PCB_PLOT_PARAMS plotOpts;
1588 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, aGerberJob, *m_reporter );
1589 plotOpts.SetLayerSelection( aGerberJob->m_plotLayerSequence );
1591
1593 wxString layerName;
1594 wxString sheetName;
1595 wxString sheetPath;
1596
1597 // The first layer will be treated as the layer name for the gerber header,
1598 // the other layers will be treated equivalent to the "Plot on All Layers" option
1599 // in the GUI
1600 if( aGerberJob->m_plotLayerSequence.size() >= 1 )
1601 {
1602 layer = aGerberJob->m_plotLayerSequence.front();
1603 layerName = brd->GetLayerName( layer );
1604 }
1605
1606 if( aJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
1607 layerName = aJob->GetVarOverrides().at( wxT( "LAYER" ) );
1608
1609 if( aJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
1610 sheetName = aJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
1611
1612 if( aJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
1613 sheetPath = aJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
1614
1615 // We are feeding it one layer at the start here to silence a logic check
1616 PLOTTER* plotter = StartPlotBoard( brd, &plotOpts, layer, layerName, outPath, sheetName,
1617 sheetPath );
1618
1619 if( plotter )
1620 {
1621 PlotBoardLayers( brd, plotter, aGerberJob->m_plotLayerSequence, plotOpts );
1622 plotter->EndPlot();
1623 }
1624 else
1625 {
1626 m_reporter->Report( wxString::Format( _( "Failed to plot to '%s'.\n" ), outPath ),
1629 }
1630
1631 delete plotter;
1632
1633 return exitCode;
1634}
1635
1638
1639
1641{
1642 JOB_EXPORT_PCB_DRILL* aDrillJob = dynamic_cast<JOB_EXPORT_PCB_DRILL*>( aJob );
1643
1644 if( aDrillJob == nullptr )
1646
1647 BOARD* brd = getBoard( aDrillJob->m_filename );
1648
1649 if( !brd )
1651
1652 wxString outPath = resolveJobOutputPath( aJob, brd );
1653
1654 if( !PATHS::EnsurePathExists( outPath ) )
1655 {
1656 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1658 }
1659
1660 std::unique_ptr<GENDRILL_WRITER_BASE> drillWriter;
1661
1663 drillWriter = std::make_unique<EXCELLON_WRITER>( brd );
1664 else
1665 drillWriter = std::make_unique<GERBER_WRITER>( brd );
1666
1667 VECTOR2I offset;
1668
1670 offset = VECTOR2I( 0, 0 );
1671 else
1672 offset = brd->GetDesignSettings().GetAuxOrigin();
1673
1674 PLOT_FORMAT mapFormat = PLOT_FORMAT::PDF;
1675
1676 switch( aDrillJob->m_mapFormat )
1677 {
1682 default:
1684 }
1685
1686
1687 if( aDrillJob->m_generateReport && aDrillJob->m_reportPath.IsEmpty() )
1688 {
1689 wxFileName fn = outPath;
1690 fn.SetFullName( brd->GetFileName() );
1691 fn.SetName( fn.GetName() + "-drill" );
1692 fn.SetExt( FILEEXT::ReportFileExtension );
1693
1694 aDrillJob->m_reportPath = fn.GetFullPath();
1695 }
1696
1698 {
1700
1701 switch( aDrillJob->m_zeroFormat )
1702 {
1705 break;
1706
1709 break;
1710
1713 break;
1714
1716 default:
1718 break;
1719 }
1720
1721 DRILL_PRECISION precision;
1722
1724 precision = precisionListForInches;
1725 else
1726 precision = precisionListForMetric;
1727
1728 EXCELLON_WRITER* excellonWriter = dynamic_cast<EXCELLON_WRITER*>( drillWriter.get() );
1729
1730 if( excellonWriter == nullptr )
1732
1733 excellonWriter->SetFormat( aDrillJob->m_drillUnits == JOB_EXPORT_PCB_DRILL::DRILL_UNITS::MM,
1734 zeroFmt, precision.m_Lhs, precision.m_Rhs );
1735 excellonWriter->SetOptions( aDrillJob->m_excellonMirrorY,
1736 aDrillJob->m_excellonMinimalHeader,
1737 offset, aDrillJob->m_excellonCombinePTHNPTH );
1738 excellonWriter->SetRouteModeForOvalHoles( aDrillJob->m_excellonOvalDrillRoute );
1739 excellonWriter->SetMapFileFormat( mapFormat );
1740
1741 if( !excellonWriter->CreateDrillandMapFilesSet( outPath, true, aDrillJob->m_generateMap,
1742 m_reporter ) )
1743 {
1745 }
1746
1747 if( aDrillJob->m_generateReport )
1748 {
1749 wxString reportPath = aDrillJob->ResolveOutputPath( aDrillJob->m_reportPath, true, brd->GetProject() );
1750
1751 if( !excellonWriter->GenDrillReportFile( reportPath ) )
1752 {
1754 }
1755 }
1756 }
1758 {
1759 GERBER_WRITER* gerberWriter = dynamic_cast<GERBER_WRITER*>( drillWriter.get() );
1760
1761 if( gerberWriter == nullptr )
1763
1764 // Set gerber precision: only 5 or 6 digits for mantissa are allowed
1765 // (SetFormat() accept 5 or 6, and any other value set the precision to 5)
1766 // the integer part precision is always 4, and units always mm
1767 gerberWriter->SetFormat( aDrillJob->m_gerberPrecision );
1768 gerberWriter->SetOptions( offset );
1769 gerberWriter->SetMapFileFormat( mapFormat );
1770
1771 if( !gerberWriter->CreateDrillandMapFilesSet( outPath, true, aDrillJob->m_generateMap,
1772 aDrillJob->m_generateTenting, m_reporter ) )
1773 {
1775 }
1776
1777 if( aDrillJob->m_generateReport )
1778 {
1779 wxString reportPath = aDrillJob->ResolveOutputPath( aDrillJob->m_reportPath, true, brd->GetProject() );
1780
1781 if( !gerberWriter->GenDrillReportFile( reportPath ) )
1782 {
1784 }
1785 }
1786 }
1787
1788 return CLI::EXIT_CODES::OK;
1789}
1790
1791
1793{
1794 JOB_EXPORT_PCB_POS* aPosJob = dynamic_cast<JOB_EXPORT_PCB_POS*>( aJob );
1795
1796 if( aPosJob == nullptr )
1798
1799 BOARD* brd = getBoard( aPosJob->m_filename );
1800
1801 if( !brd )
1803
1804 if( aPosJob->GetConfiguredOutputPath().IsEmpty() )
1805 {
1806 wxFileName fn = brd->GetFileName();
1807 fn.SetName( fn.GetName() );
1808
1811 else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::CSV )
1812 fn.SetExt( FILEEXT::CsvFileExtension );
1813 else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::GERBER )
1814 fn.SetExt( FILEEXT::GerberFileExtension );
1815
1816 aPosJob->SetWorkingOutputPath( fn.GetFullName() );
1817 }
1818
1819 wxString outPath = resolveJobOutputPath( aJob, brd );
1820
1821 if( !PATHS::EnsurePathExists( outPath, true ) )
1822 {
1823 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1825 }
1826
1829 {
1830 wxFileName fn( outPath );
1831 wxString baseName = fn.GetName();
1832
1833 auto exportPlaceFile =
1834 [&]( bool frontSide, bool backSide, const wxString& curr_outPath ) -> bool
1835 {
1836 FILE* file = wxFopen( curr_outPath, wxS( "wt" ) );
1837 wxCHECK( file, false );
1838
1839 PLACE_FILE_EXPORTER exporter( brd,
1841 aPosJob->m_smdOnly,
1843 aPosJob->m_excludeDNP,
1844 aPosJob->m_excludeBOM,
1845 frontSide,
1846 backSide,
1849 aPosJob->m_negateBottomX );
1850
1851 // Set variant for variant-aware DNP/BOM/position file filtering
1852 exporter.SetVariant( aPosJob->m_variant );
1853
1854 std::string data = exporter.GenPositionData();
1855 fputs( data.c_str(), file );
1856 fclose( file );
1857
1858 return true;
1859 };
1860
1861 if( aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH && !aPosJob->m_singleFile )
1862 {
1863 fn.SetName( PLACE_FILE_EXPORTER::DecorateFilename( baseName, true, false ) );
1864
1865 if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::CSV && !aPosJob->m_nakedFilename )
1866 fn.SetName( fn.GetName() + wxT( "-" ) + FILEEXT::FootprintPlaceFileExtension );
1867
1868 if( exportPlaceFile( true, false, fn.GetFullPath() ) )
1869 {
1870 m_reporter->Report( wxString::Format( _( "Wrote front position data to '%s'.\n" ),
1871 fn.GetFullPath() ),
1873
1874 aPosJob->AddOutput( fn.GetFullPath() );
1875 }
1876 else
1877 {
1879 }
1880
1881 fn.SetName( PLACE_FILE_EXPORTER::DecorateFilename( baseName, false, true ) );
1882
1883 if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::CSV && !aPosJob->m_nakedFilename )
1884 fn.SetName( fn.GetName() + wxT( "-" ) + FILEEXT::FootprintPlaceFileExtension );
1885
1886 if( exportPlaceFile( false, true, fn.GetFullPath() ) )
1887 {
1888 m_reporter->Report( wxString::Format( _( "Wrote back position data to '%s'.\n" ),
1889 fn.GetFullPath() ),
1891
1892 aPosJob->AddOutput( fn.GetFullPath() );
1893 }
1894 else
1895 {
1897 }
1898 }
1899 else
1900 {
1901 bool front = aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::FRONT
1903
1904 bool back = aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BACK
1906
1907 if( !aPosJob->m_nakedFilename )
1908 {
1909 fn.SetName( PLACE_FILE_EXPORTER::DecorateFilename( fn.GetName(), front, back ) );
1910
1912 fn.SetName( fn.GetName() + wxT( "-" ) + FILEEXT::FootprintPlaceFileExtension );
1913 }
1914
1915 if( exportPlaceFile( front, back, fn.GetFullPath() ) )
1916 {
1917 m_reporter->Report( wxString::Format( _( "Wrote position data to '%s'.\n" ),
1918 fn.GetFullPath() ),
1920
1921 aPosJob->AddOutput( fn.GetFullPath() );
1922 }
1923 else
1924 {
1926 }
1927 }
1928 }
1929 else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::GERBER )
1930 {
1931 PLACEFILE_GERBER_WRITER exporter( brd );
1932
1933 // Set variant for variant-aware DNP/BOM/position file filtering
1934 exporter.SetVariant( aPosJob->m_variant );
1935
1936 PCB_LAYER_ID gbrLayer = F_Cu;
1937 wxString outPath_base = outPath;
1938
1940 || aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH )
1941 {
1942 if( aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH || !aPosJob->m_nakedFilename )
1943 outPath = exporter.GetPlaceFileName( outPath, gbrLayer );
1944
1945 if( exporter.CreatePlaceFile( outPath, gbrLayer, aPosJob->m_gerberBoardEdge,
1946 aPosJob->m_excludeDNP, aPosJob->m_excludeBOM ) >= 0 )
1947 {
1948 m_reporter->Report( wxString::Format( _( "Wrote front position data to '%s'.\n" ), outPath ),
1950
1951 aPosJob->AddOutput( outPath );
1952 }
1953 else
1954 {
1956 }
1957 }
1958
1960 || aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH )
1961 {
1962 gbrLayer = B_Cu;
1963
1964 outPath = outPath_base;
1965
1966 if( aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH || !aPosJob->m_nakedFilename )
1967 outPath = exporter.GetPlaceFileName( outPath, gbrLayer );
1968
1969 if( exporter.CreatePlaceFile( outPath, gbrLayer, aPosJob->m_gerberBoardEdge,
1970 aPosJob->m_excludeDNP, aPosJob->m_excludeBOM ) >= 0 )
1971 {
1972 m_reporter->Report( wxString::Format( _( "Wrote back position data to '%s'.\n" ), outPath ),
1974
1975 aPosJob->AddOutput( outPath );
1976 }
1977 else
1978 {
1980 }
1981 }
1982 }
1983
1984 return CLI::EXIT_CODES::OK;
1985}
1986
1987
1989{
1990 JOB_FP_UPGRADE* upgradeJob = dynamic_cast<JOB_FP_UPGRADE*>( aJob );
1991
1992 if( upgradeJob == nullptr )
1994
1996
1997 if( !upgradeJob->m_outputLibraryPath.IsEmpty() )
1998 {
1999 if( wxFile::Exists( upgradeJob->m_outputLibraryPath )
2000 || wxDir::Exists( upgradeJob->m_outputLibraryPath) )
2001 {
2002 m_reporter->Report( _( "Output path must not conflict with existing path\n" ),
2005 }
2006 }
2007 else if( fileType != PCB_IO_MGR::KICAD_SEXP )
2008 {
2009 m_reporter->Report( _( "Output path must be specified to convert legacy and non-KiCad libraries\n" ),
2011
2013 }
2014
2016 {
2017 if( !wxDir::Exists( upgradeJob->m_libraryPath ) )
2018 {
2019 m_reporter->Report( _( "Footprint library path does not exist or is not accessible\n" ),
2022 }
2023
2025 FP_CACHE fpLib( &pcb_io, upgradeJob->m_libraryPath );
2026
2027 try
2028 {
2029 fpLib.Load();
2030 }
2031 catch( ... )
2032 {
2033 m_reporter->Report( _( "Unable to load library\n" ), RPT_SEVERITY_ERROR );
2035 }
2036
2037 if( m_progressReporter )
2038 m_progressReporter->KeepRefreshing();
2039
2040 bool shouldSave = upgradeJob->m_force;
2041
2042 for( const auto& footprint : fpLib.GetFootprints() )
2043 {
2044 if( footprint.second->GetFootprint()->GetFileFormatVersionAtLoad() < SEXPR_BOARD_FILE_VERSION )
2045 shouldSave = true;
2046 }
2047
2048 if( shouldSave )
2049 {
2050 try
2051 {
2052 if( !upgradeJob->m_outputLibraryPath.IsEmpty() )
2053 fpLib.SetPath( upgradeJob->m_outputLibraryPath );
2054
2055 fpLib.Save();
2056 }
2057 catch( ... )
2058 {
2059 m_reporter->Report( _( "Unable to save library\n" ), RPT_SEVERITY_ERROR );
2061 }
2062 }
2063 else
2064 {
2065 m_reporter->Report( _( "Footprint library was not updated\n" ), RPT_SEVERITY_ERROR );
2066 }
2067 }
2068 else
2069 {
2070 if( !PCB_IO_MGR::ConvertLibrary( {}, upgradeJob->m_libraryPath,
2071 upgradeJob->m_outputLibraryPath, nullptr /* REPORTER */ ) )
2072 {
2073 m_reporter->Report( ( "Unable to convert library\n" ), RPT_SEVERITY_ERROR );
2075 }
2076 }
2077
2078 return CLI::EXIT_CODES::OK;
2079}
2080
2081
2083{
2084 JOB_FP_EXPORT_SVG* svgJob = dynamic_cast<JOB_FP_EXPORT_SVG*>( aJob );
2085
2086 if( svgJob == nullptr )
2088
2090 FP_CACHE fpLib( &pcb_io, svgJob->m_libraryPath );
2091
2092 if( svgJob->m_argLayers )
2093 {
2094 if( !svgJob->m_argLayers.value().empty() )
2095 svgJob->m_plotLayerSequence = convertLayerArg( svgJob->m_argLayers.value(), nullptr );
2096 else
2098 }
2099
2100 try
2101 {
2102 fpLib.Load();
2103 }
2104 catch( ... )
2105 {
2106 m_reporter->Report( _( "Unable to load library\n" ), RPT_SEVERITY_ERROR );
2108 }
2109
2110 wxString outPath = svgJob->GetFullOutputPath( nullptr );
2111
2112 if( !PATHS::EnsurePathExists( outPath, true ) )
2113 {
2114 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
2116 }
2117
2118 int exitCode = CLI::EXIT_CODES::OK;
2119 bool singleFpPlotted = false;
2120
2121 for( const auto& [fpName, fpCacheEntry] : fpLib.GetFootprints() )
2122 {
2123 if( m_progressReporter )
2124 {
2125 m_progressReporter->AdvancePhase( wxString::Format( _( "Exporting %s" ), fpName ) );
2126 m_progressReporter->KeepRefreshing();
2127 }
2128
2129 if( !svgJob->m_footprint.IsEmpty() )
2130 {
2131 // skip until we find the right footprint
2132 if( fpName != svgJob->m_footprint )
2133 continue;
2134 else
2135 singleFpPlotted = true;
2136 }
2137
2138 exitCode = doFpExportSvg( svgJob, fpCacheEntry->GetFootprint().get() );
2139
2140 if( exitCode != CLI::EXIT_CODES::OK )
2141 break;
2142 }
2143
2144 if( !svgJob->m_footprint.IsEmpty() && !singleFpPlotted )
2145 {
2146 m_reporter->Report( _( "The given footprint could not be found to export." ) + wxS( "\n" ),
2148 }
2149
2150 return CLI::EXIT_CODES::OK;
2151}
2152
2153
2155{
2156 // the hack for now is we create fake boards containing the footprint and plot the board
2157 // until we refactor better plot api later
2158 std::unique_ptr<BOARD> brd;
2159 brd.reset( CreateEmptyBoard() );
2160 brd->GetProject()->ApplyTextVars( aSvgJob->GetVarOverrides() );
2161 brd->SynchronizeProperties();
2162
2163 FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( aFootprint->Clone() );
2164
2165 if( fp == nullptr )
2167
2168 fp->SetLink( niluuid );
2169 fp->SetFlags( IS_NEW );
2170 fp->SetParent( brd.get() );
2171
2172 for( PAD* pad : fp->Pads() )
2173 {
2174 pad->SetLocalRatsnestVisible( false );
2175 pad->SetNetCode( 0 );
2176 }
2177
2178 fp->SetOrientation( ANGLE_0 );
2179 fp->SetPosition( VECTOR2I( 0, 0 ) );
2180
2181 brd->Add( fp, ADD_MODE::INSERT, true );
2182
2183 wxFileName outputFile;
2184 outputFile.SetPath( aSvgJob->GetFullOutputPath(nullptr) );
2185 outputFile.SetName( aFootprint->GetFPID().GetLibItemName().wx_str() );
2186 outputFile.SetExt( FILEEXT::SVGFileExtension );
2187
2188 m_reporter->Report( wxString::Format( _( "Plotting footprint '%s' to '%s'\n" ),
2189 aFootprint->GetFPID().GetLibItemName().wx_str(),
2190 outputFile.GetFullPath() ),
2192
2193 PCB_PLOT_PARAMS plotOpts;
2194 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, aSvgJob, *m_reporter );
2195
2196 // always fixed for the svg plot
2197 plotOpts.SetPlotFrameRef( false );
2198 plotOpts.SetSvgFitPageToBoard( true );
2199 plotOpts.SetMirror( false );
2200 plotOpts.SetSkipPlotNPTH_Pads( false );
2201
2202 if( plotOpts.GetSketchPadsOnFabLayers() )
2203 {
2204 plotOpts.SetPlotPadNumbers( true );
2205 }
2206
2207 PCB_PLOTTER plotter( brd.get(), m_reporter, plotOpts );
2208
2209 if( !plotter.Plot( outputFile.GetFullPath(),
2210 aSvgJob->m_plotLayerSequence,
2212 false,
2213 true,
2214 wxEmptyString, wxEmptyString,
2215 wxEmptyString ) )
2216 {
2217 m_reporter->Report( _( "Error creating svg file" ) + wxS( "\n" ), RPT_SEVERITY_ERROR );
2219 }
2220
2221 return CLI::EXIT_CODES::OK;
2222}
2223
2224
2226{
2227 JOB_PCB_DRC* drcJob = dynamic_cast<JOB_PCB_DRC*>( aJob );
2228
2229 if( drcJob == nullptr )
2231
2232 BOARD* brd = getBoard( drcJob->m_filename );
2233
2234 if( !brd )
2236
2237 if( drcJob->GetConfiguredOutputPath().IsEmpty() )
2238 {
2239 wxFileName fn = brd->GetFileName();
2240 fn.SetName( fn.GetName() + wxS( "-drc" ) );
2241
2243 fn.SetExt( FILEEXT::JsonFileExtension );
2244 else
2245 fn.SetExt( FILEEXT::ReportFileExtension );
2246
2247 drcJob->SetWorkingOutputPath( fn.GetFullName() );
2248 }
2249
2250 wxString outPath = resolveJobOutputPath( aJob, brd );
2251
2252 if( !PATHS::EnsurePathExists( outPath, true ) )
2253 {
2254 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
2256 }
2257
2258 EDA_UNITS units;
2259
2260 switch( drcJob->m_units )
2261 {
2262 case JOB_PCB_DRC::UNITS::INCH: units = EDA_UNITS::INCH; break;
2263 case JOB_PCB_DRC::UNITS::MILS: units = EDA_UNITS::MILS; break;
2264 case JOB_PCB_DRC::UNITS::MM: units = EDA_UNITS::MM; break;
2265 default: units = EDA_UNITS::MM; break;
2266 }
2267
2268 std::shared_ptr<DRC_ENGINE> drcEngine = brd->GetDesignSettings().m_DRCEngine;
2269 std::unique_ptr<NETLIST> netlist = std::make_unique<NETLIST>();
2270
2271 drcEngine->SetDrawingSheet( getDrawingSheetProxyView( brd ) );
2272
2273 // BOARD_COMMIT uses TOOL_MANAGER to grab the board internally so we must give it one
2274 TOOL_MANAGER* toolManager = getToolManager( brd );
2275
2276 BOARD_COMMIT commit( toolManager );
2277 bool checkParity = drcJob->m_parity;
2278 std::string netlist_str;
2279
2280 if( checkParity )
2281 {
2282 wxString annotateMsg = _( "Schematic parity tests require a fully annotated schematic." );
2283 netlist_str = annotateMsg;
2284
2285 // The KIFACE_NETLIST_SCHEMATIC function has some broken-ness that the schematic
2286 // frame's version does not, but it is the only one that works in CLI, so we use it
2287 // if we don't have the sch frame open.
2288 // TODO: clean this up, see https://gitlab.com/kicad/code/kicad/-/issues/19929
2289 if( m_kiway->Player( FRAME_SCH, false ) )
2290 {
2291 m_kiway->ExpressMail( FRAME_SCH, MAIL_SCH_GET_NETLIST, netlist_str );
2292 }
2293 else
2294 {
2295 wxFileName schematicPath( drcJob->m_filename );
2296 schematicPath.SetExt( FILEEXT::KiCadSchematicFileExtension );
2297
2298 if( !schematicPath.Exists() )
2299 schematicPath.SetExt( FILEEXT::LegacySchematicFileExtension );
2300
2301 if( !schematicPath.Exists() )
2302 {
2303 m_reporter->Report( _( "Failed to fetch schematic netlist for parity tests.\n" ),
2305 checkParity = false;
2306 }
2307 else
2308 {
2309 typedef bool ( *NETLIST_FN_PTR )( const wxString&, std::string& );
2310 KIFACE* eeschema = m_kiway->KiFACE( KIWAY::FACE_SCH );
2311 NETLIST_FN_PTR netlister =
2312 (NETLIST_FN_PTR) eeschema->IfaceOrAddress( KIFACE_NETLIST_SCHEMATIC );
2313 ( *netlister )( schematicPath.GetFullPath(), netlist_str );
2314 }
2315 }
2316
2317 if( netlist_str == annotateMsg )
2318 {
2319 m_reporter->Report( wxString( netlist_str ) + wxT( "\n" ), RPT_SEVERITY_ERROR );
2320 checkParity = false;
2321 }
2322 }
2323
2324 if( checkParity )
2325 {
2326 try
2327 {
2328 STRING_LINE_READER* lineReader = new STRING_LINE_READER( netlist_str,
2329 _( "Eeschema netlist" ) );
2330 KICAD_NETLIST_READER netlistReader( lineReader, netlist.get() );
2331
2332 netlistReader.LoadNetlist();
2333 }
2334 catch( const IO_ERROR& )
2335 {
2336 m_reporter->Report( _( "Failed to fetch schematic netlist for parity tests.\n" ),
2338 checkParity = false;
2339 }
2340
2341 drcEngine->SetSchematicNetlist( netlist.get() );
2342 }
2343
2344 if( drcJob->m_refillZones )
2345 {
2346 if( !toolManager->FindTool( ZONE_FILLER_TOOL_NAME ) )
2347 toolManager->RegisterTool( new ZONE_FILLER_TOOL );
2348
2349 toolManager->GetTool<ZONE_FILLER_TOOL>()->FillAllZones( nullptr, m_progressReporter, true );
2350 }
2351
2352 drcEngine->SetProgressReporter( m_progressReporter );
2353 drcEngine->SetViolationHandler(
2354 [&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
2355 const std::function<void( PCB_MARKER* )>& aPathGenerator )
2356 {
2357 PCB_MARKER* marker = new PCB_MARKER( aItem, aPos, aLayer );
2358 aPathGenerator( marker );
2359 commit.Add( marker );
2360 } );
2361
2362 brd->RecordDRCExclusions();
2363 brd->DeleteMARKERs( true, true );
2364 drcEngine->RunTests( units, drcJob->m_reportAllTrackErrors, checkParity );
2365 drcEngine->ClearViolationHandler();
2366
2367 commit.Push( _( "DRC" ), SKIP_UNDO | SKIP_SET_DIRTY );
2368
2369 // Update the exclusion status on any excluded markers that still exist.
2370 brd->ResolveDRCExclusions( false );
2371
2372 std::shared_ptr<DRC_ITEMS_PROVIDER> markersProvider = std::make_shared<DRC_ITEMS_PROVIDER>(
2374
2375 std::shared_ptr<DRC_ITEMS_PROVIDER> ratsnestProvider =
2376 std::make_shared<DRC_ITEMS_PROVIDER>( brd, MARKER_BASE::MARKER_RATSNEST );
2377
2378 std::shared_ptr<DRC_ITEMS_PROVIDER> fpWarningsProvider =
2379 std::make_shared<DRC_ITEMS_PROVIDER>( brd, MARKER_BASE::MARKER_PARITY );
2380
2381 markersProvider->SetSeverities( drcJob->m_severity );
2382 ratsnestProvider->SetSeverities( drcJob->m_severity );
2383 fpWarningsProvider->SetSeverities( drcJob->m_severity );
2384
2385 m_reporter->Report( wxString::Format( _( "Found %d violations\n" ),
2386 markersProvider->GetCount() ),
2388 m_reporter->Report( wxString::Format( _( "Found %d unconnected items\n" ),
2389 ratsnestProvider->GetCount() ),
2391
2392 if( checkParity )
2393 {
2394 m_reporter->Report( wxString::Format( _( "Found %d schematic parity issues\n" ),
2395 fpWarningsProvider->GetCount() ),
2397 }
2398
2399 DRC_REPORT reportWriter( brd, units, markersProvider, ratsnestProvider, fpWarningsProvider );
2400
2401 bool wroteReport = false;
2402
2404 wroteReport = reportWriter.WriteJsonReport( outPath );
2405 else
2406 wroteReport = reportWriter.WriteTextReport( outPath );
2407
2408 if( !wroteReport )
2409 {
2410 m_reporter->Report( wxString::Format( _( "Unable to save DRC report to %s\n" ), outPath ),
2413 }
2414
2415 m_reporter->Report( wxString::Format( _( "Saved DRC Report to %s\n" ), outPath ),
2417
2418 if( drcJob->m_refillZones && drcJob->m_saveBoard )
2419 {
2420 if( SaveBoard( drcJob->m_filename, brd, true ) )
2421 {
2422 m_reporter->Report( _( "Saved board\n" ), RPT_SEVERITY_ACTION );
2423 }
2424 else
2425 {
2426 m_reporter->Report( _( "Failed to save board.\n" ), RPT_SEVERITY_ERROR );
2427
2429 }
2430 }
2431
2432 if( drcJob->m_exitCodeViolations )
2433 {
2434 if( markersProvider->GetCount() > 0 || ratsnestProvider->GetCount() > 0
2435 || fpWarningsProvider->GetCount() > 0 )
2436 {
2438 }
2439 }
2440
2442}
2443
2444
2446{
2447 JOB_EXPORT_PCB_IPC2581* job = dynamic_cast<JOB_EXPORT_PCB_IPC2581*>( aJob );
2448
2449 if( job == nullptr )
2451
2452 BOARD* brd = getBoard( job->m_filename );
2453
2454 if( !brd )
2456
2457 if( job->GetConfiguredOutputPath().IsEmpty() )
2458 {
2459 wxFileName fn = brd->GetFileName();
2460 fn.SetName( fn.GetName() );
2461 fn.SetExt( FILEEXT::Ipc2581FileExtension );
2462
2463 job->SetWorkingOutputPath( fn.GetName() );
2464 }
2465
2466 wxString outPath = resolveJobOutputPath( aJob, brd );
2467
2468 if( !PATHS::EnsurePathExists( outPath, true ) )
2469 {
2470 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
2472 }
2473
2474 std::map<std::string, UTF8> props;
2475 props["units"] = job->m_units == JOB_EXPORT_PCB_IPC2581::IPC2581_UNITS::MM ? "mm" : "inch";
2476 props["sigfig"] = wxString::Format( "%d", job->m_precision );
2477 props["version"] = job->m_version == JOB_EXPORT_PCB_IPC2581::IPC2581_VERSION::C ? "C" : "B";
2478 props["OEMRef"] = job->m_colInternalId;
2479 props["mpn"] = job->m_colMfgPn;
2480 props["mfg"] = job->m_colMfg;
2481 props["dist"] = job->m_colDist;
2482 props["distpn"] = job->m_colDistPn;
2483
2484 wxString tempFile = wxFileName::CreateTempFileName( wxS( "pcbnew_ipc" ) );
2485 try
2486 {
2488 pi->SetProgressReporter( m_progressReporter );
2489 pi->SaveBoard( tempFile, brd, &props );
2490 }
2491 catch( const IO_ERROR& ioe )
2492 {
2493 m_reporter->Report( wxString::Format( _( "Error generating IPC-2581 file '%s'.\n%s" ),
2494 job->m_filename,
2495 ioe.What() ),
2497
2498 wxRemoveFile( tempFile );
2499
2501 }
2502
2503 if( job->m_compress )
2504 {
2505 wxFileName tempfn = outPath;
2506 tempfn.SetExt( FILEEXT::Ipc2581FileExtension );
2507 wxFileName zipfn = tempFile;
2508 zipfn.SetExt( "zip" );
2509
2510 {
2511 wxFFileOutputStream fnout( zipfn.GetFullPath() );
2512 wxZipOutputStream zip( fnout );
2513 wxFFileInputStream fnin( tempFile );
2514
2515 zip.PutNextEntry( tempfn.GetFullName() );
2516 fnin.Read( zip );
2517 }
2518
2519 wxRemoveFile( tempFile );
2520 tempFile = zipfn.GetFullPath();
2521 }
2522
2523 // If save succeeded, replace the original with what we just wrote
2524 if( !wxRenameFile( tempFile, outPath ) )
2525 {
2526 m_reporter->Report( wxString::Format( _( "Error generating IPC-2581 file '%s'.\n"
2527 "Failed to rename temporary file '%s." ),
2528 outPath,
2529 tempFile ),
2531 }
2532
2534}
2535
2536
2538{
2539 JOB_EXPORT_PCB_IPCD356* job = dynamic_cast<JOB_EXPORT_PCB_IPCD356*>( aJob );
2540
2541 if( job == nullptr )
2543
2544 BOARD* brd = getBoard( job->m_filename );
2545
2546 if( !brd )
2548
2549 if( job->GetConfiguredOutputPath().IsEmpty() )
2550 {
2551 wxFileName fn = brd->GetFileName();
2552 fn.SetName( fn.GetName() );
2553 fn.SetExt( FILEEXT::IpcD356FileExtension );
2554
2555 job->SetWorkingOutputPath( fn.GetFullName() );
2556 }
2557
2558 wxString outPath = resolveJobOutputPath( aJob, brd );
2559
2560 if( !PATHS::EnsurePathExists( outPath, true ) )
2561 {
2562 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
2564 }
2565
2566 IPC356D_WRITER exporter( brd );
2567
2568 bool success = exporter.Write( outPath );
2569
2570 if( success )
2571 {
2572 m_reporter->Report( _( "Successfully created IPC-D-356 file\n" ), RPT_SEVERITY_INFO );
2574 }
2575 else
2576 {
2577 m_reporter->Report( _( "Failed to create IPC-D-356 file\n" ), RPT_SEVERITY_ERROR );
2579 }
2580}
2581
2582
2584{
2585 JOB_EXPORT_PCB_ODB* job = dynamic_cast<JOB_EXPORT_PCB_ODB*>( aJob );
2586
2587 if( job == nullptr )
2589
2590 BOARD* brd = getBoard( job->m_filename );
2591
2592 if( !brd )
2594
2595 if( job->GetConfiguredOutputPath().IsEmpty() )
2596 {
2598 {
2599 // just basic folder name
2600 job->SetWorkingOutputPath( "odb" );
2601 }
2602 else
2603 {
2604 wxFileName fn( brd->GetFileName() );
2605 fn.SetName( fn.GetName() + wxS( "-odb" ) );
2606
2607 switch( job->m_compressionMode )
2608 {
2610 fn.SetExt( FILEEXT::ArchiveFileExtension );
2611 break;
2612
2614 fn.SetExt( "tgz" );
2615 break;
2616
2617 default:
2618 break;
2619 };
2620
2621 job->SetWorkingOutputPath( fn.GetFullName() );
2622 }
2623 }
2624
2625 resolveJobOutputPath( job, brd );
2626
2627 // The helper handles output path creation, so hand it a job that already has fully-resolved
2628 // token context (title block and project overrides applied above).
2630
2632}
2633
2635{
2636 JOB_PCB_UPGRADE* job = dynamic_cast<JOB_PCB_UPGRADE*>( aJob );
2637
2638 if( job == nullptr )
2640
2641 bool shouldSave = job->m_force;
2642
2643 try
2644 {
2646 BOARD* brd = getBoard( job->m_filename );
2648 shouldSave = true;
2649
2650 if( shouldSave )
2651 {
2652 pi->SaveBoard( brd->GetFileName(), brd );
2653 m_reporter->Report( _( "Successfully saved board file using the latest format\n" ), RPT_SEVERITY_INFO );
2654 }
2655 else
2656 {
2657 m_reporter->Report( _( "Board file was not updated\n" ), RPT_SEVERITY_ERROR );
2658 }
2659 }
2660 catch( const IO_ERROR& ioe )
2661 {
2662 wxString msg =
2663 wxString::Format( _( "Error saving board file '%s'.\n%s" ), job->m_filename, ioe.What().GetData() );
2664 m_reporter->Report( msg, RPT_SEVERITY_ERROR );
2666 }
2667
2669}
2670
2671// Most job handlers need to align the running job with the board before resolving any
2672// output paths with variables in them like ${REVISION}.
2673wxString PCBNEW_JOBS_HANDLER::resolveJobOutputPath( JOB* aJob, BOARD* aBoard, const wxString* aDrawingSheet )
2674{
2675 aJob->SetTitleBlock( aBoard->GetTitleBlock() );
2676
2677 if( aDrawingSheet && !aDrawingSheet->IsEmpty() )
2678 loadOverrideDrawingSheet( aBoard, *aDrawingSheet );
2679
2680 PROJECT* project = aBoard->GetProject();
2681
2682 if( project )
2683 project->ApplyTextVars( aJob->GetVarOverrides() );
2684
2685 aBoard->SynchronizeProperties();
2686
2687 return aJob->GetFullOutputPath( project );
2688}
2689
2690
2692{
2694 &aBrd->GetPageSettings(),
2695 aBrd->GetProject(),
2696 &aBrd->GetTitleBlock(),
2697 &aBrd->GetProperties() );
2698
2699 drawingSheet->SetSheetName( std::string() );
2700 drawingSheet->SetSheetPath( std::string() );
2701 drawingSheet->SetIsFirstPage( true );
2702
2703 drawingSheet->SetFileName( TO_UTF8( aBrd->GetFileName() ) );
2704
2705 return drawingSheet;
2706}
2707
2708
2709void PCBNEW_JOBS_HANDLER::loadOverrideDrawingSheet( BOARD* aBrd, const wxString& aSheetPath )
2710{
2711 // dont bother attempting to load a empty path, if there was one
2712 if( aSheetPath.IsEmpty() )
2713 return;
2714
2715 auto loadSheet =
2716 [&]( const wxString& path ) -> bool
2717 {
2720 resolver.SetProject( aBrd->GetProject() );
2721 resolver.SetProgramBase( &Pgm() );
2722
2723 wxString filename = resolver.ResolvePath( BASE_SCREEN::m_DrawingSheetFileName,
2724 aBrd->GetProject()->GetProjectPath(),
2725 { aBrd->GetEmbeddedFiles() } );
2726 wxString msg;
2727
2728 if( !DS_DATA_MODEL::GetTheInstance().LoadDrawingSheet( filename, &msg ) )
2729 {
2730 m_reporter->Report( wxString::Format( _( "Error loading drawing sheet '%s'." ),
2731 path )
2732 + wxS( "\n" ) + msg + wxS( "\n" ),
2734 return false;
2735 }
2736
2737 return true;
2738 };
2739
2740 if( loadSheet( aSheetPath ) )
2741 return;
2742
2743 // failed loading custom path, revert back to default
2744 loadSheet( aBrd->GetProject()->GetProjectFile().m_BoardDrawingSheetFile );
2745}
@ 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:799
void RecordDRCExclusions()
Scan existing markers and record data from any that are Excluded.
Definition board.cpp:329
TITLE_BLOCK & GetTitleBlock()
Definition board.h:805
BOX2I ComputeBoundingBox(bool aBoardEdgesOnly=false) const
Calculate the bounding box containing all board items (or board edge segments).
Definition board.cpp:2103
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:386
int GetFileFormatVersionAtLoad() const
Definition board.h:456
const PCB_PLOT_PARAMS & GetPlotOptions() const
Definition board.h:802
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition board.cpp:728
PROJECT * GetProject() const
Definition board.h:579
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1082
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition board.cpp:967
void SynchronizeProperties()
Copy the current project's text variables into the boards property cache.
Definition board.cpp:2478
void DeleteMARKERs()
Delete all MARKERS from the board.
Definition board.cpp:1718
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:148
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:1066
void SetOrientation(const EDA_ANGLE &aNewAngle)
EDA_ITEM * Clone() const override
Invoke a function on all children.
std::deque< PAD * > & Pads()
Definition footprint.h:304
const LIB_ID & GetFPID() const
Definition footprint.h:349
void SetPath(const wxString &aPath)
void Save(FOOTPRINT *aFootprintFilter=nullptr)
Save the footprint cache or a single footprint from it to disk.
boost::ptr_map< wxString, FP_CACHE_ENTRY > & GetFootprints()
Export board to GenCAD file format.
void UseIndividualShapes(bool aUnique)
Make pad shapes unique.
void UsePinNamesUnique(bool aUnique)
Make pin names unique.
void StoreOriginCoordsInFile(bool aStore)
Store origin coordinate in GenCAD file.
void FlipBottomPads(bool aFlip)
Flip pad shapes on the bottom side.
void SetPlotOffet(VECTOR2I aOffset)
Set the coordinates offset when exporting items.
bool WriteFile(const wxString &aFullFileName)
Export a GenCAD file.
void SetMapFileFormat(PLOT_FORMAT aMapFmt)
Initialize the format for the drill map file.
bool GenDrillReportFile(const wxString &aFullFileName, REPORTER *aReporter=nullptr)
Create a plain text report file giving a list of drill values and drill count for through holes,...
GERBER_JOBFILE_WRITER is a class used to create Gerber job file a Gerber job file stores info to make...
bool CreateJobFile(const wxString &aFullFilename)
Creates a Gerber job file.
void AddGbrFile(PCB_LAYER_ID aLayer, wxString &aFilename)
add a gerber file name and type in job file list
virtual bool EndPlot() override
Used to create Gerber drill files.
bool CreateDrillandMapFilesSet(const wxString &aPlotDirectory, bool aGenDrill, bool aGenMap, bool aGenTenting, REPORTER *aReporter=nullptr)
Create the full set of Excellon drill file for the board filenames are computed from the board name,...
void SetOptions(const VECTOR2I &aOffset)
Initialize internal parameters to match drill options.
void SetFormat(int aRightDigits=6)
Initialize internal parameters to match the given format.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
Wrapper to expose an API for writing IPC-D356 files.
Definition export_d356.h:54
bool Write(const wxString &aFilename)
Generates and writes the netlist to a given path.
void Register(const std::string &aJobTypeName, std::function< int(JOB *job)> aHandler, std::function< bool(JOB *job, wxWindow *aParent)> aConfigHandler)
JOB_DISPATCHER(KIWAY *aKiway)
PROGRESS_REPORTER * m_progressReporter
REPORTER * m_reporter
JOB_EXPORT_PCB_3D::FORMAT m_format
EXPORTER_STEP_PARAMS m_3dparams
Despite the name; also used for other formats.
wxString GetSettingsDialogTitle() const override
ODB_COMPRESSION m_compressionMode
@ ALL_LAYERS_ONE_FILE
DEPRECATED MODE.
bool m_pdfSingle
This is a hack to deal with cli having the wrong behavior We will deprecate out the wrong behavior,...
GEN_MODE m_pdfGenMode
The background color specified in a hex string.
LSEQ m_plotOnAllLayersSequence
Used by SVG & PDF.
std::optional< wxString > m_argLayers
std::optional< wxString > m_argCommonLayers
LSEQ m_plotLayerSequence
Layers to include on all individual layer prints.
wxString m_variant
Variant name for variant-aware filtering.
void SetDefaultOutputPath(const wxString &aReferenceName)
wxString m_libraryPath
wxString m_outputLibraryPath
bool m_saveBoard
Definition job_pcb_drc.h:36
bool m_reportAllTrackErrors
Definition job_pcb_drc.h:32
bool m_refillZones
Definition job_pcb_drc.h:35
VECTOR3D m_lightBottomIntensity
VECTOR3D m_lightTopIntensity
VECTOR3D m_lightCameraIntensity
VECTOR3D m_rotation
wxString m_filename
bool m_useBoardStackupColors
VECTOR3D m_lightSideIntensity
std::string m_appearancePreset
bool m_exitCodeViolations
Definition job_rc.h:52
int m_severity
Definition job_rc.h:49
UNITS m_units
Definition job_rc.h:48
OUTPUT_FORMAT m_format
Definition job_rc.h:50
wxString m_filename
Definition job_rc.h:47
An simple container class that lets us dispatch output jobs to kifaces.
Definition job.h:183
wxString ResolveOutputPath(const wxString &aPath, bool aPathIsDirectory, PROJECT *aProject) const
Definition job.cpp:100
void AddOutput(wxString aOutputPath)
Definition job.h:215
wxString GetFullOutputPath(PROJECT *aProject) const
Returns the full output path for the job, taking into account the configured output path,...
Definition job.cpp:150
wxString GetWorkingOutputPath() const
Returns the working output path for the job, if one has been set.
Definition job.h:243
wxString GetConfiguredOutputPath() const
Returns the configured output path for the job.
Definition job.h:232
void SetTitleBlock(const TITLE_BLOCK &aTitleBlock)
Definition job.h:203
void SetWorkingOutputPath(const wxString &aPath)
Sets a transient output path for the job, it takes priority over the configured output path when GetF...
Definition job.h:238
const std::map< wxString, wxString > & GetVarOverrides() const
Definition job.h:196
Read the new s-expression based KiCad netlist format.
virtual void LoadNetlist() override
Load the contents of the netlist file into aNetlist.
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:105
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition kiway.h:294
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:301
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
void SetSvgFitPageToBoard(int aSvgFitPageToBoard)
bool GetUseGerberProtelExtensions() const
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:132
Used to create Gerber drill files.
const wxString GetPlaceFileName(const wxString &aFullBaseFilename, PCB_LAYER_ID aLayer) const
void SetVariant(const wxString &aVariant)
Set the variant name for variant-aware filtering.
int CreatePlaceFile(const wxString &aFullFilename, PCB_LAYER_ID aLayer, bool aIncludeBrdEdges, bool aExcludeDNP, bool aExcludeBOM)
Create an pnp gerber file.
The ASCII format of the kicad place file is:
static wxString DecorateFilename(const wxString &aBaseName, bool aFront, bool aBack)
std::string GenPositionData()
build a string filled with the position data
void SetVariant(const wxString &aVariant)
Set the variant name for variant-aware DNP filtering.
Base plotter engine class.
Definition plotter.h:136
virtual bool EndPlot()=0
wxString m_BoardDrawingSheetFile
PcbNew params.
static S3D_CACHE * Get3DCacheManager(PROJECT *aProject, bool updateProjDir=false)
Return a pointer to an instance of the 3D cache manager.
Container for project specific data.
Definition project.h:65
virtual const wxString GetProjectFullName() const
Return the full path and name of the project.
Definition project.cpp:161
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition project.cpp:167
virtual const wxString GetProjectName() const
Return the short name of the project.
Definition project.cpp:179
virtual PROJECT_FILE & GetProjectFile() const
Definition project.h:199
bool Redraw(bool aIsMoving, REPORTER *aStatusReporter, REPORTER *aWarningReporter) override
Redraw the view.
void SetCurWindowSize(const wxSize &aSize) override
Before each render, the canvas will tell the render what is the size of its windows,...
PROJECT & Prj() const
A helper while we are not MDI-capable – return the one and only project.
Is a LINE_READER that reads from a multiline 8 bit wide std::string.
Definition richio.h:226
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Master controller class:
TOOL_BASE * FindTool(int aId) const
Search for a tool with given ID.
void RegisterTool(TOOL_BASE *aTool)
Add a tool to the manager set and sets it up.
void SetEnvironment(EDA_ITEM *aModel, KIGFX::VIEW *aView, KIGFX::VIEW_CONTROLS *aViewControls, APP_SETTINGS_BASE *aSettings, TOOLS_HOLDER *aFrame)
Set the work environment (model, view, view controls and the parent window).
void Pan_T1(const SFVEC3F &aDeltaOffsetInc) override
void SetT0_and_T1_current_T() override
This will set T0 and T1 with the current values.
void Interpolate(float t) override
It will update the matrix to interpolate between T0 and T1 values.
wxString wx_str() const
Definition utf8.cpp:45
Handle actions specific to filling copper zones.
wxString GetDefaultPlotExtension(PLOT_FORMAT aFormat)
Return the default plot extension for a format.
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:202
This file is part of the common library.
static DRILL_PRECISION precisionListForInches(2, 4)
static DRILL_PRECISION precisionListForMetric(3, 3)
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:411
#define IS_NEW
New item, just created.
EDA_UNITS
Definition eda_units.h:48
static FILENAME_RESOLVER * resolver
@ FRAME_PCB_EDITOR
Definition frame_type.h:42
@ FRAME_SCH
Definition frame_type.h:34
Classes used in drill files, map files and report files generation.
Classes used in drill files, map files and report files generation.
Classes used to generate a Gerber job file in JSON.
Classes used in place file generation.
static const std::string LegacySchematicFileExtension
static const std::string BrepFileExtension
static const std::string JpegFileExtension
static const std::string GerberJobFileExtension
static const std::string GerberFileExtension
static const std::string XaoFileExtension
static const std::string ReportFileExtension
static const std::string GltfBinaryFileExtension
static const std::string PngFileExtension
static const std::string FootprintPlaceFileExtension
static const std::string JsonFileExtension
static const std::string KiCadSchematicFileExtension
static const std::string CsvFileExtension
static const std::string U3DFileExtension
static const std::string PdfFileExtension
static const std::string Ipc2581FileExtension
static const std::string GencadFileExtension
static const std::string StlFileExtension
static const std::string IpcD356FileExtension
static const std::string PlyFileExtension
static const std::string StepFileExtension
static const std::string SVGFileExtension
static const std::string VrmlFileExtension
static const std::string ArchiveFileExtension
static const std::string KiCadPcbFileExtension
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition io_mgr.h:33
@ KIFACE_NETLIST_SCHEMATIC
Definition kiface_ids.h:43
KIID niluuid(0)
wxString LayerName(int aLayer)
Returns the default display name for a given layer.
Definition layer_id.cpp:31
@ LAYER_3D_BACKGROUND_TOP
Definition layer_ids.h:553
@ LAYER_3D_BACKGROUND_BOTTOM
Definition layer_ids.h:552
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ F_CrtYd
Definition layer_ids.h:116
@ B_Adhes
Definition layer_ids.h:103
@ F_Paste
Definition layer_ids.h:104
@ F_Adhes
Definition layer_ids.h:102
@ B_Mask
Definition layer_ids.h:98
@ B_Cu
Definition layer_ids.h:65
@ F_Mask
Definition layer_ids.h:97
@ B_Paste
Definition layer_ids.h:105
@ F_Fab
Definition layer_ids.h:119
@ F_SilkS
Definition layer_ids.h:100
@ B_CrtYd
Definition layer_ids.h:115
@ UNDEFINED_LAYER
Definition layer_ids.h:61
@ B_SilkS
Definition layer_ids.h:101
@ F_Cu
Definition layer_ids.h:64
@ B_Fab
Definition layer_ids.h:118
This file contains miscellaneous commonly used macros and functions.
@ MAIL_SCH_GET_NETLIST
Definition mail_type.h:49
static const int ERR_ARGS
Definition exit_codes.h:31
static const int OK
Definition exit_codes.h:30
static const int ERR_RC_VIOLATIONS
Rules check violation count was greater than 0.
Definition exit_codes.h:37
static const int ERR_INVALID_INPUT_FILE
Definition exit_codes.h:33
static const int SUCCESS
Definition exit_codes.h:29
static const int ERR_INVALID_OUTPUT_CONFLICT
Definition exit_codes.h:34
static const int ERR_UNKNOWN
Definition exit_codes.h:32
#define SEXPR_BOARD_FILE_VERSION
Current s-expression file format version. 2 was the last legacy format version.
#define CTL_FOR_LIBRARY
Format output for a footprint library instead of clipboard or BOARD.
static DRILL_PRECISION precisionListForInches(2, 4)
static DRILL_PRECISION precisionListForMetric(3, 3)
SETTINGS_MANAGER * GetSettingsManager()
BOARD * CreateEmptyBoard()
Construct a default BOARD with a temporary (no filename) project.
bool SaveBoard(wxString &aFileName, BOARD *aBoard, PCB_IO_MGR::PCB_FILE_T aFormat, bool aSkipSettings)
BOARD * LoadBoard(const wxString &aFileName, bool aSetActive)
Loads a board from file This function identifies the file type by extension and determines the correc...
const wxString GetGerberProtelExtension(int aLayer)
Definition pcbplot.cpp:43
void BuildPlotFileName(wxFileName *aFilename, const wxString &aOutputDir, const wxString &aSuffix, const wxString &aExtension)
Complete a plot filename.
Definition pcbplot.cpp:379
PLOTTER * StartPlotBoard(BOARD *aBoard, const PCB_PLOT_PARAMS *aPlotOpts, int aLayer, const wxString &aLayerName, const wxString &aFullFileName, const wxString &aSheetName, const wxString &aSheetPath, const wxString &aPageName=wxT("1"), const wxString &aPageNumber=wxEmptyString, const int aPageCount=1)
Open a new plotfile using the options (and especially the format) specified in the options and prepar...
void PlotBoardLayers(BOARD *aBoard, PLOTTER *aPlotter, const LSEQ &aLayerSequence, const PCB_PLOT_PARAMS &aPlotOptions)
Plot a sequence of board layer IDs.
PGM_BASE & Pgm()
The global program "get" accessor.
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