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>
25#include <drc/drc_item.h>
26#include <drc/drc_report.h>
30#include <jobs/job_fp_upgrade.h>
45#include <jobs/job_pcb_render.h>
46#include <jobs/job_pcb_drc.h>
47#include <lset.h>
48#include <cli/exit_codes.h>
54#include <tool/tool_manager.h>
55#include <tools/drc_tool.h>
56#include <filename_resolver.h>
61#include <kiface_base.h>
62#include <macros.h>
63#include <pad.h>
64#include <pcb_marker.h>
68#include <kiface_ids.h>
71#include <pcbnew_settings.h>
72#include <pcbplot.h>
73#include <pcb_plotter.h>
74#include <pgm_base.h>
77#include <project_pcb.h>
79#include <reporter.h>
80#include <progress_reporter.h>
82#include <export_vrml.h>
83#include <wx/wfstream.h>
84#include <wx/zipstrm.h>
91#include <dialogs/dialog_plot.h>
95#include <paths.h>
96
98#include <locale_io.h>
99#include <confirm.h>
100
101
102#ifdef _WIN32
103#ifdef TRANSPARENT
104#undef TRANSPARENT
105#endif
106#endif
107
108
110 JOB_DISPATCHER( aKiway ),
111 m_cliBoard( nullptr )
112{
113 Register( "3d", std::bind( &PCBNEW_JOBS_HANDLER::JobExportStep, this, std::placeholders::_1 ),
114 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
115 {
116 JOB_EXPORT_PCB_3D* svgJob = dynamic_cast<JOB_EXPORT_PCB_3D*>( job );
117
118 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
119 false ) );
120
121 wxCHECK( svgJob && editFrame, false );
122
123 DIALOG_EXPORT_STEP dlg( editFrame, aParent, "", svgJob );
124 return dlg.ShowModal() == wxID_OK;
125 } );
126 Register( "render",
127 std::bind( &PCBNEW_JOBS_HANDLER::JobExportRender, this, std::placeholders::_1 ),
128 []( JOB* job, wxWindow* aParent ) -> bool
129 {
130 JOB_PCB_RENDER* renderJob = dynamic_cast<JOB_PCB_RENDER*>( job );
131
132 wxCHECK( renderJob, false );
133
134 DIALOG_RENDER_JOB dlg( aParent, renderJob );
135 return dlg.ShowModal() == wxID_OK;
136 } );
137 Register( "svg", std::bind( &PCBNEW_JOBS_HANDLER::JobExportSvg, this, std::placeholders::_1 ),
138 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
139 {
140 JOB_EXPORT_PCB_SVG* svgJob = dynamic_cast<JOB_EXPORT_PCB_SVG*>( job );
141
142 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
143 false ) );
144
145 wxCHECK( svgJob && editFrame, false );
146
147 DIALOG_PLOT dlg( editFrame, aParent, svgJob );
148 return dlg.ShowModal() == wxID_OK;
149 } );
150 Register( "gencad",
151 std::bind( &PCBNEW_JOBS_HANDLER::JobExportGencad, this, std::placeholders::_1 ),
152 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
153 {
154 JOB_EXPORT_PCB_GENCAD* gencadJob = dynamic_cast<JOB_EXPORT_PCB_GENCAD*>( job );
155
156 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
157 false ) );
158
159 wxCHECK( gencadJob && editFrame, false );
160
161 DIALOG_GENCAD_EXPORT_OPTIONS dlg( editFrame, gencadJob );
162 return dlg.ShowModal() == wxID_OK;
163 } );
164 Register( "dxf", std::bind( &PCBNEW_JOBS_HANDLER::JobExportDxf, this, std::placeholders::_1 ),
165 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
166 {
167 JOB_EXPORT_PCB_DXF* dxfJob = dynamic_cast<JOB_EXPORT_PCB_DXF*>( job );
168
169 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
170 false ) );
171
172 wxCHECK( dxfJob && editFrame, false );
173
174 DIALOG_PLOT dlg( editFrame, aParent, dxfJob );
175 return dlg.ShowModal() == wxID_OK;
176 } );
177 Register( "pdf", std::bind( &PCBNEW_JOBS_HANDLER::JobExportPdf, this, std::placeholders::_1 ),
178 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
179 {
180 JOB_EXPORT_PCB_PDF* pdfJob = dynamic_cast<JOB_EXPORT_PCB_PDF*>( job );
181
182 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
183 false ) );
184
185 wxCHECK( pdfJob && editFrame, false );
186
187 DIALOG_PLOT dlg( editFrame, aParent, pdfJob );
188 return dlg.ShowModal() == wxID_OK;
189 } );
190 Register( "ps", std::bind( &PCBNEW_JOBS_HANDLER::JobExportPs, this, std::placeholders::_1 ),
191 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
192 {
193 JOB_EXPORT_PCB_PS* psJob = dynamic_cast<JOB_EXPORT_PCB_PS*>( job );
194
195 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
196 false ) );
197
198 wxCHECK( psJob && editFrame, false );
199
200 DIALOG_PLOT dlg( editFrame, aParent, psJob );
201 return dlg.ShowModal() == wxID_OK;
202 } );
203 Register( "gerber",
204 std::bind( &PCBNEW_JOBS_HANDLER::JobExportGerber, this, std::placeholders::_1 ),
205 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
206 {
207 JOB_EXPORT_PCB_GERBER* gJob = dynamic_cast<JOB_EXPORT_PCB_GERBER*>( job );
208
209 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
210 false ) );
211
212 wxCHECK( gJob && editFrame, false );
213
214 DIALOG_PLOT dlg( editFrame, aParent, gJob );
215 return dlg.ShowModal() == wxID_OK;
216 } );
217 Register( "gerbers",
218 std::bind( &PCBNEW_JOBS_HANDLER::JobExportGerbers, this, std::placeholders::_1 ),
219 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
220 {
221 JOB_EXPORT_PCB_GERBERS* gJob = dynamic_cast<JOB_EXPORT_PCB_GERBERS*>( job );
222
223 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
224 false ) );
225
226 wxCHECK( gJob && editFrame, false );
227
228 DIALOG_PLOT dlg( editFrame, aParent, gJob );
229 return dlg.ShowModal() == wxID_OK;
230 } );
231 Register( "hpgl",
232 [&]( JOB* aJob )
233 {
234 m_reporter->Report( _( "Plotting to HPGL is no longer supported as of KiCad 10.0.\n" ),
237 },
238 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
239 {
240 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
241 false ) );
242
243 wxCHECK( editFrame, false );
244
245 DisplayErrorMessage( editFrame,
246 _( "Plotting to HPGL is no longer supported as of KiCad 10.0." ) );
247 return false;
248 } );
249 Register( "drill",
250 std::bind( &PCBNEW_JOBS_HANDLER::JobExportDrill, this, std::placeholders::_1 ),
251 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
252 {
253 JOB_EXPORT_PCB_DRILL* drillJob = dynamic_cast<JOB_EXPORT_PCB_DRILL*>( job );
254
255 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
256 false ) );
257
258 wxCHECK( drillJob && editFrame, false );
259
260 DIALOG_GENDRILL dlg( editFrame, drillJob, aParent );
261 return dlg.ShowModal() == wxID_OK;
262 } );
263 Register( "pos", std::bind( &PCBNEW_JOBS_HANDLER::JobExportPos, this, std::placeholders::_1 ),
264 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
265 {
266 JOB_EXPORT_PCB_POS* posJob = dynamic_cast<JOB_EXPORT_PCB_POS*>( job );
267
268 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
269 false ) );
270
271 wxCHECK( posJob && editFrame, false );
272
273 DIALOG_GEN_FOOTPRINT_POSITION dlg( posJob, editFrame, aParent );
274 return dlg.ShowModal() == wxID_OK;
275 } );
276 Register( "fpupgrade",
277 std::bind( &PCBNEW_JOBS_HANDLER::JobExportFpUpgrade, this, std::placeholders::_1 ),
278 []( JOB* job, wxWindow* aParent ) -> bool
279 {
280 return true;
281 } );
282 Register( "fpsvg",
283 std::bind( &PCBNEW_JOBS_HANDLER::JobExportFpSvg, this, std::placeholders::_1 ),
284 []( JOB* job, wxWindow* aParent ) -> bool
285 {
286 return true;
287 } );
288 Register( "drc", std::bind( &PCBNEW_JOBS_HANDLER::JobExportDrc, this, std::placeholders::_1 ),
289 []( JOB* job, wxWindow* aParent ) -> bool
290 {
291 JOB_PCB_DRC* drcJob = dynamic_cast<JOB_PCB_DRC*>( job );
292
293 wxCHECK( drcJob, false );
294
295 DIALOG_DRC_JOB_CONFIG dlg( aParent, drcJob );
296 return dlg.ShowModal() == wxID_OK;
297 } );
298 Register( "ipc2581",
299 std::bind( &PCBNEW_JOBS_HANDLER::JobExportIpc2581, this, std::placeholders::_1 ),
300 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
301 {
302 JOB_EXPORT_PCB_IPC2581* ipcJob = dynamic_cast<JOB_EXPORT_PCB_IPC2581*>( job );
303
304 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
305 false ) );
306
307 wxCHECK( ipcJob && editFrame, false );
308
309 DIALOG_EXPORT_2581 dlg( ipcJob, editFrame, aParent );
310 return dlg.ShowModal() == wxID_OK;
311 } );
312 Register( "ipcd356",
313 std::bind( &PCBNEW_JOBS_HANDLER::JobExportIpcD356, this, std::placeholders::_1 ),
314 []( JOB* job, wxWindow* aParent ) -> bool
315 {
316 return true;
317 } );
318 Register( "odb",
319 std::bind( &PCBNEW_JOBS_HANDLER::JobExportOdb, this, std::placeholders::_1 ),
320 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
321 {
322 JOB_EXPORT_PCB_ODB* odbJob = dynamic_cast<JOB_EXPORT_PCB_ODB*>( job );
323
324 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
325 false ) );
326
327 wxCHECK( odbJob && editFrame, false );
328
329 DIALOG_EXPORT_ODBPP dlg( odbJob, editFrame, aParent );
330 return dlg.ShowModal() == wxID_OK;
331 } );
332}
333
334
335BOARD* PCBNEW_JOBS_HANDLER::getBoard( const wxString& aPath )
336{
337 BOARD* brd = nullptr;
338
339 if( !Pgm().IsGUI() && Pgm().GetSettingsManager().IsProjectOpen() )
340 {
341 wxString pcbPath = aPath;
342
343 if( pcbPath.IsEmpty() )
344 {
345 wxFileName path = Pgm().GetSettingsManager().Prj().GetProjectFullName();
347 path.MakeAbsolute();
348 pcbPath = path.GetFullPath();
349 }
350
351 if( !m_cliBoard )
352 m_cliBoard = LoadBoard( pcbPath, true );
353
354 brd = m_cliBoard;
355 }
356 else if( Pgm().IsGUI() && Pgm().GetSettingsManager().IsProjectOpen() )
357 {
359
360 if( editFrame )
361 brd = editFrame->GetBoard();
362 }
363 else
364 {
365 brd = LoadBoard( aPath, true );
366 }
367
368 if( !brd )
369 m_reporter->Report( _( "Failed to load board\n" ), RPT_SEVERITY_ERROR );
370
371 return brd;
372}
373
374
375LSEQ PCBNEW_JOBS_HANDLER::convertLayerArg( wxString& aLayerString, BOARD* aBoard ) const
376{
377 std::map<wxString, LSET> layerUserMasks;
378 std::map<wxString, LSET> layerMasks;
379 std::map<wxString, LSET> layerGuiMasks;
380
381 // Build list of layer names and their layer mask:
382 for( PCB_LAYER_ID layer : LSET::AllLayersMask().Seq() )
383 {
384 // Add user layer name
385 if( aBoard )
386 layerUserMasks[ aBoard->GetLayerName( layer ) ] = LSET( { layer } );
387
388 // Add layer name used in pcb files
389 layerMasks[ LSET::Name( layer ) ] = LSET( { layer } );
390 // Add layer name using GUI canonical layer name
391 layerGuiMasks[ LayerName( layer ) ] = LSET( { layer } );
392 }
393
394 // Add list of grouped layer names used in pcb files
395 layerMasks[ wxT( "*" ) ] = LSET::AllLayersMask();
396 layerMasks[ wxT( "*.Cu" ) ] = LSET::AllCuMask();
397 layerMasks[ wxT( "*In.Cu" ) ] = LSET::InternalCuMask();
398 layerMasks[ wxT( "F&B.Cu" ) ] = LSET( { F_Cu, B_Cu } );
399 layerMasks[ wxT( "*.Adhes" ) ] = LSET( { B_Adhes, F_Adhes } );
400 layerMasks[ wxT( "*.Paste" ) ] = LSET( { B_Paste, F_Paste } );
401 layerMasks[ wxT( "*.Mask" ) ] = LSET( { B_Mask, F_Mask } );
402 layerMasks[ wxT( "*.SilkS" ) ] = LSET( { B_SilkS, F_SilkS } );
403 layerMasks[ wxT( "*.Fab" ) ] = LSET( { B_Fab, F_Fab } );
404 layerMasks[ wxT( "*.CrtYd" ) ] = LSET( { B_CrtYd, F_CrtYd } );
405
406 // Add list of grouped layer names using GUI canonical layer names
407 layerGuiMasks[ wxT( "*.Adhesive" ) ] = LSET( { B_Adhes, F_Adhes } );
408 layerGuiMasks[ wxT( "*.Silkscreen" ) ] = LSET( { B_SilkS, F_SilkS } );
409 layerGuiMasks[ wxT( "*.Courtyard" ) ] = LSET( { B_CrtYd, F_CrtYd } );
410
411 LSEQ layerMask;
412
413 auto pushLayers =
414 [&]( const LSET& layerSet )
415 {
416 for( PCB_LAYER_ID layer : layerSet.Seq() )
417 layerMask.push_back( layer );
418 };
419
420 if( !aLayerString.IsEmpty() )
421 {
422 wxStringTokenizer layerTokens( aLayerString, "," );
423
424 while( layerTokens.HasMoreTokens() )
425 {
426 std::string token = TO_UTF8( layerTokens.GetNextToken() );
427
428 if( layerUserMasks.contains( token ) )
429 pushLayers( layerUserMasks.at( token ) );
430 else if( layerMasks.count( token ) )
431 pushLayers( layerMasks.at( token ) );
432 else if( layerGuiMasks.count( token ) )
433 pushLayers( layerGuiMasks.at( token ) );
434 else
435 m_reporter->Report( wxString::Format( _( "Invalid layer name \"%s\"\n" ), token ) );
436 }
437 }
438
439 return layerMask;
440}
441
442
444{
445 JOB_EXPORT_PCB_3D* aStepJob = dynamic_cast<JOB_EXPORT_PCB_3D*>( aJob );
446
447 if( aStepJob == nullptr )
449
450 BOARD* brd = getBoard( aStepJob->m_filename );
451
452 if( !brd )
454
455 aJob->SetTitleBlock( brd->GetTitleBlock() );
456 brd->GetProject()->ApplyTextVars( aJob->GetVarOverrides() );
458
459 if( aStepJob->GetConfiguredOutputPath().IsEmpty() )
460 {
461 wxFileName fn = brd->GetFileName();
462 fn.SetName( fn.GetName() );
463
464 switch( aStepJob->m_format )
465 {
473 default:
474 m_reporter->Report( _( "Unknown export format" ), RPT_SEVERITY_ERROR );
475 return CLI::EXIT_CODES::ERR_UNKNOWN; // shouldnt have gotten here
476 }
477
478 aStepJob->SetWorkingOutputPath( fn.GetFullName() );
479 }
480
481 wxString outPath = aStepJob->GetFullOutputPath( brd->GetProject() );
482
483 if( !PATHS::EnsurePathExists( outPath, true ) )
484 {
485 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
487 }
488
490 {
491
492 double scale = 0.0;
493 switch ( aStepJob->m_vrmlUnits )
494 {
495 case JOB_EXPORT_PCB_3D::VRML_UNITS::MM: scale = 1.0; break;
496 case JOB_EXPORT_PCB_3D::VRML_UNITS::METERS: scale = 0.001; break;
497 case JOB_EXPORT_PCB_3D::VRML_UNITS::TENTHS: scale = 10.0 / 25.4; break;
498 case JOB_EXPORT_PCB_3D::VRML_UNITS::INCH: scale = 1.0 / 25.4; break;
499 }
500
501 EXPORTER_VRML vrmlExporter( brd );
502 wxString messages;
503
504 double originX = pcbIUScale.IUTomm( aStepJob->m_3dparams.m_Origin.x );
505 double originY = pcbIUScale.IUTomm( aStepJob->m_3dparams.m_Origin.y );
506
507 if( !aStepJob->m_hasUserOrigin )
508 {
509 BOX2I bbox = brd->ComputeBoundingBox( true );
510 originX = pcbIUScale.IUTomm( bbox.GetCenter().x );
511 originY = pcbIUScale.IUTomm( bbox.GetCenter().y );
512 }
513
514 bool success = vrmlExporter.ExportVRML_File( brd->GetProject(),
515 &messages,
516 outPath,
517 scale,
519 aStepJob->m_3dparams.m_IncludeDNP,
520 !aStepJob->m_vrmlModelDir.IsEmpty(),
521 aStepJob->m_vrmlRelativePaths,
522 aStepJob->m_vrmlModelDir,
523 originX,
524 originY );
525
526 if ( success )
527 {
528 m_reporter->Report( wxString::Format( _( "Successfully exported VRML to %s" ),
529 outPath ),
531 }
532 else
533 {
534 m_reporter->Report( _( "Error exporting VRML" ), RPT_SEVERITY_ERROR );
536 }
537 }
538 else
539 {
540 EXPORTER_STEP_PARAMS params = aStepJob->m_3dparams;
541
542 switch( aStepJob->m_format )
543 {
551 default:
552 m_reporter->Report( _( "Unknown export format" ), RPT_SEVERITY_ERROR );
553 return CLI::EXIT_CODES::ERR_UNKNOWN; // shouldnt have gotten here
554 }
555
556 EXPORTER_STEP stepExporter( brd, params, m_reporter );
557 stepExporter.m_outputFile = aStepJob->GetFullOutputPath( brd->GetProject() );
558
559 if( !stepExporter.Export() )
561 }
562
563 return CLI::EXIT_CODES::OK;
564}
565
566
568{
569 JOB_PCB_RENDER* aRenderJob = dynamic_cast<JOB_PCB_RENDER*>( aJob );
570
571 if( aRenderJob == nullptr )
573
574 // Reject width and height being invalid
575 // Final bit of sanity because this can blow things up
576 if( aRenderJob->m_width <= 0 || aRenderJob->m_height <= 0 )
577 {
578 m_reporter->Report( _( "Invalid image dimensions" ), RPT_SEVERITY_ERROR );
580 }
581
582 BOARD* brd = getBoard( aRenderJob->m_filename );
583
584 if( !brd )
586
587 aJob->SetTitleBlock( brd->GetTitleBlock() );
588 brd->GetProject()->ApplyTextVars( aJob->GetVarOverrides() );
590
591 if( aRenderJob->GetConfiguredOutputPath().IsEmpty() )
592 {
593 wxFileName fn = brd->GetFileName();
594
595 switch( aRenderJob->m_format )
596 {
599 default:
600 m_reporter->Report( _( "Unknown export format" ), RPT_SEVERITY_ERROR );
601 return CLI::EXIT_CODES::ERR_UNKNOWN; // shouldnt have gotten here
602 }
603
604 // set the name to board name + "side", its lazy but its hard to generate anything truely unique
605 // incase someone is doing this in a jobset with multiple jobs, they should be setting the output themselves
606 // or we do a hash based on all the options
607 fn.SetName( wxString::Format( "%s-%d", fn.GetName(), static_cast<int>( aRenderJob->m_side ) ) );
608
609 aRenderJob->SetWorkingOutputPath( fn.GetFullName() );
610 }
611
612 wxString outPath = aRenderJob->GetFullOutputPath( brd->GetProject() );
613
614 if( !PATHS::EnsurePathExists( outPath, true ) )
615 {
616 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
618 }
619
620 BOARD_ADAPTER boardAdapter;
621
622 boardAdapter.SetBoard( brd );
623 boardAdapter.m_IsBoardView = false;
624
625 if( aRenderJob->m_appearancePreset.empty() )
626 boardAdapter.m_IsPreviewer = true; // Force display 3D models, regardless of 3D viewer options
627
629
630 if( EDA_3D_VIEWER_SETTINGS* userCfg = GetAppSettings<EDA_3D_VIEWER_SETTINGS>( "3d_viewer" ) )
631 {
632 cfg.m_Render = userCfg->m_Render;
633 cfg.m_Camera = userCfg->m_Camera;
634 cfg.m_LayerPresets = userCfg->m_LayerPresets;
635 }
636
637 if( aRenderJob->m_quality == JOB_PCB_RENDER::QUALITY::BASIC )
638 {
639 // Silkscreen is pixelated without antialiasing
641
642 cfg.m_Render.raytrace_backfloor = aRenderJob->m_floor;
643 cfg.m_Render.raytrace_post_processing = aRenderJob->m_floor;
644
646 cfg.m_Render.raytrace_reflections = false;
647 cfg.m_Render.raytrace_shadows = aRenderJob->m_floor;
648
649 // Better colors
651
652 // Tracks below soldermask are not visible without refractions
655 }
656 else if( aRenderJob->m_quality == JOB_PCB_RENDER::QUALITY::HIGH )
657 {
659 cfg.m_Render.raytrace_backfloor = true;
663 cfg.m_Render.raytrace_shadows = true;
666 }
667 else if( aRenderJob->m_quality == JOB_PCB_RENDER::QUALITY::JOB_SETTINGS )
668 {
670 cfg.m_Render.raytrace_backfloor = aRenderJob->m_floor;
673 }
674
676 aRenderJob->m_lightTopIntensity.y,
677 aRenderJob->m_lightTopIntensity.z, 1.0 );
678
680 aRenderJob->m_lightBottomIntensity.y,
681 aRenderJob->m_lightBottomIntensity.z, 1.0 );
682
684 aRenderJob->m_lightCameraIntensity.y,
685 aRenderJob->m_lightCameraIntensity.z, 1.0 );
686
687 COLOR4D lightColor( aRenderJob->m_lightSideIntensity.x,
688 aRenderJob->m_lightSideIntensity.y,
689 aRenderJob->m_lightSideIntensity.z, 1.0 );
690
692 lightColor, lightColor, lightColor, lightColor,
693 lightColor, lightColor, lightColor, lightColor,
694 };
695
696 int sideElevation = aRenderJob->m_lightSideElevation;
697
699 sideElevation, sideElevation, sideElevation, sideElevation,
700 -sideElevation, -sideElevation, -sideElevation, -sideElevation,
701 };
702
704 45, 135, 225, 315, 45, 135, 225, 315,
705 };
706
707 cfg.m_CurrentPreset = aRenderJob->m_appearancePreset;
708 boardAdapter.m_Cfg = &cfg;
709
712 && aRenderJob->m_format == JOB_PCB_RENDER::FORMAT::PNG ) )
713 {
714 boardAdapter.m_ColorOverrides[LAYER_3D_BACKGROUND_TOP] = COLOR4D( 1.0, 1.0, 1.0, 0.0 );
715 boardAdapter.m_ColorOverrides[LAYER_3D_BACKGROUND_BOTTOM] = COLOR4D( 1.0, 1.0, 1.0, 0.0 );
716 }
717
719
720 static std::map<JOB_PCB_RENDER::SIDE, VIEW3D_TYPE> s_viewCmdMap = {
721 { JOB_PCB_RENDER::SIDE::TOP, VIEW3D_TYPE::VIEW3D_TOP },
722 { JOB_PCB_RENDER::SIDE::BOTTOM, VIEW3D_TYPE::VIEW3D_BOTTOM },
723 { JOB_PCB_RENDER::SIDE::LEFT, VIEW3D_TYPE::VIEW3D_LEFT },
724 { JOB_PCB_RENDER::SIDE::RIGHT, VIEW3D_TYPE::VIEW3D_RIGHT },
725 { JOB_PCB_RENDER::SIDE::FRONT, VIEW3D_TYPE::VIEW3D_FRONT },
726 { JOB_PCB_RENDER::SIDE::BACK, VIEW3D_TYPE::VIEW3D_BACK },
727 };
728
729 PROJECTION_TYPE projection = aRenderJob->m_perspective ? PROJECTION_TYPE::PERSPECTIVE
730 : PROJECTION_TYPE::ORTHO;
731
732 wxSize windowSize( aRenderJob->m_width, aRenderJob->m_height );
733 TRACK_BALL camera( 2 * RANGE_SCALE_3D );
734
735 camera.SetProjection( projection );
736 camera.SetCurWindowSize( windowSize );
737
738 RENDER_3D_RAYTRACE_RAM raytrace( boardAdapter, camera );
739 raytrace.SetCurWindowSize( windowSize );
740
741 for( bool first = true; raytrace.Redraw( false, m_reporter, m_reporter ); first = false )
742 {
743 if( first )
744 {
745 const float cmTo3D = boardAdapter.BiuTo3dUnits() * pcbIUScale.mmToIU( 10.0 );
746
747 // First redraw resets lookat point to the board center, so set up the camera here
748 camera.ViewCommand_T1( s_viewCmdMap[aRenderJob->m_side] );
749
750 camera.SetLookAtPos_T1( camera.GetLookAtPos_T1() + SFVEC3F( aRenderJob->m_pivot.x,
751 aRenderJob->m_pivot.y,
752 aRenderJob->m_pivot.z ) * cmTo3D );
753
754 camera.Pan_T1( SFVEC3F( aRenderJob->m_pan.x, aRenderJob->m_pan.y, aRenderJob->m_pan.z ) );
755
756 camera.Zoom_T1( aRenderJob->m_zoom );
757
758 camera.RotateX_T1( DEG2RAD( aRenderJob->m_rotation.x ) );
759 camera.RotateY_T1( DEG2RAD( aRenderJob->m_rotation.y ) );
760 camera.RotateZ_T1( DEG2RAD( aRenderJob->m_rotation.z ) );
761
762 camera.Interpolate( 1.0f );
763 camera.SetT0_and_T1_current_T();
764 camera.ParametersChanged();
765 }
766 }
767
768 uint8_t* rgbaBuffer = raytrace.GetBuffer();
769 wxSize realSize = raytrace.GetRealBufferSize();
770 bool success = !!rgbaBuffer;
771
772 if( rgbaBuffer )
773 {
774 const unsigned int wxh = realSize.x * realSize.y;
775
776 unsigned char* rgbBuffer = (unsigned char*) malloc( wxh * 3 );
777 unsigned char* alphaBuffer = (unsigned char*) malloc( wxh );
778
779 unsigned char* rgbaPtr = rgbaBuffer;
780 unsigned char* rgbPtr = rgbBuffer;
781 unsigned char* alphaPtr = alphaBuffer;
782
783 for( int y = 0; y < realSize.y; y++ )
784 {
785 for( int x = 0; x < realSize.x; x++ )
786 {
787 rgbPtr[0] = rgbaPtr[0];
788 rgbPtr[1] = rgbaPtr[1];
789 rgbPtr[2] = rgbaPtr[2];
790 alphaPtr[0] = rgbaPtr[3];
791
792 rgbaPtr += 4;
793 rgbPtr += 3;
794 alphaPtr += 1;
795 }
796 }
797
798 wxImage image( realSize );
799 image.SetData( rgbBuffer );
800 image.SetAlpha( alphaBuffer );
801 image = image.Mirror( false );
802
803 image.SetOption( wxIMAGE_OPTION_QUALITY, 90 );
804 image.SaveFile( outPath, aRenderJob->m_format == JOB_PCB_RENDER::FORMAT::PNG ? wxBITMAP_TYPE_PNG
805 : wxBITMAP_TYPE_JPEG );
806 }
807
808 if( success )
809 {
810 m_reporter->Report( _( "Successfully created 3D render image" ) + wxS( "\n" ), RPT_SEVERITY_INFO );
811 return CLI::EXIT_CODES::OK;
812 }
813 else
814 {
815 m_reporter->Report( _( "Error creating 3D render image" ) + wxS( "\n" ), RPT_SEVERITY_ERROR );
817 }
818}
819
820
822{
823 JOB_EXPORT_PCB_SVG* aSvgJob = dynamic_cast<JOB_EXPORT_PCB_SVG*>( aJob );
824
825 if( aSvgJob == nullptr )
827
828 BOARD* brd = getBoard( aSvgJob->m_filename );
829
830 if( !brd )
832
833 aJob->SetTitleBlock( brd->GetTitleBlock() );
834
836 {
837 if( aSvgJob->GetConfiguredOutputPath().IsEmpty() )
838 {
839 wxFileName fn = brd->GetFileName();
840 fn.SetName( fn.GetName() );
841 fn.SetExt( GetDefaultPlotExtension( PLOT_FORMAT::SVG ) );
842
843 aSvgJob->SetWorkingOutputPath( fn.GetFullName() );
844 }
845 }
846
847 wxString outPath = aSvgJob->GetFullOutputPath( brd->GetProject() );
848
850 {
851 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
853 }
854
856 brd->GetProject()->ApplyTextVars( aJob->GetVarOverrides() );
858
859 if( aSvgJob->m_argLayers )
860 aSvgJob->m_plotLayerSequence = convertLayerArg( aSvgJob->m_argLayers.value(), brd );
861
862 if( aSvgJob->m_argCommonLayers )
863 aSvgJob->m_plotOnAllLayersSequence = convertLayerArg( aSvgJob->m_argCommonLayers.value(), brd );
864
865 if( aSvgJob->m_plotLayerSequence.size() < 1 )
866 {
867 m_reporter->Report( _( "At least one layer must be specified\n" ), RPT_SEVERITY_ERROR );
869 }
870
871 PCB_PLOT_PARAMS plotOpts;
872 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, aSvgJob, *m_reporter );
873
874 PCB_PLOTTER plotter( brd, m_reporter, plotOpts );
875
876 std::optional<wxString> layerName;
877 std::optional<wxString> sheetName;
878 std::optional<wxString> sheetPath;
879
881 {
882 if( aJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
883 layerName = aSvgJob->GetVarOverrides().at( wxT( "LAYER" ) );
884
885 if( aJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
886 sheetName = aSvgJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
887
888 if( aJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
889 sheetPath = aSvgJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
890 }
891
892 if( !plotter.Plot( outPath, aSvgJob->m_plotLayerSequence, aSvgJob->m_plotOnAllLayersSequence,
894 layerName, sheetName, sheetPath ) )
895 {
897 }
898
899 return CLI::EXIT_CODES::OK;
900}
901
902
904{
905 JOB_EXPORT_PCB_DXF* aDxfJob = dynamic_cast<JOB_EXPORT_PCB_DXF*>( aJob );
906
907 if( aDxfJob == nullptr )
909
910 BOARD* brd = getBoard( aDxfJob->m_filename );
911
912 if( !brd )
914
915 aJob->SetTitleBlock( brd->GetTitleBlock() );
917 brd->GetProject()->ApplyTextVars( aJob->GetVarOverrides() );
919
920 if( aDxfJob->m_argLayers )
921 aDxfJob->m_plotLayerSequence = convertLayerArg( aDxfJob->m_argLayers.value(), brd );
922
923 if( aDxfJob->m_argCommonLayers )
924 aDxfJob->m_plotOnAllLayersSequence = convertLayerArg( aDxfJob->m_argCommonLayers.value(), brd );
925
926 if( aDxfJob->m_plotLayerSequence.size() < 1 )
927 {
928 m_reporter->Report( _( "At least one layer must be specified\n" ), RPT_SEVERITY_ERROR );
930 }
931
933 {
934 if( aDxfJob->GetConfiguredOutputPath().IsEmpty() )
935 {
936 wxFileName fn = brd->GetFileName();
937 fn.SetName( fn.GetName() );
938 fn.SetExt( GetDefaultPlotExtension( PLOT_FORMAT::DXF ) );
939
940 aDxfJob->SetWorkingOutputPath( fn.GetFullName() );
941 }
942 }
943
944 wxString outPath = aDxfJob->GetFullOutputPath( brd->GetProject() );
945
947 {
948 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
950 }
951
952 PCB_PLOT_PARAMS plotOpts;
953 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, aDxfJob, *m_reporter);
954
955 PCB_PLOTTER plotter( brd, m_reporter, plotOpts );
956
957 std::optional<wxString> layerName;
958 std::optional<wxString> sheetName;
959 std::optional<wxString> sheetPath;
960
962 {
963 if( aJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
964 layerName = aDxfJob->GetVarOverrides().at( wxT( "LAYER" ) );
965
966 if( aJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
967 sheetName = aDxfJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
968
969 if( aJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
970 sheetPath = aDxfJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
971 }
972
973 if( !plotter.Plot( outPath, aDxfJob->m_plotLayerSequence, aDxfJob->m_plotOnAllLayersSequence,
975 layerName, sheetName, sheetPath ) )
976 {
978 }
979
980 return CLI::EXIT_CODES::OK;
981}
982
983
985{
986 bool plotAllLayersOneFile = false;
987 JOB_EXPORT_PCB_PDF* pdfJob = dynamic_cast<JOB_EXPORT_PCB_PDF*>( aJob );
988
989 if( pdfJob == nullptr )
991
992 BOARD* brd = getBoard( pdfJob->m_filename );
993
994 if( !brd )
996
997 pdfJob->SetTitleBlock( brd->GetTitleBlock() );
999 brd->GetProject()->ApplyTextVars( pdfJob->GetVarOverrides() );
1000 brd->SynchronizeProperties();
1001
1002 if( pdfJob->m_argLayers )
1003 pdfJob->m_plotLayerSequence = convertLayerArg( pdfJob->m_argLayers.value(), brd );
1004
1005 if( pdfJob->m_argCommonLayers )
1006 pdfJob->m_plotOnAllLayersSequence = convertLayerArg( pdfJob->m_argCommonLayers.value(), brd );
1007
1009 plotAllLayersOneFile = true;
1010
1011 if( pdfJob->m_plotLayerSequence.size() < 1 )
1012 {
1013 m_reporter->Report( _( "At least one layer must be specified\n" ), RPT_SEVERITY_ERROR );
1015 }
1016
1017 if( plotAllLayersOneFile && pdfJob->GetConfiguredOutputPath().IsEmpty() )
1018 {
1019 wxFileName fn = brd->GetFileName();
1020 fn.SetName( fn.GetName() );
1021 fn.SetExt( GetDefaultPlotExtension( PLOT_FORMAT::PDF ) );
1022
1023 pdfJob->SetWorkingOutputPath( fn.GetFullName() );
1024 }
1025
1026 PCB_PLOT_PARAMS plotOpts;
1027 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, pdfJob, *m_reporter );
1028
1029 // ensure this is set for this one gen mode
1030 if( plotAllLayersOneFile )
1031 plotOpts.m_PDFSingle = true;
1032
1033 PCB_PLOTTER pcbPlotter( brd, m_reporter, plotOpts );
1034
1035 wxString outPath = pdfJob->GetFullOutputPath( brd->GetProject() );
1036
1037 if( !PATHS::EnsurePathExists( outPath, plotAllLayersOneFile ) )
1038 {
1039 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1041 }
1042
1043 std::optional<wxString> layerName;
1044 std::optional<wxString> sheetName;
1045 std::optional<wxString> sheetPath;
1046
1047 if( plotAllLayersOneFile )
1048 {
1049 if( pdfJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
1050 layerName = pdfJob->GetVarOverrides().at( wxT( "LAYER" ) );
1051
1052 if( pdfJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
1053 sheetName = pdfJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
1054
1055 if( pdfJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
1056 sheetPath = pdfJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
1057 }
1058
1059
1061
1062 if( !pcbPlotter.Plot( outPath, pdfJob->m_plotLayerSequence,
1063 pdfJob->m_plotOnAllLayersSequence, false, plotAllLayersOneFile,
1064 layerName, sheetName, sheetPath ) )
1065 {
1067 }
1068
1069 return CLI::EXIT_CODES::OK;
1070}
1071
1072
1074{
1075 JOB_EXPORT_PCB_PS* psJob = dynamic_cast<JOB_EXPORT_PCB_PS*>( aJob );
1076
1077 if( psJob == nullptr )
1079
1080 BOARD* brd = getBoard( psJob->m_filename );
1081
1082 if( !brd )
1084
1085 psJob->SetTitleBlock( brd->GetTitleBlock() );
1087 brd->GetProject()->ApplyTextVars( psJob->GetVarOverrides() );
1088 brd->SynchronizeProperties();
1089
1090 if( psJob->m_argLayers )
1091 psJob->m_plotLayerSequence = convertLayerArg( psJob->m_argLayers.value(), brd );
1092
1093 if( psJob->m_argCommonLayers )
1094 psJob->m_plotOnAllLayersSequence = convertLayerArg( psJob->m_argCommonLayers.value(), brd );
1095
1096 if( psJob->m_plotLayerSequence.size() < 1 )
1097 {
1098 m_reporter->Report( _( "At least one layer must be specified\n" ), RPT_SEVERITY_ERROR );
1100 }
1101
1102 bool isSingle = psJob->m_genMode == JOB_EXPORT_PCB_PS::GEN_MODE::SINGLE;
1103
1104 if( isSingle )
1105 {
1106 if( psJob->GetConfiguredOutputPath().IsEmpty() )
1107 {
1108 wxFileName fn = brd->GetFileName();
1109 fn.SetName( fn.GetName() );
1110 fn.SetExt( GetDefaultPlotExtension( PLOT_FORMAT::POST ) );
1111
1112 psJob->SetWorkingOutputPath( fn.GetFullName() );
1113 }
1114 }
1115
1116 wxString outPath = psJob->GetFullOutputPath( brd->GetProject() );
1117
1118 if( !PATHS::EnsurePathExists( outPath, isSingle ) )
1119 {
1120 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1122 }
1123
1124 PCB_PLOT_PARAMS plotOpts;
1125 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, psJob, *m_reporter );
1126
1127 PCB_PLOTTER pcbPlotter( brd, m_reporter, plotOpts );
1128
1129 std::optional<wxString> layerName;
1130 std::optional<wxString> sheetName;
1131 std::optional<wxString> sheetPath;
1132
1133 if( isSingle )
1134 {
1135 if( aJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
1136 layerName = psJob->GetVarOverrides().at( wxT( "LAYER" ) );
1137
1138 if( aJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
1139 sheetName = psJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
1140
1141 if( aJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
1142 sheetPath = psJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
1143 }
1144
1146
1147 if( !pcbPlotter.Plot( outPath, psJob->m_plotLayerSequence, psJob->m_plotOnAllLayersSequence, false, isSingle,
1148 layerName, sheetName, sheetPath ) )
1149 {
1151 }
1152
1153 return CLI::EXIT_CODES::OK;
1154}
1155
1156
1158{
1159 int exitCode = CLI::EXIT_CODES::OK;
1160 JOB_EXPORT_PCB_GERBERS* aGerberJob = dynamic_cast<JOB_EXPORT_PCB_GERBERS*>( aJob );
1161
1162 if( aGerberJob == nullptr )
1164
1165 BOARD* brd = getBoard( aGerberJob->m_filename );
1166
1167 if( !brd )
1169
1170 wxString outPath = aGerberJob->GetFullOutputPath( brd->GetProject() );
1171
1172 if( !PATHS::EnsurePathExists( outPath, false ) )
1173 {
1174 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1176 }
1177
1178 aJob->SetTitleBlock( brd->GetTitleBlock() );
1179 loadOverrideDrawingSheet( brd, aGerberJob->m_drawingSheet );
1180 brd->GetProject()->ApplyTextVars( aJob->GetVarOverrides() );
1181 brd->SynchronizeProperties();
1182
1183 bool hasLayerListSpecified = false; // will be true if the user layer list is not empty
1184
1185 if( aGerberJob->m_argLayers )
1186 {
1187 if( !aGerberJob->m_argLayers.value().empty() )
1188 {
1189 aGerberJob->m_plotLayerSequence = convertLayerArg( aGerberJob->m_argLayers.value(), brd );
1190 hasLayerListSpecified = true;
1191 }
1192 else
1193 {
1195 }
1196 }
1197
1198 if( aGerberJob->m_argCommonLayers )
1199 aGerberJob->m_plotOnAllLayersSequence = convertLayerArg( aGerberJob->m_argCommonLayers.value(), brd );
1200
1201 PCB_PLOT_PARAMS boardPlotOptions = brd->GetPlotOptions();
1202 GERBER_JOBFILE_WRITER jobfile_writer( brd );
1203
1204 wxString fileExt;
1205
1206 if( aGerberJob->m_useBoardPlotParams )
1207 {
1208 // The board plot options are saved with all copper layers enabled, even those that don't
1209 // exist in the current stackup. This is done so the layers are automatically enabled in the plot
1210 // dialog when the user enables them. We need to filter out these not-enabled layers here so
1211 // we don't plot 32 layers when we only have 4, etc.
1212 LSET plotLayers = ( boardPlotOptions.GetLayerSelection() & LSET::AllNonCuMask() )
1213 | ( brd->GetEnabledLayers() & LSET::AllCuMask() );
1214 aGerberJob->m_plotLayerSequence = plotLayers.SeqStackupForPlotting();
1215 aGerberJob->m_plotOnAllLayersSequence = boardPlotOptions.GetPlotOnAllLayersSequence();
1216 }
1217 else
1218 {
1219 // default to the board enabled layers, but only if the user has not specifed a layer list
1220 // ( m_plotLayerSequence can be empty with a broken user layer list)
1221 if( aGerberJob->m_plotLayerSequence.empty() && !hasLayerListSpecified )
1223 }
1224
1225 // Ensure layers to plot are restricted to enabled layers of the board to plot
1226 LSET layersToPlot = LSET( { aGerberJob->m_plotLayerSequence } ) & brd->GetEnabledLayers();
1227
1228 for( PCB_LAYER_ID layer : layersToPlot.UIOrder() )
1229 {
1230 LSEQ plotSequence;
1231
1232 // Base layer always gets plotted first.
1233 plotSequence.push_back( layer );
1234
1235 // Now all the "include on all" layers
1236 for( PCB_LAYER_ID layer_all : aGerberJob->m_plotOnAllLayersSequence )
1237 {
1238 // Don't plot the same layer more than once;
1239 if( find( plotSequence.begin(), plotSequence.end(), layer_all ) != plotSequence.end() )
1240 continue;
1241
1242 plotSequence.push_back( layer_all );
1243 }
1244
1245 // Pick the basename from the board file
1246 wxFileName fn( brd->GetFileName() );
1247 wxString layerName = brd->GetLayerName( layer );
1248 wxString sheetName;
1249 wxString sheetPath;
1250 PCB_PLOT_PARAMS plotOpts;
1251
1252 if( aGerberJob->m_useBoardPlotParams )
1253 plotOpts = boardPlotOptions;
1254 else
1255 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, aGerberJob, *m_reporter );
1256
1257 if( plotOpts.GetUseGerberProtelExtensions() )
1258 fileExt = GetGerberProtelExtension( layer );
1259 else
1261
1262 BuildPlotFileName( &fn, outPath, layerName, fileExt );
1263 wxString fullname = fn.GetFullName();
1264
1265 if( m_progressReporter )
1266 {
1267 m_progressReporter->AdvancePhase( wxString::Format( _( "Exporting %s" ), fullname ) );
1269 }
1270
1271 jobfile_writer.AddGbrFile( layer, fullname );
1272
1273 if( aJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
1274 layerName = aJob->GetVarOverrides().at( wxT( "LAYER" ) );
1275
1276 if( aJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
1277 sheetName = aJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
1278
1279 if( aJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
1280 sheetPath = aJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
1281
1282 // We are feeding it one layer at the start here to silence a logic check
1283 GERBER_PLOTTER* plotter;
1284 {
1286 plotter = (GERBER_PLOTTER*) StartPlotBoard( brd, &plotOpts, layer, layerName,
1287 fn.GetFullPath(), sheetName, sheetPath );
1288 }
1289
1290 if( plotter )
1291 {
1292 m_reporter->Report( wxString::Format( _( "Plotted to '%s'.\n" ), fn.GetFullPath() ),
1295 PlotBoardLayers( brd, plotter, plotSequence, plotOpts );
1296 plotter->EndPlot();
1297 }
1298 else
1299 {
1300 m_reporter->Report( wxString::Format( _( "Failed to plot to '%s'.\n" ), fn.GetFullPath() ),
1303 }
1304
1305 delete plotter;
1306 }
1307
1308 if( aGerberJob->m_createJobsFile )
1309 {
1310 wxFileName fn( brd->GetFileName() );
1311
1312 // Build gerber job file from basename
1313 BuildPlotFileName( &fn, outPath, wxT( "job" ), FILEEXT::GerberJobFileExtension );
1314 jobfile_writer.CreateJobFile( fn.GetFullPath() );
1315 }
1316
1317 return exitCode;
1318}
1319
1320
1322{
1323 JOB_EXPORT_PCB_GENCAD* aGencadJob = dynamic_cast<JOB_EXPORT_PCB_GENCAD*>( aJob );
1324
1325 if( aGencadJob == nullptr )
1327
1328 BOARD* brd = LoadBoard( aGencadJob->m_filename, true ); // Ensure m_board is of type BOARD*
1329
1330 if( brd == nullptr )
1332
1333 GENCAD_EXPORTER exporter( brd );
1334
1335 VECTOR2I GencadOffset;
1336 VECTOR2I auxOrigin = brd->GetDesignSettings().GetAuxOrigin();
1337 GencadOffset.x = aGencadJob->m_useDrillOrigin ? auxOrigin.x : 0;
1338 GencadOffset.y = aGencadJob->m_useDrillOrigin ? auxOrigin.y : 0;
1339
1340 exporter.FlipBottomPads( aGencadJob->m_flipBottomPads );
1341 exporter.UsePinNamesUnique( aGencadJob->m_useUniquePins );
1342 exporter.UseIndividualShapes( aGencadJob->m_useIndividualShapes );
1343 exporter.SetPlotOffet( GencadOffset );
1344 exporter.StoreOriginCoordsInFile( aGencadJob->m_storeOriginCoords );
1345
1346 if( aGencadJob->GetConfiguredOutputPath().IsEmpty() )
1347 {
1348 wxFileName fn = brd->GetFileName();
1349 fn.SetName( fn.GetName() );
1350 fn.SetExt( FILEEXT::GencadFileExtension );
1351
1352 aGencadJob->SetWorkingOutputPath( fn.GetFullName() );
1353 }
1354
1355 wxString outPath = aGencadJob->GetFullOutputPath( brd->GetProject() );
1356
1357 if( !PATHS::EnsurePathExists( outPath, true ) )
1358 {
1359 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1361 }
1362
1363 if( !exporter.WriteFile( outPath ) )
1364 {
1365 m_reporter->Report( wxString::Format( _( "Failed to create file '%s'.\n" ), outPath ),
1367
1369 }
1370
1371 m_reporter->Report( _( "Successfully created genCAD file\n" ), RPT_SEVERITY_INFO );
1372
1373 return CLI::EXIT_CODES::OK;
1374}
1375
1376
1378{
1379 int exitCode = CLI::EXIT_CODES::OK;
1380 JOB_EXPORT_PCB_GERBER* aGerberJob = dynamic_cast<JOB_EXPORT_PCB_GERBER*>( aJob );
1381
1382 if( aGerberJob == nullptr )
1384
1385 BOARD* brd = getBoard( aGerberJob->m_filename );
1386
1387 if( !brd )
1389
1390 aJob->SetTitleBlock( brd->GetTitleBlock() );
1391 brd->GetProject()->ApplyTextVars( aJob->GetVarOverrides() );
1392 brd->SynchronizeProperties();
1393
1394 if( aGerberJob->m_argLayers )
1395 aGerberJob->m_plotLayerSequence = convertLayerArg( aGerberJob->m_argLayers.value(), brd );
1396
1397 if( aGerberJob->m_argCommonLayers )
1398 aGerberJob->m_plotOnAllLayersSequence = convertLayerArg( aGerberJob->m_argCommonLayers.value(), brd );
1399
1400 if( aGerberJob->m_plotLayerSequence.size() < 1 )
1401 {
1402 m_reporter->Report( _( "At least one layer must be specified\n" ), RPT_SEVERITY_ERROR );
1404 }
1405
1406 if( aGerberJob->GetConfiguredOutputPath().IsEmpty() )
1407 {
1408 wxFileName fn = brd->GetFileName();
1409 fn.SetName( fn.GetName() );
1410 fn.SetExt( GetDefaultPlotExtension( PLOT_FORMAT::GERBER ) );
1411
1412 aGerberJob->SetWorkingOutputPath( fn.GetFullName() );
1413 }
1414
1415 PCB_PLOT_PARAMS plotOpts;
1416 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, aGerberJob, *m_reporter );
1417 plotOpts.SetLayerSelection( aGerberJob->m_plotLayerSequence );
1419
1421 wxString layerName;
1422 wxString sheetName;
1423 wxString sheetPath;
1424 wxString outPath = aGerberJob->GetFullOutputPath( brd->GetProject() );
1425
1426 // The first layer will be treated as the layer name for the gerber header,
1427 // the other layers will be treated equivalent to the "Plot on All Layers" option
1428 // in the GUI
1429 if( aGerberJob->m_plotLayerSequence.size() >= 1 )
1430 {
1431 layer = aGerberJob->m_plotLayerSequence.front();
1432 layerName = brd->GetLayerName( layer );
1433 }
1434
1435 if( aJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
1436 layerName = aJob->GetVarOverrides().at( wxT( "LAYER" ) );
1437
1438 if( aJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
1439 sheetName = aJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
1440
1441 if( aJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
1442 sheetPath = aJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
1443
1444 // We are feeding it one layer at the start here to silence a logic check
1445 PLOTTER* plotter = StartPlotBoard( brd, &plotOpts, layer, layerName, outPath, sheetName,
1446 sheetPath );
1447
1448 if( plotter )
1449 {
1450 PlotBoardLayers( brd, plotter, aGerberJob->m_plotLayerSequence, plotOpts );
1451 plotter->EndPlot();
1452 }
1453 else
1454 {
1455 m_reporter->Report( wxString::Format( _( "Failed to plot to '%s'.\n" ), outPath ),
1458 }
1459
1460 delete plotter;
1461
1462 return exitCode;
1463}
1464
1467
1468
1470{
1471 JOB_EXPORT_PCB_DRILL* aDrillJob = dynamic_cast<JOB_EXPORT_PCB_DRILL*>( aJob );
1472
1473 if( aDrillJob == nullptr )
1475
1476 BOARD* brd = getBoard( aDrillJob->m_filename );
1477
1478 if( !brd )
1480
1481 aJob->SetTitleBlock( brd->GetTitleBlock() );
1482
1483 wxString outPath = aDrillJob->GetFullOutputPath( brd->GetProject() );
1484
1485 if( !PATHS::EnsurePathExists( outPath ) )
1486 {
1487 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1489 }
1490
1491 std::unique_ptr<GENDRILL_WRITER_BASE> drillWriter;
1492
1494 drillWriter = std::make_unique<EXCELLON_WRITER>( brd );
1495 else
1496 drillWriter = std::make_unique<GERBER_WRITER>( brd );
1497
1498 VECTOR2I offset;
1499
1501 offset = VECTOR2I( 0, 0 );
1502 else
1503 offset = brd->GetDesignSettings().GetAuxOrigin();
1504
1505 PLOT_FORMAT mapFormat = PLOT_FORMAT::PDF;
1506
1507 switch( aDrillJob->m_mapFormat )
1508 {
1509 case JOB_EXPORT_PCB_DRILL::MAP_FORMAT::POSTSCRIPT: mapFormat = PLOT_FORMAT::POST; break;
1510 case JOB_EXPORT_PCB_DRILL::MAP_FORMAT::GERBER_X2: mapFormat = PLOT_FORMAT::GERBER; break;
1511 case JOB_EXPORT_PCB_DRILL::MAP_FORMAT::DXF: mapFormat = PLOT_FORMAT::DXF; break;
1512 case JOB_EXPORT_PCB_DRILL::MAP_FORMAT::SVG: mapFormat = PLOT_FORMAT::SVG; break;
1513 default:
1514 case JOB_EXPORT_PCB_DRILL::MAP_FORMAT::PDF: mapFormat = PLOT_FORMAT::PDF; break;
1515 }
1516
1518 {
1520 switch( aDrillJob->m_zeroFormat )
1521 {
1524 break;
1527 break;
1530 break;
1532 default:
1534 break;
1535 }
1536
1537 DRILL_PRECISION precision;
1538
1540 precision = precisionListForInches;
1541 else
1542 precision = precisionListForMetric;
1543
1544 EXCELLON_WRITER* excellonWriter = dynamic_cast<EXCELLON_WRITER*>( drillWriter.get() );
1545
1546 if( excellonWriter == nullptr )
1548
1549 excellonWriter->SetFormat( aDrillJob->m_drillUnits == JOB_EXPORT_PCB_DRILL::DRILL_UNITS::MM,
1550 zeroFmt, precision.m_Lhs, precision.m_Rhs );
1551 excellonWriter->SetOptions( aDrillJob->m_excellonMirrorY,
1552 aDrillJob->m_excellonMinimalHeader,
1553 offset, aDrillJob->m_excellonCombinePTHNPTH );
1554 excellonWriter->SetRouteModeForOvalHoles( aDrillJob->m_excellonOvalDrillRoute );
1555 excellonWriter->SetMapFileFormat( mapFormat );
1556
1557 if( !excellonWriter->CreateDrillandMapFilesSet( outPath, true, aDrillJob->m_generateMap,
1558 m_reporter ) )
1559 {
1561 }
1562 }
1564 {
1565 GERBER_WRITER* gerberWriter = dynamic_cast<GERBER_WRITER*>( drillWriter.get() );
1566
1567 if( gerberWriter == nullptr )
1569
1570 // Set gerber precision: only 5 or 6 digits for mantissa are allowed
1571 // (SetFormat() accept 5 or 6, and any other value set the precision to 5)
1572 // the integer part precision is always 4, and units always mm
1573 gerberWriter->SetFormat( aDrillJob->m_gerberPrecision );
1574 gerberWriter->SetOptions( offset );
1575 gerberWriter->SetMapFileFormat( mapFormat );
1576
1577 if( !gerberWriter->CreateDrillandMapFilesSet( outPath, true, aDrillJob->m_generateMap,
1578 aDrillJob->m_generateTenting, m_reporter ) )
1579 {
1581 }
1582 }
1583
1584 return CLI::EXIT_CODES::OK;
1585}
1586
1587
1589{
1590 JOB_EXPORT_PCB_POS* aPosJob = dynamic_cast<JOB_EXPORT_PCB_POS*>( aJob );
1591
1592 if( aPosJob == nullptr )
1594
1595 BOARD* brd = getBoard( aPosJob->m_filename );
1596
1597 if( !brd )
1599
1600 aJob->SetTitleBlock( brd->GetTitleBlock() );
1601
1602 if( aPosJob->GetConfiguredOutputPath().IsEmpty() )
1603 {
1604 wxFileName fn = brd->GetFileName();
1605 fn.SetName( fn.GetName() );
1606
1609 else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::CSV )
1610 fn.SetExt( FILEEXT::CsvFileExtension );
1611 else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::GERBER )
1612 fn.SetExt( FILEEXT::GerberFileExtension );
1613
1614 aPosJob->SetWorkingOutputPath( fn.GetFullName() );
1615 }
1616
1617 wxString outPath = aPosJob->GetFullOutputPath( brd->GetProject() );
1618
1619 if( !PATHS::EnsurePathExists( outPath, true ) )
1620 {
1621 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1623 }
1624
1627 {
1628 wxFileName fn( outPath );
1629 wxString baseName = fn.GetName();
1630
1631 auto exportPlaceFile =
1632 [&]( bool frontSide, bool backSide, const wxString& curr_outPath ) -> bool
1633 {
1634 FILE* file = wxFopen( curr_outPath, wxS( "wt" ) );
1635 wxCHECK( file, false );
1636
1637 PLACE_FILE_EXPORTER exporter( brd,
1639 aPosJob->m_smdOnly,
1641 aPosJob->m_excludeDNP,
1642 frontSide,
1643 backSide,
1646 aPosJob->m_negateBottomX );
1647
1648 std::string data = exporter.GenPositionData();
1649 fputs( data.c_str(), file );
1650 fclose( file );
1651
1652 return true;
1653 };
1654
1655 if( aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH && !aPosJob->m_singleFile )
1656 {
1657 fn.SetName( PLACE_FILE_EXPORTER::DecorateFilename( baseName, true, false ) );
1658
1659 if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::CSV && !aPosJob->m_nakedFilename )
1660 fn.SetName( fn.GetName() + wxT( "-" ) + FILEEXT::FootprintPlaceFileExtension );
1661
1662 if( exportPlaceFile( true, false, fn.GetFullPath() ) )
1663 {
1664 m_reporter->Report( wxString::Format( _( "Wrote front position data to '%s'.\n" ),
1665 fn.GetFullPath() ),
1667
1668 aPosJob->AddOutput( fn.GetFullPath() );
1669 }
1670 else
1671 {
1673 }
1674
1675 fn.SetName( PLACE_FILE_EXPORTER::DecorateFilename( baseName, false, true ) );
1676
1677 if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::CSV && !aPosJob->m_nakedFilename )
1678 fn.SetName( fn.GetName() + wxT( "-" ) + FILEEXT::FootprintPlaceFileExtension );
1679
1680 if( exportPlaceFile( false, true, fn.GetFullPath() ) )
1681 {
1682 m_reporter->Report( wxString::Format( _( "Wrote back position data to '%s'.\n" ),
1683 fn.GetFullPath() ),
1685
1686 aPosJob->AddOutput( fn.GetFullPath() );
1687 }
1688 else
1689 {
1691 }
1692 }
1693 else
1694 {
1695 bool front = aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::FRONT
1697
1698 bool back = aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BACK
1700
1701 if( !aPosJob->m_nakedFilename )
1702 {
1703 fn.SetName( PLACE_FILE_EXPORTER::DecorateFilename( fn.GetName(), front, back ) );
1704
1706 fn.SetName( fn.GetName() + wxT( "-" ) + FILEEXT::FootprintPlaceFileExtension );
1707 }
1708
1709 if( exportPlaceFile( front, back, fn.GetFullPath() ) )
1710 {
1711 m_reporter->Report( wxString::Format( _( "Wrote position data to '%s'.\n" ),
1712 fn.GetFullPath() ),
1714
1715 aPosJob->AddOutput( fn.GetFullPath() );
1716 }
1717 else
1718 {
1720 }
1721 }
1722 }
1723 else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::GERBER )
1724 {
1725 PLACEFILE_GERBER_WRITER exporter( brd );
1726 PCB_LAYER_ID gbrLayer = F_Cu;
1727 wxString outPath_base = outPath;
1728
1730 || aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH )
1731 {
1732 if( aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH || !aPosJob->m_nakedFilename )
1733 outPath = exporter.GetPlaceFileName( outPath, gbrLayer );
1734
1735 if( exporter.CreatePlaceFile( outPath, gbrLayer, aPosJob->m_gerberBoardEdge, aPosJob->m_excludeDNP ) >= 0 )
1736 {
1737 m_reporter->Report( wxString::Format( _( "Wrote front position data to '%s'.\n" ), outPath ),
1739
1740 aPosJob->AddOutput( outPath );
1741 }
1742 else
1743 {
1745 }
1746 }
1747
1749 || aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH )
1750 {
1751 gbrLayer = B_Cu;
1752
1753 outPath = outPath_base;
1754
1755 if( aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH || !aPosJob->m_nakedFilename )
1756 outPath = exporter.GetPlaceFileName( outPath, gbrLayer );
1757
1758 if( exporter.CreatePlaceFile( outPath, gbrLayer, aPosJob->m_gerberBoardEdge, aPosJob->m_excludeDNP ) >= 0 )
1759 {
1760 m_reporter->Report( wxString::Format( _( "Wrote back position data to '%s'.\n" ), outPath ),
1762
1763 aPosJob->AddOutput( outPath );
1764 }
1765 else
1766 {
1768 }
1769 }
1770 }
1771
1772 return CLI::EXIT_CODES::OK;
1773}
1774
1775
1777{
1778 JOB_FP_UPGRADE* upgradeJob = dynamic_cast<JOB_FP_UPGRADE*>( aJob );
1779
1780 if( upgradeJob == nullptr )
1782
1784
1785 if( !upgradeJob->m_outputLibraryPath.IsEmpty() )
1786 {
1787 if( wxFile::Exists( upgradeJob->m_outputLibraryPath )
1788 || wxDir::Exists( upgradeJob->m_outputLibraryPath) )
1789 {
1790 m_reporter->Report( _( "Output path must not conflict with existing path\n" ),
1793 }
1794 }
1795 else if( fileType != PCB_IO_MGR::KICAD_SEXP )
1796 {
1797 m_reporter->Report( _( "Output path must be specified to convert legacy and non-KiCad libraries\n" ),
1799
1801 }
1802
1804 {
1805 if( !wxDir::Exists( upgradeJob->m_libraryPath ) )
1806 {
1807 m_reporter->Report( _( "Footprint library path does not exist or is not accessible\n" ),
1810 }
1811
1813 FP_CACHE fpLib( &pcb_io, upgradeJob->m_libraryPath );
1814
1815 try
1816 {
1817 fpLib.Load();
1818 }
1819 catch( ... )
1820 {
1821 m_reporter->Report( _( "Unable to load library\n" ), RPT_SEVERITY_ERROR );
1823 }
1824
1825 if( m_progressReporter )
1827
1828 bool shouldSave = upgradeJob->m_force;
1829
1830 for( const auto& footprint : fpLib.GetFootprints() )
1831 {
1832 if( footprint.second->GetFootprint()->GetFileFormatVersionAtLoad() < SEXPR_BOARD_FILE_VERSION )
1833 shouldSave = true;
1834 }
1835
1836 if( shouldSave )
1837 {
1838 try
1839 {
1840 if( !upgradeJob->m_outputLibraryPath.IsEmpty() )
1841 fpLib.SetPath( upgradeJob->m_outputLibraryPath );
1842
1843 fpLib.Save();
1844 }
1845 catch( ... )
1846 {
1847 m_reporter->Report( _( "Unable to save library\n" ), RPT_SEVERITY_ERROR );
1849 }
1850 }
1851 else
1852 {
1853 m_reporter->Report( _( "Footprint library was not updated\n" ), RPT_SEVERITY_ERROR );
1854 }
1855 }
1856 else
1857 {
1858 if( !PCB_IO_MGR::ConvertLibrary( nullptr, upgradeJob->m_libraryPath,
1859 upgradeJob->m_outputLibraryPath, nullptr /* REPORTER */ ) )
1860 {
1861 m_reporter->Report( ( "Unable to convert library\n" ), RPT_SEVERITY_ERROR );
1863 }
1864 }
1865
1866 return CLI::EXIT_CODES::OK;
1867}
1868
1869
1871{
1872 JOB_FP_EXPORT_SVG* svgJob = dynamic_cast<JOB_FP_EXPORT_SVG*>( aJob );
1873
1874 if( svgJob == nullptr )
1876
1878 FP_CACHE fpLib( &pcb_io, svgJob->m_libraryPath );
1879
1880 if( svgJob->m_argLayers )
1881 {
1882 if( !svgJob->m_argLayers.value().empty() )
1883 svgJob->m_plotLayerSequence = convertLayerArg( svgJob->m_argLayers.value(), nullptr );
1884 else
1886 }
1887
1888 try
1889 {
1890 fpLib.Load();
1891 }
1892 catch( ... )
1893 {
1894 m_reporter->Report( _( "Unable to load library\n" ), RPT_SEVERITY_ERROR );
1896 }
1897
1898 wxString outPath = svgJob->GetFullOutputPath( nullptr );
1899
1900 if( !PATHS::EnsurePathExists( outPath, true ) )
1901 {
1902 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1904 }
1905
1906 int exitCode = CLI::EXIT_CODES::OK;
1907 bool singleFpPlotted = false;
1908
1909 for( const auto& [fpName, fpCacheEntry] : fpLib.GetFootprints() )
1910 {
1911 if( m_progressReporter )
1912 {
1913 m_progressReporter->AdvancePhase( wxString::Format( _( "Exporting %s" ), fpName ) );
1915 }
1916
1917 if( !svgJob->m_footprint.IsEmpty() )
1918 {
1919 // skip until we find the right footprint
1920 if( fpName != svgJob->m_footprint )
1921 continue;
1922 else
1923 singleFpPlotted = true;
1924 }
1925
1926 exitCode = doFpExportSvg( svgJob, fpCacheEntry->GetFootprint().get() );
1927
1928 if( exitCode != CLI::EXIT_CODES::OK )
1929 break;
1930 }
1931
1932 if( !svgJob->m_footprint.IsEmpty() && !singleFpPlotted )
1933 {
1934 m_reporter->Report( _( "The given footprint could not be found to export." ) + wxS( "\n" ),
1936 }
1937
1938 return CLI::EXIT_CODES::OK;
1939}
1940
1941
1943{
1944 // the hack for now is we create fake boards containing the footprint and plot the board
1945 // until we refactor better plot api later
1946 std::unique_ptr<BOARD> brd;
1947 brd.reset( CreateEmptyBoard() );
1948 brd->GetProject()->ApplyTextVars( aSvgJob->GetVarOverrides() );
1949 brd->SynchronizeProperties();
1950
1951 FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( aFootprint->Clone() );
1952
1953 if( fp == nullptr )
1955
1956 fp->SetLink( niluuid );
1957 fp->SetFlags( IS_NEW );
1958 fp->SetParent( brd.get() );
1959
1960 for( PAD* pad : fp->Pads() )
1961 {
1962 pad->SetLocalRatsnestVisible( false );
1963 pad->SetNetCode( 0 );
1964 }
1965
1966 fp->SetOrientation( ANGLE_0 );
1967 fp->SetPosition( VECTOR2I( 0, 0 ) );
1968
1969 brd->Add( fp, ADD_MODE::INSERT, true );
1970
1971 wxFileName outputFile;
1972 outputFile.SetPath( aSvgJob->GetFullOutputPath(nullptr) );
1973 outputFile.SetName( aFootprint->GetFPID().GetLibItemName().wx_str() );
1974 outputFile.SetExt( FILEEXT::SVGFileExtension );
1975
1976 m_reporter->Report( wxString::Format( _( "Plotting footprint '%s' to '%s'\n" ),
1977 aFootprint->GetFPID().GetLibItemName().wx_str(),
1978 outputFile.GetFullPath() ),
1980
1981 PCB_PLOT_PARAMS plotOpts;
1982 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, aSvgJob, *m_reporter );
1983
1984 // always fixed for the svg plot
1985 plotOpts.SetPlotFrameRef( false );
1986 plotOpts.SetSvgFitPageToBoard( true );
1987 plotOpts.SetMirror( false );
1988 plotOpts.SetSkipPlotNPTH_Pads( false );
1989
1990 if( plotOpts.GetSketchPadsOnFabLayers() )
1991 {
1992 plotOpts.SetPlotPadNumbers( true );
1993 }
1994
1995 PCB_PLOTTER plotter( brd.get(), m_reporter, plotOpts );
1996
1997 if( !plotter.Plot( outputFile.GetFullPath(),
1998 aSvgJob->m_plotLayerSequence,
2000 false,
2001 true,
2002 wxEmptyString, wxEmptyString,
2003 wxEmptyString ) )
2004 {
2005 m_reporter->Report( _( "Error creating svg file" ) + wxS( "\n" ), RPT_SEVERITY_ERROR );
2007 }
2008
2009 return CLI::EXIT_CODES::OK;
2010}
2011
2012
2014{
2015 JOB_PCB_DRC* drcJob = dynamic_cast<JOB_PCB_DRC*>( aJob );
2016
2017 if( drcJob == nullptr )
2019
2020 BOARD* brd = getBoard( drcJob->m_filename );
2021
2022 if( !brd )
2024
2025 aJob->SetTitleBlock( brd->GetTitleBlock() );
2026 brd->GetProject()->ApplyTextVars( aJob->GetVarOverrides() );
2027 brd->SynchronizeProperties();
2028
2029 if( drcJob->GetConfiguredOutputPath().IsEmpty() )
2030 {
2031 wxFileName fn = brd->GetFileName();
2032 fn.SetName( fn.GetName() + wxS( "-drc" ) );
2033
2035 fn.SetExt( FILEEXT::JsonFileExtension );
2036 else
2037 fn.SetExt( FILEEXT::ReportFileExtension );
2038
2039 drcJob->SetWorkingOutputPath( fn.GetFullName() );
2040 }
2041
2042 wxString outPath = drcJob->GetFullOutputPath( brd->GetProject() );
2043
2044 if( !PATHS::EnsurePathExists( outPath, true ) )
2045 {
2046 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
2048 }
2049
2050 EDA_UNITS units;
2051
2052 switch( drcJob->m_units )
2053 {
2054 case JOB_PCB_DRC::UNITS::INCH: units = EDA_UNITS::INCH; break;
2055 case JOB_PCB_DRC::UNITS::MILS: units = EDA_UNITS::MILS; break;
2056 case JOB_PCB_DRC::UNITS::MM: units = EDA_UNITS::MM; break;
2057 default: units = EDA_UNITS::MM; break;
2058 }
2059
2060 std::shared_ptr<DRC_ENGINE> drcEngine = brd->GetDesignSettings().m_DRCEngine;
2061 std::unique_ptr<NETLIST> netlist = std::make_unique<NETLIST>();
2062
2063 drcEngine->SetDrawingSheet( getDrawingSheetProxyView( brd ) );
2064
2065 // BOARD_COMMIT uses TOOL_MANAGER to grab the board internally so we must give it one
2066 TOOL_MANAGER* toolManager = new TOOL_MANAGER;
2067 toolManager->SetEnvironment( brd, nullptr, nullptr, Kiface().KifaceSettings(), nullptr );
2068
2069 BOARD_COMMIT commit( toolManager );
2070 bool checkParity = drcJob->m_parity;
2071 std::string netlist_str;
2072
2073 if( checkParity )
2074 {
2075 wxString annotateMsg = _( "Schematic parity tests require a fully annotated schematic." );
2076 netlist_str = annotateMsg;
2077
2078 // The KIFACE_NETLIST_SCHEMATIC function has some broken-ness that the schematic
2079 // frame's version does not, but it is the only one that works in CLI, so we use it
2080 // if we don't have the sch frame open.
2081 // TODO: clean this up, see https://gitlab.com/kicad/code/kicad/-/issues/19929
2082 if( m_kiway->Player( FRAME_SCH, false ) )
2083 {
2085 }
2086 else
2087 {
2088 wxFileName schematicPath( drcJob->m_filename );
2089 schematicPath.SetExt( FILEEXT::KiCadSchematicFileExtension );
2090
2091 if( !schematicPath.Exists() )
2092 schematicPath.SetExt( FILEEXT::LegacySchematicFileExtension );
2093
2094 if( !schematicPath.Exists() )
2095 {
2096 m_reporter->Report( _( "Failed to fetch schematic netlist for parity tests.\n" ),
2098 checkParity = false;
2099 }
2100 else
2101 {
2102 typedef bool ( *NETLIST_FN_PTR )( const wxString&, std::string& );
2104 NETLIST_FN_PTR netlister =
2105 (NETLIST_FN_PTR) eeschema->IfaceOrAddress( KIFACE_NETLIST_SCHEMATIC );
2106 ( *netlister )( schematicPath.GetFullPath(), netlist_str );
2107 }
2108 }
2109
2110 if( netlist_str == annotateMsg )
2111 {
2112 m_reporter->Report( wxString( netlist_str ) + wxT( "\n" ), RPT_SEVERITY_ERROR );
2113 checkParity = false;
2114 }
2115 }
2116
2117 if( checkParity )
2118 {
2119 try
2120 {
2121 STRING_LINE_READER* lineReader = new STRING_LINE_READER( netlist_str,
2122 _( "Eeschema netlist" ) );
2123 KICAD_NETLIST_READER netlistReader( lineReader, netlist.get() );
2124
2125 netlistReader.LoadNetlist();
2126 }
2127 catch( const IO_ERROR& )
2128 {
2129 m_reporter->Report( _( "Failed to fetch schematic netlist for parity tests.\n" ),
2131 checkParity = false;
2132 }
2133
2134 drcEngine->SetSchematicNetlist( netlist.get() );
2135 }
2136
2137 drcEngine->SetProgressReporter( m_progressReporter );
2138 drcEngine->SetViolationHandler(
2139 [&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
2140 DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
2141 {
2142 PCB_MARKER* marker = new PCB_MARKER( aItem, aPos, aLayer );
2143 commit.Add( marker );
2144 } );
2145
2146 brd->RecordDRCExclusions();
2147 brd->DeleteMARKERs( true, true );
2148 drcEngine->RunTests( units, drcJob->m_reportAllTrackErrors, checkParity );
2149 drcEngine->ClearViolationHandler();
2150
2151 commit.Push( _( "DRC" ), SKIP_UNDO | SKIP_SET_DIRTY );
2152
2153 // Update the exclusion status on any excluded markers that still exist.
2154 brd->ResolveDRCExclusions( false );
2155
2156 std::shared_ptr<DRC_ITEMS_PROVIDER> markersProvider = std::make_shared<DRC_ITEMS_PROVIDER>(
2158
2159 std::shared_ptr<DRC_ITEMS_PROVIDER> ratsnestProvider =
2160 std::make_shared<DRC_ITEMS_PROVIDER>( brd, MARKER_BASE::MARKER_RATSNEST );
2161
2162 std::shared_ptr<DRC_ITEMS_PROVIDER> fpWarningsProvider =
2163 std::make_shared<DRC_ITEMS_PROVIDER>( brd, MARKER_BASE::MARKER_PARITY );
2164
2165 markersProvider->SetSeverities( drcJob->m_severity );
2166 ratsnestProvider->SetSeverities( drcJob->m_severity );
2167 fpWarningsProvider->SetSeverities( drcJob->m_severity );
2168
2169 m_reporter->Report( wxString::Format( _( "Found %d violations\n" ),
2170 markersProvider->GetCount() ),
2172 m_reporter->Report( wxString::Format( _( "Found %d unconnected items\n" ),
2173 ratsnestProvider->GetCount() ),
2175
2176 if( checkParity )
2177 {
2178 m_reporter->Report( wxString::Format( _( "Found %d schematic parity issues\n" ),
2179 fpWarningsProvider->GetCount() ),
2181 }
2182
2183 DRC_REPORT reportWriter( brd, units, markersProvider, ratsnestProvider, fpWarningsProvider );
2184
2185 bool wroteReport = false;
2186
2188 wroteReport = reportWriter.WriteJsonReport( outPath );
2189 else
2190 wroteReport = reportWriter.WriteTextReport( outPath );
2191
2192 if( !wroteReport )
2193 {
2194 m_reporter->Report( wxString::Format( _( "Unable to save DRC report to %s\n" ), outPath ),
2197 }
2198
2199 m_reporter->Report( wxString::Format( _( "Saved DRC Report to %s\n" ), outPath ),
2201
2202 if( drcJob->m_exitCodeViolations )
2203 {
2204 if( markersProvider->GetCount() > 0 || ratsnestProvider->GetCount() > 0
2205 || fpWarningsProvider->GetCount() > 0 )
2206 {
2208 }
2209 }
2210
2212}
2213
2214
2216{
2217 JOB_EXPORT_PCB_IPC2581* job = dynamic_cast<JOB_EXPORT_PCB_IPC2581*>( aJob );
2218
2219 if( job == nullptr )
2221
2222 BOARD* brd = getBoard( job->m_filename );
2223
2224 if( !brd )
2226
2227 aJob->SetTitleBlock( brd->GetTitleBlock() );
2228
2229 if( job->GetConfiguredOutputPath().IsEmpty() )
2230 {
2231 wxFileName fn = brd->GetFileName();
2232 fn.SetName( fn.GetName() );
2233 fn.SetExt( FILEEXT::Ipc2581FileExtension );
2234
2235 job->SetWorkingOutputPath( fn.GetName() );
2236 }
2237
2238 wxString outPath = job->GetFullOutputPath( brd->GetProject() );
2239
2240 if( !PATHS::EnsurePathExists( outPath, true ) )
2241 {
2242 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
2244 }
2245
2246 std::map<std::string, UTF8> props;
2247 props["units"] = job->m_units == JOB_EXPORT_PCB_IPC2581::IPC2581_UNITS::MM ? "mm" : "inch";
2248 props["sigfig"] = wxString::Format( "%d", job->m_precision );
2249 props["version"] = job->m_version == JOB_EXPORT_PCB_IPC2581::IPC2581_VERSION::C ? "C" : "B";
2250 props["OEMRef"] = job->m_colInternalId;
2251 props["mpn"] = job->m_colMfgPn;
2252 props["mfg"] = job->m_colMfg;
2253 props["dist"] = job->m_colDist;
2254 props["distpn"] = job->m_colDistPn;
2255
2256 wxString tempFile = wxFileName::CreateTempFileName( wxS( "pcbnew_ipc" ) );
2257 try
2258 {
2260 pi->SetProgressReporter( m_progressReporter );
2261 pi->SaveBoard( tempFile, brd, &props );
2262 }
2263 catch( const IO_ERROR& ioe )
2264 {
2265 m_reporter->Report( wxString::Format( _( "Error generating IPC-2581 file '%s'.\n%s" ),
2266 job->m_filename,
2267 ioe.What() ),
2269
2270 wxRemoveFile( tempFile );
2271
2273 }
2274
2275 if( job->m_compress )
2276 {
2277 wxFileName tempfn = outPath;
2278 tempfn.SetExt( FILEEXT::Ipc2581FileExtension );
2279 wxFileName zipfn = tempFile;
2280 zipfn.SetExt( "zip" );
2281
2282 {
2283 wxFFileOutputStream fnout( zipfn.GetFullPath() );
2284 wxZipOutputStream zip( fnout );
2285 wxFFileInputStream fnin( tempFile );
2286
2287 zip.PutNextEntry( tempfn.GetFullName() );
2288 fnin.Read( zip );
2289 }
2290
2291 wxRemoveFile( tempFile );
2292 tempFile = zipfn.GetFullPath();
2293 }
2294
2295 // If save succeeded, replace the original with what we just wrote
2296 if( !wxRenameFile( tempFile, outPath ) )
2297 {
2298 m_reporter->Report( wxString::Format( _( "Error generating IPC-2581 file '%s'.\n"
2299 "Failed to rename temporary file '%s." ),
2300 outPath,
2301 tempFile ),
2303 }
2304
2306}
2307
2308
2310{
2311 JOB_EXPORT_PCB_IPCD356* job = dynamic_cast<JOB_EXPORT_PCB_IPCD356*>( aJob );
2312
2313 if( job == nullptr )
2315
2316 BOARD* brd = getBoard( job->m_filename );
2317
2318 if( !brd )
2320
2321 aJob->SetTitleBlock( brd->GetTitleBlock() );
2322
2323 if( job->GetConfiguredOutputPath().IsEmpty() )
2324 {
2325 wxFileName fn = brd->GetFileName();
2326 fn.SetName( fn.GetName() );
2327 fn.SetExt( FILEEXT::IpcD356FileExtension );
2328
2329 job->SetWorkingOutputPath( fn.GetFullName() );
2330 }
2331
2332 wxString outPath = job->GetFullOutputPath( brd->GetProject() );
2333
2334 if( !PATHS::EnsurePathExists( outPath, true ) )
2335 {
2336 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
2338 }
2339
2340 IPC356D_WRITER exporter( brd );
2341
2342 bool success = exporter.Write( outPath );
2343
2344 if( success )
2345 {
2346 m_reporter->Report( _( "Successfully created IPC-D-356 file\n" ), RPT_SEVERITY_INFO );
2348 }
2349 else
2350 {
2351 m_reporter->Report( _( "Failed to create IPC-D-356 file\n" ), RPT_SEVERITY_ERROR );
2353 }
2354}
2355
2356
2358{
2359 JOB_EXPORT_PCB_ODB* job = dynamic_cast<JOB_EXPORT_PCB_ODB*>( aJob );
2360
2361 if( job == nullptr )
2363
2364 BOARD* brd = getBoard( job->m_filename );
2365
2366 if( !brd )
2368
2369 aJob->SetTitleBlock( brd->GetTitleBlock() );
2370
2371 wxString path = job->GetConfiguredOutputPath();
2372
2373 if( job->GetConfiguredOutputPath().IsEmpty() )
2374 {
2376 {
2377 // just basic folder name
2378 job->SetWorkingOutputPath( "odb" );
2379 }
2380 else
2381 {
2382 wxFileName fn( brd->GetFileName() );
2383 fn.SetName( fn.GetName() + wxS( "-odb" ) );
2384
2385 switch( job->m_compressionMode )
2386 {
2388 fn.SetExt( FILEEXT::ArchiveFileExtension );
2389 break;
2391 fn.SetExt( "tgz" );
2392 break;
2393 default:
2394 break;
2395 };
2396
2397 job->SetWorkingOutputPath( fn.GetFullName() );
2398 }
2399 }
2400
2402
2404}
2405
2406
2408{
2410 &aBrd->GetPageSettings(),
2411 aBrd->GetProject(),
2412 &aBrd->GetTitleBlock(),
2413 &aBrd->GetProperties() );
2414
2415 drawingSheet->SetSheetName( std::string() );
2416 drawingSheet->SetSheetPath( std::string() );
2417 drawingSheet->SetIsFirstPage( true );
2418
2419 drawingSheet->SetFileName( TO_UTF8( aBrd->GetFileName() ) );
2420
2421 return drawingSheet;
2422}
2423
2424
2425void PCBNEW_JOBS_HANDLER::loadOverrideDrawingSheet( BOARD* aBrd, const wxString& aSheetPath )
2426{
2427 // dont bother attempting to load a empty path, if there was one
2428 if( aSheetPath.IsEmpty() )
2429 return;
2430
2431 auto loadSheet =
2432 [&]( const wxString& path ) -> bool
2433 {
2436 resolver.SetProject( aBrd->GetProject() );
2438
2440 aBrd->GetProject()->GetProjectPath(),
2441 { aBrd->GetEmbeddedFiles() } );
2442 wxString msg;
2443
2444 if( !DS_DATA_MODEL::GetTheInstance().LoadDrawingSheet( filename, &msg ) )
2445 {
2446 m_reporter->Report( wxString::Format( _( "Error loading drawing sheet '%s'." ),
2447 path )
2448 + wxS( "\n" ) + msg + wxS( "\n" ),
2450 return false;
2451 }
2452
2453 return true;
2454 };
2455
2456 if( loadSheet( aSheetPath ) )
2457 return;
2458
2459 // failed loading custom path, revert back to default
2460 loadSheet( aBrd->GetProject()->GetProjectFile().m_BoardDrawingSheetFile );
2461}
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.
Definition: board_adapter.h:66
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.
Definition: board_adapter.h:73
double BiuTo3dUnits() const noexcept
Board integer units To 3D units.
bool m_IsPreviewer
true if we're in a 3D preview panel, false for the standard 3D viewer
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.
Definition: board_adapter.h:84
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:317
EMBEDDED_FILES * GetEmbeddedFiles() override
Definition: board.cpp:2628
const PAGE_INFO & GetPageSettings() const
Definition: board.h:740
void RecordDRCExclusions()
Scan existing markers and record data from any that are Excluded.
Definition: board.cpp:328
TITLE_BLOCK & GetTitleBlock()
Definition: board.h:746
BOX2I ComputeBoundingBox(bool aBoardEdgesOnly=false) const
Calculate the bounding box containing all board items (or board edge segments).
Definition: board.cpp:1822
const std::map< wxString, wxString > & GetProperties() const
Definition: board.h:393
const wxString & GetFileName() const
Definition: board.h:354
std::vector< PCB_MARKER * > ResolveDRCExclusions(bool aCreateMarkers)
Rebuild DRC markers from the serialized data in BOARD_DESIGN_SETTINGS.
Definition: board.cpp:385
const PCB_PLOT_PARAMS & GetPlotOptions() const
Definition: board.h:743
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:679
PROJECT * GetProject() const
Definition: board.h:536
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:1011
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:894
void SynchronizeProperties()
Copy the current project's text variables into the boards property cache.
Definition: board.cpp:2192
void DeleteMARKERs()
Delete all MARKERS from the board.
Definition: board.cpp:1501
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:79
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)
Definition: drc_report.cpp:114
bool WriteTextReport(const wxString &aFullFileName)
Definition: drc_report.cpp:47
Helper to handle drill precision format in excellon files.
bool LoadDrawingSheet(const wxString &aFullFileName, wxString *aMsg, bool aAppend=false)
Populate the list with a custom layout or the default layout if no custom layout is available.
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:141
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:112
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
Definition: exporter_step.h:54
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.
wxString ResolvePath(const wxString &aFileName, const wxString &aWorkingPath, std::vector< const EMBEDDED_FILES * > aEmbeddedFilesStack)
Determine the full path of the given file name.
void SetProgramBase(PGM_BASE *aBase)
Set a pointer to the application's PGM_BASE instance used to extract the local env vars.
bool SetProject(const PROJECT *aProject, bool *flgChanged=nullptr)
Set the current KiCad project directory as the first entry in the model path list.
void SetPosition(const VECTOR2I &aPos) override
Definition: footprint.cpp:2465
void SetLink(const KIID &aLink)
Definition: footprint.h:842
void SetOrientation(const EDA_ANGLE &aNewAngle)
Definition: footprint.cpp:2547
EDA_ITEM * Clone() const override
Invoke a function on all children.
Definition: footprint.cpp:2202
std::deque< PAD * > & Pads()
Definition: footprint.h:209
const LIB_ID & GetFPID() const
Definition: footprint.h:251
void SetPath(const wxString &aPath)
void Save(FOOTPRINT *aFootprintFilter=nullptr)
Save the footprint cache or a single footprint from it to disk.
boost::ptr_map< wxString, FP_CACHE_ENTRY > & GetFootprints()
Export board to GenCAD file format.
void UseIndividualShapes(bool aUnique)
Make pad shapes unique.
void UsePinNamesUnique(bool aUnique)
Make pin names unique.
void StoreOriginCoordsInFile(bool aStore)
Store origin coordinate in GenCAD file.
void FlipBottomPads(bool aFlip)
Flip pad shapes on the bottom side.
void SetPlotOffet(VECTOR2I aOffset)
Set the coordinates offset when exporting items.
bool WriteFile(const wxString &aFullFileName)
Export a GenCAD file.
void SetMapFileFormat(PLOT_FORMAT aMapFmt)
Initialize the format for the drill map file.
GERBER_JOBFILE_WRITER is a class used to create Gerber job file a Gerber job file stores info to make...
bool CreateJobFile(const wxString &aFullFilename)
Creates a Gerber job file.
void AddGbrFile(PCB_LAYER_ID aLayer, wxString &aFilename)
add a gerber file name and type in job file list
virtual bool EndPlot() override
Used to create Gerber drill files.
bool CreateDrillandMapFilesSet(const wxString &aPlotDirectory, bool aGenDrill, bool aGenMap, bool aGenTenting, REPORTER *aReporter=nullptr)
Create the full set of Excellon drill file for the board filenames are computed from the board name,...
void SetOptions(const VECTOR2I &aOffset)
Initialize internal parameters to match drill options.
void SetFormat(int aRightDigits=6)
Initialize internal parameters to match the given format.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:77
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:30
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)
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.
ODB_COMPRESSION m_compressionMode
@ ALL_LAYERS_ONE_FILE
DEPRECATED MODE.
GEN_MODE m_pdfGenMode
The background color specified in a hex string.
LSEQ m_plotOnAllLayersSequence
Used by SVG & PDF.
std::optional< wxString > m_argLayers
std::optional< wxString > m_argCommonLayers
LSEQ m_plotLayerSequence
Layers to include on all individual layer prints.
wxString m_libraryPath
wxString m_outputLibraryPath
bool m_parity
Definition: job_pcb_drc.h:33
bool m_reportAllTrackErrors
Definition: job_pcb_drc.h:32
VECTOR3D m_lightBottomIntensity
VECTOR3D m_lightTopIntensity
BG_STYLE m_bgStyle
VECTOR3D m_lightCameraIntensity
VECTOR3D m_rotation
bool m_proceduralTextures
wxString m_filename
VECTOR3D m_pivot
VECTOR3D m_lightSideIntensity
std::string m_appearancePreset
bool m_exitCodeViolations
Definition: job_rc.h:52
int m_severity
Definition: job_rc.h:49
UNITS m_units
Definition: job_rc.h:48
OUTPUT_FORMAT m_format
Definition: job_rc.h:50
wxString m_filename
Definition: job_rc.h:47
An simple container class that lets us dispatch output jobs to kifaces.
Definition: job.h:183
void AddOutput(wxString aOutputPath)
Definition: job.h:210
wxString GetFullOutputPath(PROJECT *aProject) const
Returns the full output path for the job, taking into account the configured output path,...
Definition: job.cpp:100
wxString GetConfiguredOutputPath() const
Returns the configured output path for the job.
Definition: job.h:227
void SetTitleBlock(const TITLE_BLOCK &aTitleBlock)
Definition: job.h:198
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:233
const std::map< wxString, wxString > & GetVarOverrides() const
Definition: job.h:191
Read the new s-expression based KiCad netlist format.
virtual void LoadNetlist() override
Load the contents of the netlist file into aNetlist.
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition: kiway.h:286
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:395
virtual KIFACE * KiFACE(FACE_T aFaceId, bool doLoad=true)
Return the KIFACE* given a FACE_T.
Definition: kiway.cpp:198
@ FACE_SCH
eeschema DSO
Definition: kiway.h:293
virtual void ExpressMail(FRAME_T aDestination, MAIL_T aCommand, std::string &aPayload, wxWindow *aSource=nullptr)
Send aPayload to aDestination from aSource.
Definition: kiway.cpp:499
const UTF8 & GetLibItemName() const
Definition: lib_id.h:102
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:41
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:733
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 const LSET & AllLayersMask()
Definition: lset.cpp:624
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition: lset.cpp:591
static const LSET & InternalCuMask()
Return a complete set of internal copper layers which is all Cu layers except F_Cu and B_Cu.
Definition: lset.cpp:560
static wxString Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition: lset.cpp:188
@ MARKER_DRAWING_SHEET
Definition: marker_base.h:56
Definition: pad.h:54
static bool EnsurePathExists(const wxString &aPath, bool aPathToFile=false)
Attempts to create a given path if it does not exist.
Definition: paths.cpp:484
int JobExportFpUpgrade(JOB *aJob)
DS_PROXY_VIEW_ITEM * getDrawingSheetProxyView(BOARD *aBrd)
void loadOverrideDrawingSheet(BOARD *brd, const wxString &aSheetPath)
PCBNEW_JOBS_HANDLER(KIWAY *aKiway)
BOARD * getBoard(const wxString &aPath=wxEmptyString)
LSEQ convertLayerArg(wxString &aLayerString, BOARD *aBoard) const
int JobExportRender(JOB *aJob)
int doFpExportSvg(JOB_FP_EXPORT_SVG *aSvgJob, const FOOTPRINT *aFootprint)
BOARD * GetBoard() const
The main frame for Pcbnew.
A #PLUGIN derivation for saving and loading Pcbnew s-expression formatted files.
static PCB_IO * PluginFind(PCB_FILE_T aFileType)
Return a #PLUGIN which the caller can use to import, export, save, or load design documents.
Definition: pcb_io_mgr.cpp:69
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 bool ConvertLibrary(std::map< std::string, UTF8 > *aOldFileProps, const wxString &aOldFilePath, const wxString &aNewFilePath, REPORTER *aReporter)
Convert a schematic symbol library to the latest KiCad format.
Definition: pcb_io_mgr.cpp:191
static PCB_FILE_T GuessPluginTypeFromLibPath(const wxString &aLibPath, int aCtl=0)
Return a plugin type given a footprint library's libPath.
Definition: pcb_io_mgr.cpp:136
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)
Definition: pcb_plotter.cpp:64
static void PlotJobToPlotOpts(PCB_PLOT_PARAMS &aOpts, JOB_EXPORT_PCB_PLOT *aJob, REPORTER &aReporter)
Translate a JOB to PCB_PLOT_PARAMS.
Parameters and options when plotting/printing a board.
LSEQ GetPlotOnAllLayersSequence() const
void SetSkipPlotNPTH_Pads(bool aSkip)
void SetLayerSelection(const LSET &aSelection)
void SetPlotOnAllLayersSequence(LSEQ aSeq)
void SetPlotFrameRef(bool aFlag)
void SetPlotPadNumbers(bool aFlag)
LSET GetLayerSelection() const
void SetMirror(bool aFlag)
bool GetSketchPadsOnFabLayers() const
bool m_PDFSingle
Generate a single PDF file for all layers.
void SetSvgFitPageToBoard(int aSvgFitPageToBoard)
bool GetUseGerberProtelExtensions() const
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition: pgm_base.h:125
Used to create Gerber drill files.
const wxString GetPlaceFileName(const wxString &aFullBaseFilename, PCB_LAYER_ID aLayer) const
int CreatePlaceFile(const wxString &aFullFilename, PCB_LAYER_ID aLayer, bool aIncludeBrdEdges, bool aExcludeDNP)
Create an pnp gerber file.
The ASCII format of the kicad place file is:
static wxString DecorateFilename(const wxString &aBaseName, bool aFront, bool aBack)
std::string GenPositionData()
build a string filled with the position data
Base plotter engine class.
Definition: plotter.h:121
virtual bool EndPlot()=0
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
virtual void AdvancePhase()=0
Use the next available virtual zone of the dialog progress bar.
wxString m_BoardDrawingSheetFile
PcbNew params.
Definition: project_file.h:176
static S3D_CACHE * Get3DCacheManager(PROJECT *aProject, bool updateProjDir=false)
Return a pointer to an instance of the 3D cache manager.
Definition: project_pcb.cpp:77
virtual const wxString GetProjectFullName() const
Return the full path and name of the project.
Definition: project.cpp:142
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition: project.cpp:148
virtual void ApplyTextVars(const std::map< wxString, wxString > &aVarsMap)
Applies the given var map, it will create or update existing vars.
Definition: project.cpp:103
virtual PROJECT_FILE & GetProjectFile() const
Definition: project.h:204
bool Redraw(bool aIsMoving, REPORTER *aStatusReporter, REPORTER *aWarningReporter) override
Redraw the view.
void SetCurWindowSize(const wxSize &aSize) override
Before each render, the canvas will tell the render what is the size of its windows,...
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition: reporter.h:102
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:253
Master controller class:
Definition: tool_manager.h:62
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
Definition: track_ball.cpp:125
void SetT0_and_T1_current_T() override
This will set T0 and T1 with the current values.
Definition: track_ball.cpp:138
void Interpolate(float t) override
It will update the matrix to interpolate between T0 and T1 values.
Definition: track_ball.cpp:152
wxString wx_str() const
Definition: utf8.cpp:45
T y
Definition: vector3.h:64
T z
Definition: vector3.h:65
T x
Definition: vector3.h:63
wxString GetDefaultPlotExtension(PLOT_FORMAT aFormat)
Return the default plot extension for a format.
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:194
This file is part of the common library.
static DRILL_PRECISION precisionListForInches(2, 4)
static DRILL_PRECISION precisionListForMetric(3, 3)
std::function< void(PCB_MARKER *aMarker)> DRC_CUSTOM_MARKER_HANDLER
Definition: drc_engine.h:68
#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
Definition: export_idf.cpp:53
@ 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 Ipc2581FileExtension
static const std::string GencadFileExtension
static const std::string StlFileExtension
static const std::string IpcD356FileExtension
static const std::string PlyFileExtension
static const std::string StepFileExtension
static const std::string SVGFileExtension
static const std::string VrmlFileExtension
static const std::string ArchiveFileExtension
static const std::string KiCadPcbFileExtension
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition: io_mgr.h:33
@ KIFACE_NETLIST_SCHEMATIC
Definition: kiface_ids.h:56
KIID niluuid(0)
wxString LayerName(int aLayer)
Returns the default display name for a given layer.
Definition: layer_id.cpp:31
@ LAYER_3D_BACKGROUND_TOP
Definition: layer_ids.h:541
@ LAYER_3D_BACKGROUND_BOTTOM
Definition: layer_ids.h:540
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.
BOARD * LoadBoard(const wxString &aFileName, bool aSetActive)
Loads a board from file This function identifies the file type by extension and determines the correc...
const wxString GetGerberProtelExtension(int aLayer)
Definition: pcbplot.cpp:43
void BuildPlotFileName(wxFileName *aFilename, const wxString &aOutputDir, const wxString &aSuffix, const wxString &aExtension)
Complete a plot filename.
Definition: pcbplot.cpp:379
PLOTTER * StartPlotBoard(BOARD *aBoard, const PCB_PLOT_PARAMS *aPlotOpts, int aLayer, const wxString &aLayerName, const wxString &aFullFileName, const wxString &aSheetName, const wxString &aSheetPath, const wxString &aPageName=wxT("1"), const wxString &aPageNumber=wxEmptyString, const int aPageCount=1)
Open a new plotfile using the options (and especially the format) specified in the options and prepar...
void PlotBoardLayers(BOARD *aBoard, PLOTTER *aPlotter, const LSEQ &aLayerSequence, const PCB_PLOT_PARAMS &aPlotOptions)
Plot a sequence of board layer IDs.
PGM_BASE & Pgm()
The global program "get" accessor.
Definition: pgm_base.cpp:893
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:43
#define SKIP_UNDO
Definition: sch_commit.h:41
const int scale
std::vector< FAB_LAYER_COLOR > dummy
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.
Definition: string_utils.h:429
std::vector< KIGFX::COLOR4D > raytrace_lightColor
constexpr double IUTomm(int iu) const
Definition: base_units.h:90
constexpr int mmToIU(double mm) const
Definition: base_units.h:92
Implement a participant in the KIWAY alchemy.
Definition: kiway.h:153
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