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>
97
99#include <locale_io.h>
100#include <confirm.h>
101
102
103#ifdef _WIN32
104#ifdef TRANSPARENT
105#undef TRANSPARENT
106#endif
107#endif
108
109
111 JOB_DISPATCHER( aKiway ),
112 m_cliBoard( nullptr ),
113 m_toolManager( nullptr )
114{
115 Register( "3d", std::bind( &PCBNEW_JOBS_HANDLER::JobExportStep, this, std::placeholders::_1 ),
116 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
117 {
118 JOB_EXPORT_PCB_3D* svgJob = dynamic_cast<JOB_EXPORT_PCB_3D*>( job );
119
120 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
121 false ) );
122
123 wxCHECK( svgJob && editFrame, false );
124
125 DIALOG_EXPORT_STEP dlg( editFrame, aParent, "", svgJob );
126 return dlg.ShowModal() == wxID_OK;
127 } );
128 Register( "render",
129 std::bind( &PCBNEW_JOBS_HANDLER::JobExportRender, this, std::placeholders::_1 ),
130 []( JOB* job, wxWindow* aParent ) -> bool
131 {
132 JOB_PCB_RENDER* renderJob = dynamic_cast<JOB_PCB_RENDER*>( job );
133
134 wxCHECK( renderJob, false );
135
136 DIALOG_RENDER_JOB dlg( aParent, renderJob );
137 return dlg.ShowModal() == wxID_OK;
138 } );
139 Register( "svg", std::bind( &PCBNEW_JOBS_HANDLER::JobExportSvg, this, std::placeholders::_1 ),
140 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
141 {
142 JOB_EXPORT_PCB_SVG* svgJob = dynamic_cast<JOB_EXPORT_PCB_SVG*>( job );
143
144 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
145 false ) );
146
147 wxCHECK( svgJob && editFrame, false );
148
149 DIALOG_PLOT dlg( editFrame, aParent, svgJob );
150 return dlg.ShowModal() == wxID_OK;
151 } );
152 Register( "gencad",
153 std::bind( &PCBNEW_JOBS_HANDLER::JobExportGencad, this, std::placeholders::_1 ),
154 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
155 {
156 JOB_EXPORT_PCB_GENCAD* gencadJob = dynamic_cast<JOB_EXPORT_PCB_GENCAD*>( job );
157
158 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
159 false ) );
160
161 wxCHECK( gencadJob && editFrame, false );
162
163 DIALOG_GENCAD_EXPORT_OPTIONS dlg( editFrame, gencadJob->GetSettingsDialogTitle(), gencadJob );
164 return dlg.ShowModal() == wxID_OK;
165 } );
166 Register( "dxf", std::bind( &PCBNEW_JOBS_HANDLER::JobExportDxf, this, std::placeholders::_1 ),
167 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
168 {
169 JOB_EXPORT_PCB_DXF* dxfJob = dynamic_cast<JOB_EXPORT_PCB_DXF*>( job );
170
171 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
172 false ) );
173
174 wxCHECK( dxfJob && editFrame, false );
175
176 DIALOG_PLOT dlg( editFrame, aParent, dxfJob );
177 return dlg.ShowModal() == wxID_OK;
178 } );
179 Register( "pdf", std::bind( &PCBNEW_JOBS_HANDLER::JobExportPdf, this, std::placeholders::_1 ),
180 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
181 {
182 JOB_EXPORT_PCB_PDF* pdfJob = dynamic_cast<JOB_EXPORT_PCB_PDF*>( job );
183
184 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
185 false ) );
186
187 wxCHECK( pdfJob && editFrame, false );
188
189 DIALOG_PLOT dlg( editFrame, aParent, pdfJob );
190 return dlg.ShowModal() == wxID_OK;
191 } );
192 Register( "ps", std::bind( &PCBNEW_JOBS_HANDLER::JobExportPs, this, std::placeholders::_1 ),
193 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
194 {
195 JOB_EXPORT_PCB_PS* psJob = dynamic_cast<JOB_EXPORT_PCB_PS*>( job );
196
197 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
198 false ) );
199
200 wxCHECK( psJob && editFrame, false );
201
202 DIALOG_PLOT dlg( editFrame, aParent, psJob );
203 return dlg.ShowModal() == wxID_OK;
204 } );
205 Register( "gerber",
206 std::bind( &PCBNEW_JOBS_HANDLER::JobExportGerber, this, std::placeholders::_1 ),
207 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
208 {
209 JOB_EXPORT_PCB_GERBER* gJob = dynamic_cast<JOB_EXPORT_PCB_GERBER*>( job );
210
211 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
212 false ) );
213
214 wxCHECK( gJob && editFrame, false );
215
216 DIALOG_PLOT dlg( editFrame, aParent, gJob );
217 return dlg.ShowModal() == wxID_OK;
218 } );
219 Register( "gerbers",
220 std::bind( &PCBNEW_JOBS_HANDLER::JobExportGerbers, this, std::placeholders::_1 ),
221 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
222 {
223 JOB_EXPORT_PCB_GERBERS* gJob = dynamic_cast<JOB_EXPORT_PCB_GERBERS*>( job );
224
225 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
226 false ) );
227
228 wxCHECK( gJob && editFrame, false );
229
230 DIALOG_PLOT dlg( editFrame, aParent, gJob );
231 return dlg.ShowModal() == wxID_OK;
232 } );
233 Register( "hpgl",
234 [&]( JOB* aJob )
235 {
236 m_reporter->Report( _( "Plotting to HPGL is no longer supported as of KiCad 10.0.\n" ),
239 },
240 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
241 {
242 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
243 false ) );
244
245 wxCHECK( editFrame, false );
246
247 DisplayErrorMessage( editFrame,
248 _( "Plotting to HPGL is no longer supported as of KiCad 10.0." ) );
249 return false;
250 } );
251 Register( "drill",
252 std::bind( &PCBNEW_JOBS_HANDLER::JobExportDrill, this, std::placeholders::_1 ),
253 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
254 {
255 JOB_EXPORT_PCB_DRILL* drillJob = dynamic_cast<JOB_EXPORT_PCB_DRILL*>( job );
256
257 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
258 false ) );
259
260 wxCHECK( drillJob && editFrame, false );
261
262 DIALOG_GENDRILL dlg( editFrame, drillJob, aParent );
263 return dlg.ShowModal() == wxID_OK;
264 } );
265 Register( "pos", std::bind( &PCBNEW_JOBS_HANDLER::JobExportPos, this, std::placeholders::_1 ),
266 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
267 {
268 JOB_EXPORT_PCB_POS* posJob = dynamic_cast<JOB_EXPORT_PCB_POS*>( job );
269
270 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
271 false ) );
272
273 wxCHECK( posJob && editFrame, false );
274
275 DIALOG_GEN_FOOTPRINT_POSITION dlg( posJob, editFrame, aParent );
276 return dlg.ShowModal() == wxID_OK;
277 } );
278 Register( "fpupgrade",
279 std::bind( &PCBNEW_JOBS_HANDLER::JobExportFpUpgrade, this, std::placeholders::_1 ),
280 []( JOB* job, wxWindow* aParent ) -> bool
281 {
282 return true;
283 } );
284 Register( "fpsvg",
285 std::bind( &PCBNEW_JOBS_HANDLER::JobExportFpSvg, this, std::placeholders::_1 ),
286 []( JOB* job, wxWindow* aParent ) -> bool
287 {
288 return true;
289 } );
290 Register( "drc", std::bind( &PCBNEW_JOBS_HANDLER::JobExportDrc, this, std::placeholders::_1 ),
291 []( JOB* job, wxWindow* aParent ) -> bool
292 {
293 JOB_PCB_DRC* drcJob = dynamic_cast<JOB_PCB_DRC*>( job );
294
295 wxCHECK( drcJob, false );
296
297 DIALOG_DRC_JOB_CONFIG dlg( aParent, drcJob );
298 return dlg.ShowModal() == wxID_OK;
299 } );
300 Register( "ipc2581",
301 std::bind( &PCBNEW_JOBS_HANDLER::JobExportIpc2581, this, std::placeholders::_1 ),
302 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
303 {
304 JOB_EXPORT_PCB_IPC2581* ipcJob = dynamic_cast<JOB_EXPORT_PCB_IPC2581*>( job );
305
306 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
307 false ) );
308
309 wxCHECK( ipcJob && editFrame, false );
310
311 DIALOG_EXPORT_2581 dlg( ipcJob, editFrame, aParent );
312 return dlg.ShowModal() == wxID_OK;
313 } );
314 Register( "ipcd356",
315 std::bind( &PCBNEW_JOBS_HANDLER::JobExportIpcD356, this, std::placeholders::_1 ),
316 []( JOB* job, wxWindow* aParent ) -> bool
317 {
318 return true;
319 } );
320 Register( "odb",
321 std::bind( &PCBNEW_JOBS_HANDLER::JobExportOdb, this, std::placeholders::_1 ),
322 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
323 {
324 JOB_EXPORT_PCB_ODB* odbJob = dynamic_cast<JOB_EXPORT_PCB_ODB*>( job );
325
326 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR,
327 false ) );
328
329 wxCHECK( odbJob && editFrame, false );
330
331 DIALOG_EXPORT_ODBPP dlg( odbJob, editFrame, aParent );
332 return dlg.ShowModal() == wxID_OK;
333 } );
334}
335
336
338{
339}
340
341
343{
344 TOOL_MANAGER* toolManager = nullptr;
345 if( Pgm().IsGUI() )
346 {
347 // we assume the PCB we are working on here is the one in the frame
348 // so use the frame's tool manager
350 if( editFrame )
351 toolManager = editFrame->GetToolManager();
352 }
353 else
354 {
355 if( m_toolManager == nullptr )
356 {
357 m_toolManager = std::make_unique<TOOL_MANAGER>();
358 }
359
360 toolManager = m_toolManager.get();
361
362 toolManager->SetEnvironment( aBrd, nullptr, nullptr, Kiface().KifaceSettings(), nullptr );
363 }
364 return toolManager;
365}
366
367
368BOARD* PCBNEW_JOBS_HANDLER::getBoard( const wxString& aPath )
369{
370 BOARD* brd = nullptr;
371
372 if( !Pgm().IsGUI() && Pgm().GetSettingsManager().IsProjectOpen() )
373 {
374 wxString pcbPath = aPath;
375
376 if( pcbPath.IsEmpty() )
377 {
378 wxFileName path = Pgm().GetSettingsManager().Prj().GetProjectFullName();
380 path.MakeAbsolute();
381 pcbPath = path.GetFullPath();
382 }
383
384 if( !m_cliBoard )
385 m_cliBoard = LoadBoard( pcbPath, true );
386
387 brd = m_cliBoard;
388 }
389 else if( Pgm().IsGUI() && Pgm().GetSettingsManager().IsProjectOpen() )
390 {
392
393 if( editFrame )
394 brd = editFrame->GetBoard();
395 }
396 else
397 {
398 brd = LoadBoard( aPath, true );
399 }
400
401 if( !brd )
402 m_reporter->Report( _( "Failed to load board\n" ), RPT_SEVERITY_ERROR );
403
404 return brd;
405}
406
407
408LSEQ PCBNEW_JOBS_HANDLER::convertLayerArg( wxString& aLayerString, BOARD* aBoard ) const
409{
410 std::map<wxString, LSET> layerUserMasks;
411 std::map<wxString, LSET> layerMasks;
412 std::map<wxString, LSET> layerGuiMasks;
413
414 // Build list of layer names and their layer mask:
415 for( PCB_LAYER_ID layer : LSET::AllLayersMask() )
416 {
417 // Add user layer name
418 if( aBoard )
419 layerUserMasks[ aBoard->GetLayerName( layer ) ] = LSET( { layer } );
420
421 // Add layer name used in pcb files
422 layerMasks[ LSET::Name( layer ) ] = LSET( { layer } );
423 // Add layer name using GUI canonical layer name
424 layerGuiMasks[ LayerName( layer ) ] = LSET( { layer } );
425 }
426
427 // Add list of grouped layer names used in pcb files
428 layerMasks[ wxT( "*" ) ] = LSET::AllLayersMask();
429 layerMasks[ wxT( "*.Cu" ) ] = LSET::AllCuMask();
430 layerMasks[ wxT( "*In.Cu" ) ] = LSET::InternalCuMask();
431 layerMasks[ wxT( "F&B.Cu" ) ] = LSET( { F_Cu, B_Cu } );
432 layerMasks[ wxT( "*.Adhes" ) ] = LSET( { B_Adhes, F_Adhes } );
433 layerMasks[ wxT( "*.Paste" ) ] = LSET( { B_Paste, F_Paste } );
434 layerMasks[ wxT( "*.Mask" ) ] = LSET( { B_Mask, F_Mask } );
435 layerMasks[ wxT( "*.SilkS" ) ] = LSET( { B_SilkS, F_SilkS } );
436 layerMasks[ wxT( "*.Fab" ) ] = LSET( { B_Fab, F_Fab } );
437 layerMasks[ wxT( "*.CrtYd" ) ] = LSET( { B_CrtYd, F_CrtYd } );
438
439 // Add list of grouped layer names using GUI canonical layer names
440 layerGuiMasks[ wxT( "*.Adhesive" ) ] = LSET( { B_Adhes, F_Adhes } );
441 layerGuiMasks[ wxT( "*.Silkscreen" ) ] = LSET( { B_SilkS, F_SilkS } );
442 layerGuiMasks[ wxT( "*.Courtyard" ) ] = LSET( { B_CrtYd, F_CrtYd } );
443
444 LSEQ layerMask;
445
446 auto pushLayers =
447 [&]( const LSET& layerSet )
448 {
449 for( PCB_LAYER_ID layer : layerSet.Seq() )
450 layerMask.push_back( layer );
451 };
452
453 if( !aLayerString.IsEmpty() )
454 {
455 wxStringTokenizer layerTokens( aLayerString, "," );
456
457 while( layerTokens.HasMoreTokens() )
458 {
459 std::string token = TO_UTF8( layerTokens.GetNextToken() );
460
461 if( layerUserMasks.contains( token ) )
462 pushLayers( layerUserMasks.at( token ) );
463 else if( layerMasks.count( token ) )
464 pushLayers( layerMasks.at( token ) );
465 else if( layerGuiMasks.count( token ) )
466 pushLayers( layerGuiMasks.at( token ) );
467 else
468 m_reporter->Report( wxString::Format( _( "Invalid layer name '%s'\n" ), token ) );
469 }
470 }
471
472 return layerMask;
473}
474
475
477{
478 JOB_EXPORT_PCB_3D* aStepJob = dynamic_cast<JOB_EXPORT_PCB_3D*>( aJob );
479
480 if( aStepJob == nullptr )
482
483 BOARD* brd = getBoard( aStepJob->m_filename );
484
485 if( !brd )
487
488 aJob->SetTitleBlock( brd->GetTitleBlock() );
489 brd->GetProject()->ApplyTextVars( aJob->GetVarOverrides() );
491
492 if( aStepJob->GetConfiguredOutputPath().IsEmpty() )
493 {
494 wxFileName fn = brd->GetFileName();
495 fn.SetName( fn.GetName() );
496
497 switch( aStepJob->m_format )
498 {
506 default:
507 m_reporter->Report( _( "Unknown export format" ), RPT_SEVERITY_ERROR );
508 return CLI::EXIT_CODES::ERR_UNKNOWN; // shouldnt have gotten here
509 }
510
511 aStepJob->SetWorkingOutputPath( fn.GetFullName() );
512 }
513
514 wxString outPath = aStepJob->GetFullOutputPath( brd->GetProject() );
515
516 if( !PATHS::EnsurePathExists( outPath, true ) )
517 {
518 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
520 }
521
523 {
524
525 double scale = 0.0;
526 switch ( aStepJob->m_vrmlUnits )
527 {
528 case JOB_EXPORT_PCB_3D::VRML_UNITS::MM: scale = 1.0; break;
529 case JOB_EXPORT_PCB_3D::VRML_UNITS::METERS: scale = 0.001; break;
530 case JOB_EXPORT_PCB_3D::VRML_UNITS::TENTHS: scale = 10.0 / 25.4; break;
531 case JOB_EXPORT_PCB_3D::VRML_UNITS::INCH: scale = 1.0 / 25.4; break;
532 }
533
534 EXPORTER_VRML vrmlExporter( brd );
535 wxString messages;
536
537 double originX = pcbIUScale.IUTomm( aStepJob->m_3dparams.m_Origin.x );
538 double originY = pcbIUScale.IUTomm( aStepJob->m_3dparams.m_Origin.y );
539
540 if( !aStepJob->m_hasUserOrigin )
541 {
542 BOX2I bbox = brd->ComputeBoundingBox( true );
543 originX = pcbIUScale.IUTomm( bbox.GetCenter().x );
544 originY = pcbIUScale.IUTomm( bbox.GetCenter().y );
545 }
546
547 bool success = vrmlExporter.ExportVRML_File( brd->GetProject(),
548 &messages,
549 outPath,
550 scale,
552 aStepJob->m_3dparams.m_IncludeDNP,
553 !aStepJob->m_vrmlModelDir.IsEmpty(),
554 aStepJob->m_vrmlRelativePaths,
555 aStepJob->m_vrmlModelDir,
556 originX,
557 originY );
558
559 if ( success )
560 {
561 m_reporter->Report( wxString::Format( _( "Successfully exported VRML to %s" ),
562 outPath ),
564 }
565 else
566 {
567 m_reporter->Report( _( "Error exporting VRML" ), RPT_SEVERITY_ERROR );
569 }
570 }
571 else
572 {
573 EXPORTER_STEP_PARAMS params = aStepJob->m_3dparams;
574
575 switch( aStepJob->m_format )
576 {
584 default:
585 m_reporter->Report( _( "Unknown export format" ), RPT_SEVERITY_ERROR );
586 return CLI::EXIT_CODES::ERR_UNKNOWN; // shouldnt have gotten here
587 }
588
589 EXPORTER_STEP stepExporter( brd, params, m_reporter );
590 stepExporter.m_outputFile = aStepJob->GetFullOutputPath( brd->GetProject() );
591
592 if( !stepExporter.Export() )
594 }
595
596 return CLI::EXIT_CODES::OK;
597}
598
599
601{
602 JOB_PCB_RENDER* aRenderJob = dynamic_cast<JOB_PCB_RENDER*>( aJob );
603
604 if( aRenderJob == nullptr )
606
607 // Reject width and height being invalid
608 // Final bit of sanity because this can blow things up
609 if( aRenderJob->m_width <= 0 || aRenderJob->m_height <= 0 )
610 {
611 m_reporter->Report( _( "Invalid image dimensions" ), RPT_SEVERITY_ERROR );
613 }
614
615 BOARD* brd = getBoard( aRenderJob->m_filename );
616
617 if( !brd )
619
620 aJob->SetTitleBlock( brd->GetTitleBlock() );
621 brd->GetProject()->ApplyTextVars( aJob->GetVarOverrides() );
623
624 if( aRenderJob->GetConfiguredOutputPath().IsEmpty() )
625 {
626 wxFileName fn = brd->GetFileName();
627
628 switch( aRenderJob->m_format )
629 {
632 default:
633 m_reporter->Report( _( "Unknown export format" ), RPT_SEVERITY_ERROR );
634 return CLI::EXIT_CODES::ERR_UNKNOWN; // shouldnt have gotten here
635 }
636
637 // set the name to board name + "side", its lazy but its hard to generate anything truely unique
638 // incase someone is doing this in a jobset with multiple jobs, they should be setting the output themselves
639 // or we do a hash based on all the options
640 fn.SetName( wxString::Format( "%s-%d", fn.GetName(), static_cast<int>( aRenderJob->m_side ) ) );
641
642 aRenderJob->SetWorkingOutputPath( fn.GetFullName() );
643 }
644
645 wxString outPath = aRenderJob->GetFullOutputPath( brd->GetProject() );
646
647 if( !PATHS::EnsurePathExists( outPath, true ) )
648 {
649 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
651 }
652
653 BOARD_ADAPTER boardAdapter;
654
655 boardAdapter.SetBoard( brd );
656 boardAdapter.m_IsBoardView = false;
657
659
660 if( EDA_3D_VIEWER_SETTINGS* userCfg = GetAppSettings<EDA_3D_VIEWER_SETTINGS>( "3d_viewer" ) )
661 {
662 cfg.m_Render = userCfg->m_Render;
663 cfg.m_Camera = userCfg->m_Camera;
664 cfg.m_LayerPresets = userCfg->m_LayerPresets;
665 }
666
667 if( aRenderJob->m_appearancePreset.empty() )
668 {
669 // Force display 3D models
671 cfg.m_Render.show_footprints_dnp = true;
675 }
676
677 if( aRenderJob->m_quality == JOB_PCB_RENDER::QUALITY::BASIC )
678 {
679 // Silkscreen is pixelated without antialiasing
681
682 cfg.m_Render.raytrace_backfloor = aRenderJob->m_floor;
683 cfg.m_Render.raytrace_post_processing = aRenderJob->m_floor;
684
686 cfg.m_Render.raytrace_reflections = false;
687 cfg.m_Render.raytrace_shadows = aRenderJob->m_floor;
688
689 // Better colors
691
692 // Tracks below soldermask are not visible without refractions
695 }
696 else if( aRenderJob->m_quality == JOB_PCB_RENDER::QUALITY::HIGH )
697 {
699 cfg.m_Render.raytrace_backfloor = true;
703 cfg.m_Render.raytrace_shadows = true;
706 }
707 else if( aRenderJob->m_quality == JOB_PCB_RENDER::QUALITY::JOB_SETTINGS )
708 {
710 cfg.m_Render.raytrace_backfloor = aRenderJob->m_floor;
713 }
714
716 aRenderJob->m_lightTopIntensity.y,
717 aRenderJob->m_lightTopIntensity.z, 1.0 );
718
720 aRenderJob->m_lightBottomIntensity.y,
721 aRenderJob->m_lightBottomIntensity.z, 1.0 );
722
724 aRenderJob->m_lightCameraIntensity.y,
725 aRenderJob->m_lightCameraIntensity.z, 1.0 );
726
727 COLOR4D lightColor( aRenderJob->m_lightSideIntensity.x,
728 aRenderJob->m_lightSideIntensity.y,
729 aRenderJob->m_lightSideIntensity.z, 1.0 );
730
732 lightColor, lightColor, lightColor, lightColor,
733 lightColor, lightColor, lightColor, lightColor,
734 };
735
736 int sideElevation = aRenderJob->m_lightSideElevation;
737
739 sideElevation, sideElevation, sideElevation, sideElevation,
740 -sideElevation, -sideElevation, -sideElevation, -sideElevation,
741 };
742
744 45, 135, 225, 315, 45, 135, 225, 315,
745 };
746
747 cfg.m_CurrentPreset = aRenderJob->m_appearancePreset;
749 boardAdapter.m_Cfg = &cfg;
750
753 && aRenderJob->m_format == JOB_PCB_RENDER::FORMAT::PNG ) )
754 {
755 boardAdapter.m_ColorOverrides[LAYER_3D_BACKGROUND_TOP] = COLOR4D( 1.0, 1.0, 1.0, 0.0 );
756 boardAdapter.m_ColorOverrides[LAYER_3D_BACKGROUND_BOTTOM] = COLOR4D( 1.0, 1.0, 1.0, 0.0 );
757 }
758
760
761 static std::map<JOB_PCB_RENDER::SIDE, VIEW3D_TYPE> s_viewCmdMap = {
762 { JOB_PCB_RENDER::SIDE::TOP, VIEW3D_TYPE::VIEW3D_TOP },
763 { JOB_PCB_RENDER::SIDE::BOTTOM, VIEW3D_TYPE::VIEW3D_BOTTOM },
764 { JOB_PCB_RENDER::SIDE::LEFT, VIEW3D_TYPE::VIEW3D_LEFT },
765 { JOB_PCB_RENDER::SIDE::RIGHT, VIEW3D_TYPE::VIEW3D_RIGHT },
766 { JOB_PCB_RENDER::SIDE::FRONT, VIEW3D_TYPE::VIEW3D_FRONT },
767 { JOB_PCB_RENDER::SIDE::BACK, VIEW3D_TYPE::VIEW3D_BACK },
768 };
769
770 PROJECTION_TYPE projection = aRenderJob->m_perspective ? PROJECTION_TYPE::PERSPECTIVE
771 : PROJECTION_TYPE::ORTHO;
772
773 wxSize windowSize( aRenderJob->m_width, aRenderJob->m_height );
774 TRACK_BALL camera( 2 * RANGE_SCALE_3D );
775
776 camera.SetProjection( projection );
777 camera.SetCurWindowSize( windowSize );
778
779 RENDER_3D_RAYTRACE_RAM raytrace( boardAdapter, camera );
780 raytrace.SetCurWindowSize( windowSize );
781
782 for( bool first = true; raytrace.Redraw( false, m_reporter, m_reporter ); first = false )
783 {
784 if( first )
785 {
786 const float cmTo3D = boardAdapter.BiuTo3dUnits() * pcbIUScale.mmToIU( 10.0 );
787
788 // First redraw resets lookat point to the board center, so set up the camera here
789 camera.ViewCommand_T1( s_viewCmdMap[aRenderJob->m_side] );
790
791 camera.SetLookAtPos_T1( camera.GetLookAtPos_T1() + SFVEC3F( aRenderJob->m_pivot.x,
792 aRenderJob->m_pivot.y,
793 aRenderJob->m_pivot.z ) * cmTo3D );
794
795 camera.Pan_T1( SFVEC3F( aRenderJob->m_pan.x, aRenderJob->m_pan.y, aRenderJob->m_pan.z ) );
796
797 camera.Zoom_T1( aRenderJob->m_zoom );
798
799 camera.RotateX_T1( DEG2RAD( aRenderJob->m_rotation.x ) );
800 camera.RotateY_T1( DEG2RAD( aRenderJob->m_rotation.y ) );
801 camera.RotateZ_T1( DEG2RAD( aRenderJob->m_rotation.z ) );
802
803 camera.Interpolate( 1.0f );
804 camera.SetT0_and_T1_current_T();
805 camera.ParametersChanged();
806 }
807 }
808
809 uint8_t* rgbaBuffer = raytrace.GetBuffer();
810 wxSize realSize = raytrace.GetRealBufferSize();
811 bool success = !!rgbaBuffer;
812
813 if( rgbaBuffer )
814 {
815 const unsigned int wxh = realSize.x * realSize.y;
816
817 unsigned char* rgbBuffer = (unsigned char*) malloc( wxh * 3 );
818 unsigned char* alphaBuffer = (unsigned char*) malloc( wxh );
819
820 unsigned char* rgbaPtr = rgbaBuffer;
821 unsigned char* rgbPtr = rgbBuffer;
822 unsigned char* alphaPtr = alphaBuffer;
823
824 for( int y = 0; y < realSize.y; y++ )
825 {
826 for( int x = 0; x < realSize.x; x++ )
827 {
828 rgbPtr[0] = rgbaPtr[0];
829 rgbPtr[1] = rgbaPtr[1];
830 rgbPtr[2] = rgbaPtr[2];
831 alphaPtr[0] = rgbaPtr[3];
832
833 rgbaPtr += 4;
834 rgbPtr += 3;
835 alphaPtr += 1;
836 }
837 }
838
839 wxImage image( realSize );
840 image.SetData( rgbBuffer );
841 image.SetAlpha( alphaBuffer );
842 image = image.Mirror( false );
843
844 image.SetOption( wxIMAGE_OPTION_QUALITY, 90 );
845 image.SaveFile( outPath, aRenderJob->m_format == JOB_PCB_RENDER::FORMAT::PNG ? wxBITMAP_TYPE_PNG
846 : wxBITMAP_TYPE_JPEG );
847 }
848
849 if( success )
850 {
851 m_reporter->Report( _( "Successfully created 3D render image" ) + wxS( "\n" ), RPT_SEVERITY_INFO );
852 return CLI::EXIT_CODES::OK;
853 }
854 else
855 {
856 m_reporter->Report( _( "Error creating 3D render image" ) + wxS( "\n" ), RPT_SEVERITY_ERROR );
858 }
859}
860
861
863{
864 JOB_EXPORT_PCB_SVG* aSvgJob = dynamic_cast<JOB_EXPORT_PCB_SVG*>( aJob );
865
866 if( aSvgJob == nullptr )
868
869 BOARD* brd = getBoard( aSvgJob->m_filename );
870 TOOL_MANAGER* toolManager = getToolManager( brd );
871
872 if( !brd )
874
875 aJob->SetTitleBlock( brd->GetTitleBlock() );
876
878 {
879 if( aSvgJob->GetConfiguredOutputPath().IsEmpty() )
880 {
881 wxFileName fn = brd->GetFileName();
882 fn.SetName( fn.GetName() );
883 fn.SetExt( GetDefaultPlotExtension( PLOT_FORMAT::SVG ) );
884
885 aSvgJob->SetWorkingOutputPath( fn.GetFullName() );
886 }
887 }
888
889 wxString outPath = aSvgJob->GetFullOutputPath( brd->GetProject() );
890
892 {
893 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
895 }
896
898 brd->GetProject()->ApplyTextVars( aJob->GetVarOverrides() );
900
901 if( aSvgJob->m_checkZonesBeforePlot )
902 {
903 if( !toolManager->FindTool( ZONE_FILLER_TOOL_NAME ) )
904 toolManager->RegisterTool( new ZONE_FILLER_TOOL );
905
906 toolManager->GetTool<ZONE_FILLER_TOOL>()->CheckAllZones( nullptr );
907 }
908
909 if( aSvgJob->m_argLayers )
910 aSvgJob->m_plotLayerSequence = convertLayerArg( aSvgJob->m_argLayers.value(), brd );
911
912 if( aSvgJob->m_argCommonLayers )
913 aSvgJob->m_plotOnAllLayersSequence = convertLayerArg( aSvgJob->m_argCommonLayers.value(), brd );
914
915 if( aSvgJob->m_plotLayerSequence.size() < 1 )
916 {
917 m_reporter->Report( _( "At least one layer must be specified\n" ), RPT_SEVERITY_ERROR );
919 }
920
921 PCB_PLOT_PARAMS plotOpts;
922 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, aSvgJob, *m_reporter );
923
924 PCB_PLOTTER plotter( brd, m_reporter, plotOpts );
925
926 std::optional<wxString> layerName;
927 std::optional<wxString> sheetName;
928 std::optional<wxString> sheetPath;
929
931 {
932 if( aJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
933 layerName = aSvgJob->GetVarOverrides().at( wxT( "LAYER" ) );
934
935 if( aJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
936 sheetName = aSvgJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
937
938 if( aJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
939 sheetPath = aSvgJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
940 }
941
942 if( !plotter.Plot( outPath, aSvgJob->m_plotLayerSequence, aSvgJob->m_plotOnAllLayersSequence,
944 layerName, sheetName, sheetPath ) )
945 {
947 }
948
949 return CLI::EXIT_CODES::OK;
950}
951
952
954{
955 JOB_EXPORT_PCB_DXF* aDxfJob = dynamic_cast<JOB_EXPORT_PCB_DXF*>( aJob );
956
957 if( aDxfJob == nullptr )
959
960 BOARD* brd = getBoard( aDxfJob->m_filename );
961
962 if( !brd )
964
965 TOOL_MANAGER* toolManager = getToolManager( brd );
966
967 aJob->SetTitleBlock( brd->GetTitleBlock() );
969 brd->GetProject()->ApplyTextVars( aJob->GetVarOverrides() );
971
972 if( aDxfJob->m_checkZonesBeforePlot )
973 {
974 if( !toolManager->FindTool( ZONE_FILLER_TOOL_NAME ) )
975 toolManager->RegisterTool( new ZONE_FILLER_TOOL );
976
977 toolManager->GetTool<ZONE_FILLER_TOOL>()->CheckAllZones( nullptr );
978 }
979
980 if( aDxfJob->m_argLayers )
981 aDxfJob->m_plotLayerSequence = convertLayerArg( aDxfJob->m_argLayers.value(), brd );
982
983 if( aDxfJob->m_argCommonLayers )
984 aDxfJob->m_plotOnAllLayersSequence = convertLayerArg( aDxfJob->m_argCommonLayers.value(), brd );
985
986 if( aDxfJob->m_plotLayerSequence.size() < 1 )
987 {
988 m_reporter->Report( _( "At least one layer must be specified\n" ), RPT_SEVERITY_ERROR );
990 }
991
993 {
994 if( aDxfJob->GetConfiguredOutputPath().IsEmpty() )
995 {
996 wxFileName fn = brd->GetFileName();
997 fn.SetName( fn.GetName() );
998 fn.SetExt( GetDefaultPlotExtension( PLOT_FORMAT::DXF ) );
999
1000 aDxfJob->SetWorkingOutputPath( fn.GetFullName() );
1001 }
1002 }
1003
1004 wxString outPath = aDxfJob->GetFullOutputPath( brd->GetProject() );
1005
1007 {
1008 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1010 }
1011
1012 PCB_PLOT_PARAMS plotOpts;
1013 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, aDxfJob, *m_reporter);
1014
1015 PCB_PLOTTER plotter( brd, m_reporter, plotOpts );
1016
1017 std::optional<wxString> layerName;
1018 std::optional<wxString> sheetName;
1019 std::optional<wxString> sheetPath;
1020
1022 {
1023 if( aJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
1024 layerName = aDxfJob->GetVarOverrides().at( wxT( "LAYER" ) );
1025
1026 if( aJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
1027 sheetName = aDxfJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
1028
1029 if( aJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
1030 sheetPath = aDxfJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
1031 }
1032
1033 if( !plotter.Plot( outPath, aDxfJob->m_plotLayerSequence, aDxfJob->m_plotOnAllLayersSequence,
1035 layerName, sheetName, sheetPath ) )
1036 {
1038 }
1039
1040 return CLI::EXIT_CODES::OK;
1041}
1042
1043
1045{
1046 bool plotAllLayersOneFile = false;
1047 JOB_EXPORT_PCB_PDF* pdfJob = dynamic_cast<JOB_EXPORT_PCB_PDF*>( aJob );
1048
1049 if( pdfJob == nullptr )
1051
1052 BOARD* brd = getBoard( pdfJob->m_filename );
1053
1054 if( !brd )
1056
1057 TOOL_MANAGER* toolManager = getToolManager( brd );
1058
1059 pdfJob->SetTitleBlock( brd->GetTitleBlock() );
1061 brd->GetProject()->ApplyTextVars( pdfJob->GetVarOverrides() );
1062 brd->SynchronizeProperties();
1063
1064 if( pdfJob->m_checkZonesBeforePlot )
1065 {
1066 if( !toolManager->FindTool( ZONE_FILLER_TOOL_NAME ) )
1067 toolManager->RegisterTool( new ZONE_FILLER_TOOL );
1068
1069 toolManager->GetTool<ZONE_FILLER_TOOL>()->CheckAllZones( nullptr );
1070 }
1071
1072 if( pdfJob->m_argLayers )
1073 pdfJob->m_plotLayerSequence = convertLayerArg( pdfJob->m_argLayers.value(), brd );
1074
1075 if( pdfJob->m_argCommonLayers )
1076 pdfJob->m_plotOnAllLayersSequence = convertLayerArg( pdfJob->m_argCommonLayers.value(), brd );
1077
1079 plotAllLayersOneFile = true;
1080
1081 if( pdfJob->m_plotLayerSequence.size() < 1 )
1082 {
1083 m_reporter->Report( _( "At least one layer must be specified\n" ), RPT_SEVERITY_ERROR );
1085 }
1086
1087 if( plotAllLayersOneFile && pdfJob->GetConfiguredOutputPath().IsEmpty() )
1088 {
1089 wxFileName fn = brd->GetFileName();
1090 fn.SetName( fn.GetName() );
1091 fn.SetExt( GetDefaultPlotExtension( PLOT_FORMAT::PDF ) );
1092
1093 pdfJob->SetWorkingOutputPath( fn.GetFullName() );
1094 }
1095
1096 PCB_PLOT_PARAMS plotOpts;
1097 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, pdfJob, *m_reporter );
1098
1099 // ensure this is set for this one gen mode
1100 if( plotAllLayersOneFile )
1101 plotOpts.m_PDFSingle = true;
1102
1103 PCB_PLOTTER pcbPlotter( brd, m_reporter, plotOpts );
1104
1105 wxString outPath = pdfJob->GetFullOutputPath( brd->GetProject() );
1106
1107 if( !PATHS::EnsurePathExists( outPath, plotAllLayersOneFile ) )
1108 {
1109 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1111 }
1112
1113 std::optional<wxString> layerName;
1114 std::optional<wxString> sheetName;
1115 std::optional<wxString> sheetPath;
1116
1117 if( plotAllLayersOneFile )
1118 {
1119 if( pdfJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
1120 layerName = pdfJob->GetVarOverrides().at( wxT( "LAYER" ) );
1121
1122 if( pdfJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
1123 sheetName = pdfJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
1124
1125 if( pdfJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
1126 sheetPath = pdfJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
1127 }
1128
1129
1131
1132 if( !pcbPlotter.Plot( outPath, pdfJob->m_plotLayerSequence,
1133 pdfJob->m_plotOnAllLayersSequence, false, plotAllLayersOneFile,
1134 layerName, sheetName, sheetPath ) )
1135 {
1137 }
1138
1139 return CLI::EXIT_CODES::OK;
1140}
1141
1142
1144{
1145 JOB_EXPORT_PCB_PS* psJob = dynamic_cast<JOB_EXPORT_PCB_PS*>( aJob );
1146
1147 if( psJob == nullptr )
1149
1150 BOARD* brd = getBoard( psJob->m_filename );
1151
1152 if( !brd )
1154
1155 TOOL_MANAGER* toolManager = getToolManager( brd );
1156
1157 psJob->SetTitleBlock( brd->GetTitleBlock() );
1159 brd->GetProject()->ApplyTextVars( psJob->GetVarOverrides() );
1160 brd->SynchronizeProperties();
1161
1162 if( psJob->m_checkZonesBeforePlot )
1163 {
1164 if( !toolManager->FindTool( ZONE_FILLER_TOOL_NAME ) )
1165 toolManager->RegisterTool( new ZONE_FILLER_TOOL );
1166
1167 toolManager->GetTool<ZONE_FILLER_TOOL>()->CheckAllZones( nullptr );
1168 }
1169
1170 if( psJob->m_argLayers )
1171 psJob->m_plotLayerSequence = convertLayerArg( psJob->m_argLayers.value(), brd );
1172
1173 if( psJob->m_argCommonLayers )
1174 psJob->m_plotOnAllLayersSequence = convertLayerArg( psJob->m_argCommonLayers.value(), brd );
1175
1176 if( psJob->m_plotLayerSequence.size() < 1 )
1177 {
1178 m_reporter->Report( _( "At least one layer must be specified\n" ), RPT_SEVERITY_ERROR );
1180 }
1181
1182 bool isSingle = psJob->m_genMode == JOB_EXPORT_PCB_PS::GEN_MODE::SINGLE;
1183
1184 if( isSingle )
1185 {
1186 if( psJob->GetConfiguredOutputPath().IsEmpty() )
1187 {
1188 wxFileName fn = brd->GetFileName();
1189 fn.SetName( fn.GetName() );
1190 fn.SetExt( GetDefaultPlotExtension( PLOT_FORMAT::POST ) );
1191
1192 psJob->SetWorkingOutputPath( fn.GetFullName() );
1193 }
1194 }
1195
1196 wxString outPath = psJob->GetFullOutputPath( brd->GetProject() );
1197
1198 if( !PATHS::EnsurePathExists( outPath, isSingle ) )
1199 {
1200 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1202 }
1203
1204 PCB_PLOT_PARAMS plotOpts;
1205 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, psJob, *m_reporter );
1206
1207 PCB_PLOTTER pcbPlotter( brd, m_reporter, plotOpts );
1208
1209 std::optional<wxString> layerName;
1210 std::optional<wxString> sheetName;
1211 std::optional<wxString> sheetPath;
1212
1213 if( isSingle )
1214 {
1215 if( aJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
1216 layerName = psJob->GetVarOverrides().at( wxT( "LAYER" ) );
1217
1218 if( aJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
1219 sheetName = psJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
1220
1221 if( aJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
1222 sheetPath = psJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
1223 }
1224
1226
1227 if( !pcbPlotter.Plot( outPath, psJob->m_plotLayerSequence, psJob->m_plotOnAllLayersSequence, false, isSingle,
1228 layerName, sheetName, sheetPath ) )
1229 {
1231 }
1232
1233 return CLI::EXIT_CODES::OK;
1234}
1235
1236
1238{
1239 int exitCode = CLI::EXIT_CODES::OK;
1240 JOB_EXPORT_PCB_GERBERS* aGerberJob = dynamic_cast<JOB_EXPORT_PCB_GERBERS*>( aJob );
1241
1242 if( aGerberJob == nullptr )
1244
1245 BOARD* brd = getBoard( aGerberJob->m_filename );
1246
1247 if( !brd )
1249
1250 TOOL_MANAGER* toolManager = getToolManager( brd );
1251
1252 wxString outPath = aGerberJob->GetFullOutputPath( brd->GetProject() );
1253
1254 if( !PATHS::EnsurePathExists( outPath, false ) )
1255 {
1256 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1258 }
1259
1260 aJob->SetTitleBlock( brd->GetTitleBlock() );
1261 loadOverrideDrawingSheet( brd, aGerberJob->m_drawingSheet );
1262 brd->GetProject()->ApplyTextVars( aJob->GetVarOverrides() );
1263 brd->SynchronizeProperties();
1264
1265 if( aGerberJob->m_checkZonesBeforePlot )
1266 {
1267 if( !toolManager->FindTool( ZONE_FILLER_TOOL_NAME ) )
1268 toolManager->RegisterTool( new ZONE_FILLER_TOOL );
1269
1270 toolManager->GetTool<ZONE_FILLER_TOOL>()->CheckAllZones( nullptr );
1271 }
1272
1273 bool hasLayerListSpecified = false; // will be true if the user layer list is not empty
1274
1275 if( aGerberJob->m_argLayers )
1276 {
1277 if( !aGerberJob->m_argLayers.value().empty() )
1278 {
1279 aGerberJob->m_plotLayerSequence = convertLayerArg( aGerberJob->m_argLayers.value(), brd );
1280 hasLayerListSpecified = true;
1281 }
1282 else
1283 {
1285 }
1286 }
1287
1288 if( aGerberJob->m_argCommonLayers )
1289 aGerberJob->m_plotOnAllLayersSequence = convertLayerArg( aGerberJob->m_argCommonLayers.value(), brd );
1290
1291 PCB_PLOT_PARAMS boardPlotOptions = brd->GetPlotOptions();
1292 GERBER_JOBFILE_WRITER jobfile_writer( brd );
1293
1294 wxString fileExt;
1295
1296 if( aGerberJob->m_useBoardPlotParams )
1297 {
1298 // The board plot options are saved with all copper layers enabled, even those that don't
1299 // exist in the current stackup. This is done so the layers are automatically enabled in the plot
1300 // dialog when the user enables them. We need to filter out these not-enabled layers here so
1301 // we don't plot 32 layers when we only have 4, etc.
1302 LSET plotLayers = ( boardPlotOptions.GetLayerSelection() & LSET::AllNonCuMask() )
1303 | ( brd->GetEnabledLayers() & LSET::AllCuMask() );
1304 aGerberJob->m_plotLayerSequence = plotLayers.SeqStackupForPlotting();
1305 aGerberJob->m_plotOnAllLayersSequence = boardPlotOptions.GetPlotOnAllLayersSequence();
1306 }
1307 else
1308 {
1309 // default to the board enabled layers, but only if the user has not specifed a layer list
1310 // ( m_plotLayerSequence can be empty with a broken user layer list)
1311 if( aGerberJob->m_plotLayerSequence.empty() && !hasLayerListSpecified )
1313 }
1314
1315 // Ensure layers to plot are restricted to enabled layers of the board to plot
1316 LSET layersToPlot = LSET( { aGerberJob->m_plotLayerSequence } ) & brd->GetEnabledLayers();
1317
1318 for( PCB_LAYER_ID layer : layersToPlot.UIOrder() )
1319 {
1320 LSEQ plotSequence;
1321
1322 // Base layer always gets plotted first.
1323 plotSequence.push_back( layer );
1324
1325 // Now all the "include on all" layers
1326 for( PCB_LAYER_ID layer_all : aGerberJob->m_plotOnAllLayersSequence )
1327 {
1328 // Don't plot the same layer more than once;
1329 if( find( plotSequence.begin(), plotSequence.end(), layer_all ) != plotSequence.end() )
1330 continue;
1331
1332 plotSequence.push_back( layer_all );
1333 }
1334
1335 // Pick the basename from the board file
1336 wxFileName fn( brd->GetFileName() );
1337 wxString layerName = brd->GetLayerName( layer );
1338 wxString sheetName;
1339 wxString sheetPath;
1340 PCB_PLOT_PARAMS plotOpts;
1341
1342 if( aGerberJob->m_useBoardPlotParams )
1343 plotOpts = boardPlotOptions;
1344 else
1345 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, aGerberJob, *m_reporter );
1346
1347 if( plotOpts.GetUseGerberProtelExtensions() )
1348 fileExt = GetGerberProtelExtension( layer );
1349 else
1351
1352 BuildPlotFileName( &fn, outPath, layerName, fileExt );
1353 wxString fullname = fn.GetFullName();
1354
1355 if( m_progressReporter )
1356 {
1357 m_progressReporter->AdvancePhase( wxString::Format( _( "Exporting %s" ), fullname ) );
1359 }
1360
1361 jobfile_writer.AddGbrFile( layer, fullname );
1362
1363 if( aJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
1364 layerName = aJob->GetVarOverrides().at( wxT( "LAYER" ) );
1365
1366 if( aJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
1367 sheetName = aJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
1368
1369 if( aJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
1370 sheetPath = aJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
1371
1372 // We are feeding it one layer at the start here to silence a logic check
1373 GERBER_PLOTTER* plotter;
1374 {
1376 plotter = (GERBER_PLOTTER*) StartPlotBoard( brd, &plotOpts, layer, layerName,
1377 fn.GetFullPath(), sheetName, sheetPath );
1378 }
1379
1380 if( plotter )
1381 {
1382 m_reporter->Report( wxString::Format( _( "Plotted to '%s'.\n" ), fn.GetFullPath() ),
1385 PlotBoardLayers( brd, plotter, plotSequence, plotOpts );
1386 plotter->EndPlot();
1387 }
1388 else
1389 {
1390 m_reporter->Report( wxString::Format( _( "Failed to plot to '%s'.\n" ), fn.GetFullPath() ),
1393 }
1394
1395 delete plotter;
1396 }
1397
1398 if( aGerberJob->m_createJobsFile )
1399 {
1400 wxFileName fn( brd->GetFileName() );
1401
1402 // Build gerber job file from basename
1403 BuildPlotFileName( &fn, outPath, wxT( "job" ), FILEEXT::GerberJobFileExtension );
1404 jobfile_writer.CreateJobFile( fn.GetFullPath() );
1405 }
1406
1407 return exitCode;
1408}
1409
1410
1412{
1413 JOB_EXPORT_PCB_GENCAD* aGencadJob = dynamic_cast<JOB_EXPORT_PCB_GENCAD*>( aJob );
1414
1415 if( aGencadJob == nullptr )
1417
1418 BOARD* brd = LoadBoard( aGencadJob->m_filename, true ); // Ensure m_board is of type BOARD*
1419
1420 if( brd == nullptr )
1422
1423 GENCAD_EXPORTER exporter( brd );
1424
1425 VECTOR2I GencadOffset;
1426 VECTOR2I auxOrigin = brd->GetDesignSettings().GetAuxOrigin();
1427 GencadOffset.x = aGencadJob->m_useDrillOrigin ? auxOrigin.x : 0;
1428 GencadOffset.y = aGencadJob->m_useDrillOrigin ? auxOrigin.y : 0;
1429
1430 exporter.FlipBottomPads( aGencadJob->m_flipBottomPads );
1431 exporter.UsePinNamesUnique( aGencadJob->m_useUniquePins );
1432 exporter.UseIndividualShapes( aGencadJob->m_useIndividualShapes );
1433 exporter.SetPlotOffet( GencadOffset );
1434 exporter.StoreOriginCoordsInFile( aGencadJob->m_storeOriginCoords );
1435
1436 if( aGencadJob->GetConfiguredOutputPath().IsEmpty() )
1437 {
1438 wxFileName fn = brd->GetFileName();
1439 fn.SetName( fn.GetName() );
1440 fn.SetExt( FILEEXT::GencadFileExtension );
1441
1442 aGencadJob->SetWorkingOutputPath( fn.GetFullName() );
1443 }
1444
1445 wxString outPath = aGencadJob->GetFullOutputPath( brd->GetProject() );
1446
1447 if( !PATHS::EnsurePathExists( outPath, true ) )
1448 {
1449 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1451 }
1452
1453 if( !exporter.WriteFile( outPath ) )
1454 {
1455 m_reporter->Report( wxString::Format( _( "Failed to create file '%s'.\n" ), outPath ),
1457
1459 }
1460
1461 m_reporter->Report( _( "Successfully created genCAD file\n" ), RPT_SEVERITY_INFO );
1462
1463 return CLI::EXIT_CODES::OK;
1464}
1465
1466
1468{
1469 int exitCode = CLI::EXIT_CODES::OK;
1470 JOB_EXPORT_PCB_GERBER* aGerberJob = dynamic_cast<JOB_EXPORT_PCB_GERBER*>( aJob );
1471
1472 if( aGerberJob == nullptr )
1474
1475 BOARD* brd = getBoard( aGerberJob->m_filename );
1476
1477 if( !brd )
1479
1480 TOOL_MANAGER* toolManager = getToolManager( brd );
1481
1482 aJob->SetTitleBlock( brd->GetTitleBlock() );
1483 brd->GetProject()->ApplyTextVars( aJob->GetVarOverrides() );
1484 brd->SynchronizeProperties();
1485
1486 if( aGerberJob->m_checkZonesBeforePlot )
1487 {
1488 if( !toolManager->FindTool( ZONE_FILLER_TOOL_NAME ) )
1489 toolManager->RegisterTool( new ZONE_FILLER_TOOL );
1490
1491 toolManager->GetTool<ZONE_FILLER_TOOL>()->CheckAllZones( nullptr );
1492 }
1493
1494 if( aGerberJob->m_argLayers )
1495 aGerberJob->m_plotLayerSequence = convertLayerArg( aGerberJob->m_argLayers.value(), brd );
1496
1497 if( aGerberJob->m_argCommonLayers )
1498 aGerberJob->m_plotOnAllLayersSequence = convertLayerArg( aGerberJob->m_argCommonLayers.value(), brd );
1499
1500 if( aGerberJob->m_plotLayerSequence.size() < 1 )
1501 {
1502 m_reporter->Report( _( "At least one layer must be specified\n" ), RPT_SEVERITY_ERROR );
1504 }
1505
1506 if( aGerberJob->GetConfiguredOutputPath().IsEmpty() )
1507 {
1508 wxFileName fn = brd->GetFileName();
1509 fn.SetName( fn.GetName() );
1510 fn.SetExt( GetDefaultPlotExtension( PLOT_FORMAT::GERBER ) );
1511
1512 aGerberJob->SetWorkingOutputPath( fn.GetFullName() );
1513 }
1514
1515 PCB_PLOT_PARAMS plotOpts;
1516 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, aGerberJob, *m_reporter );
1517 plotOpts.SetLayerSelection( aGerberJob->m_plotLayerSequence );
1519
1521 wxString layerName;
1522 wxString sheetName;
1523 wxString sheetPath;
1524 wxString outPath = aGerberJob->GetFullOutputPath( brd->GetProject() );
1525
1526 // The first layer will be treated as the layer name for the gerber header,
1527 // the other layers will be treated equivalent to the "Plot on All Layers" option
1528 // in the GUI
1529 if( aGerberJob->m_plotLayerSequence.size() >= 1 )
1530 {
1531 layer = aGerberJob->m_plotLayerSequence.front();
1532 layerName = brd->GetLayerName( layer );
1533 }
1534
1535 if( aJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
1536 layerName = aJob->GetVarOverrides().at( wxT( "LAYER" ) );
1537
1538 if( aJob->GetVarOverrides().contains( wxT( "SHEETNAME" ) ) )
1539 sheetName = aJob->GetVarOverrides().at( wxT( "SHEETNAME" ) );
1540
1541 if( aJob->GetVarOverrides().contains( wxT( "SHEETPATH" ) ) )
1542 sheetPath = aJob->GetVarOverrides().at( wxT( "SHEETPATH" ) );
1543
1544 // We are feeding it one layer at the start here to silence a logic check
1545 PLOTTER* plotter = StartPlotBoard( brd, &plotOpts, layer, layerName, outPath, sheetName,
1546 sheetPath );
1547
1548 if( plotter )
1549 {
1550 PlotBoardLayers( brd, plotter, aGerberJob->m_plotLayerSequence, plotOpts );
1551 plotter->EndPlot();
1552 }
1553 else
1554 {
1555 m_reporter->Report( wxString::Format( _( "Failed to plot to '%s'.\n" ), outPath ),
1558 }
1559
1560 delete plotter;
1561
1562 return exitCode;
1563}
1564
1567
1568
1570{
1571 JOB_EXPORT_PCB_DRILL* aDrillJob = dynamic_cast<JOB_EXPORT_PCB_DRILL*>( aJob );
1572
1573 if( aDrillJob == nullptr )
1575
1576 BOARD* brd = getBoard( aDrillJob->m_filename );
1577
1578 if( !brd )
1580
1581 aJob->SetTitleBlock( brd->GetTitleBlock() );
1582
1583 wxString outPath = aDrillJob->GetFullOutputPath( brd->GetProject() );
1584
1585 if( !PATHS::EnsurePathExists( outPath ) )
1586 {
1587 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1589 }
1590
1591 std::unique_ptr<GENDRILL_WRITER_BASE> drillWriter;
1592
1594 drillWriter = std::make_unique<EXCELLON_WRITER>( brd );
1595 else
1596 drillWriter = std::make_unique<GERBER_WRITER>( brd );
1597
1598 VECTOR2I offset;
1599
1601 offset = VECTOR2I( 0, 0 );
1602 else
1603 offset = brd->GetDesignSettings().GetAuxOrigin();
1604
1605 PLOT_FORMAT mapFormat = PLOT_FORMAT::PDF;
1606
1607 switch( aDrillJob->m_mapFormat )
1608 {
1609 case JOB_EXPORT_PCB_DRILL::MAP_FORMAT::POSTSCRIPT: mapFormat = PLOT_FORMAT::POST; break;
1610 case JOB_EXPORT_PCB_DRILL::MAP_FORMAT::GERBER_X2: mapFormat = PLOT_FORMAT::GERBER; break;
1611 case JOB_EXPORT_PCB_DRILL::MAP_FORMAT::DXF: mapFormat = PLOT_FORMAT::DXF; break;
1612 case JOB_EXPORT_PCB_DRILL::MAP_FORMAT::SVG: mapFormat = PLOT_FORMAT::SVG; break;
1613 default:
1614 case JOB_EXPORT_PCB_DRILL::MAP_FORMAT::PDF: mapFormat = PLOT_FORMAT::PDF; break;
1615 }
1616
1618 {
1620 switch( aDrillJob->m_zeroFormat )
1621 {
1624 break;
1627 break;
1630 break;
1632 default:
1634 break;
1635 }
1636
1637 DRILL_PRECISION precision;
1638
1640 precision = precisionListForInches;
1641 else
1642 precision = precisionListForMetric;
1643
1644 EXCELLON_WRITER* excellonWriter = dynamic_cast<EXCELLON_WRITER*>( drillWriter.get() );
1645
1646 if( excellonWriter == nullptr )
1648
1649 excellonWriter->SetFormat( aDrillJob->m_drillUnits == JOB_EXPORT_PCB_DRILL::DRILL_UNITS::MM,
1650 zeroFmt, precision.m_Lhs, precision.m_Rhs );
1651 excellonWriter->SetOptions( aDrillJob->m_excellonMirrorY,
1652 aDrillJob->m_excellonMinimalHeader,
1653 offset, aDrillJob->m_excellonCombinePTHNPTH );
1654 excellonWriter->SetRouteModeForOvalHoles( aDrillJob->m_excellonOvalDrillRoute );
1655 excellonWriter->SetMapFileFormat( mapFormat );
1656
1657 if( !excellonWriter->CreateDrillandMapFilesSet( outPath, true, aDrillJob->m_generateMap,
1658 m_reporter ) )
1659 {
1661 }
1662 }
1664 {
1665 GERBER_WRITER* gerberWriter = dynamic_cast<GERBER_WRITER*>( drillWriter.get() );
1666
1667 if( gerberWriter == nullptr )
1669
1670 // Set gerber precision: only 5 or 6 digits for mantissa are allowed
1671 // (SetFormat() accept 5 or 6, and any other value set the precision to 5)
1672 // the integer part precision is always 4, and units always mm
1673 gerberWriter->SetFormat( aDrillJob->m_gerberPrecision );
1674 gerberWriter->SetOptions( offset );
1675 gerberWriter->SetMapFileFormat( mapFormat );
1676
1677 if( !gerberWriter->CreateDrillandMapFilesSet( outPath, true, aDrillJob->m_generateMap,
1678 aDrillJob->m_generateTenting, m_reporter ) )
1679 {
1681 }
1682 }
1683
1684 return CLI::EXIT_CODES::OK;
1685}
1686
1687
1689{
1690 JOB_EXPORT_PCB_POS* aPosJob = dynamic_cast<JOB_EXPORT_PCB_POS*>( aJob );
1691
1692 if( aPosJob == nullptr )
1694
1695 BOARD* brd = getBoard( aPosJob->m_filename );
1696
1697 if( !brd )
1699
1700 aJob->SetTitleBlock( brd->GetTitleBlock() );
1701
1702 if( aPosJob->GetConfiguredOutputPath().IsEmpty() )
1703 {
1704 wxFileName fn = brd->GetFileName();
1705 fn.SetName( fn.GetName() );
1706
1709 else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::CSV )
1710 fn.SetExt( FILEEXT::CsvFileExtension );
1711 else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::GERBER )
1712 fn.SetExt( FILEEXT::GerberFileExtension );
1713
1714 aPosJob->SetWorkingOutputPath( fn.GetFullName() );
1715 }
1716
1717 wxString outPath = aPosJob->GetFullOutputPath( brd->GetProject() );
1718
1719 if( !PATHS::EnsurePathExists( outPath, true ) )
1720 {
1721 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1723 }
1724
1727 {
1728 wxFileName fn( outPath );
1729 wxString baseName = fn.GetName();
1730
1731 auto exportPlaceFile =
1732 [&]( bool frontSide, bool backSide, const wxString& curr_outPath ) -> bool
1733 {
1734 FILE* file = wxFopen( curr_outPath, wxS( "wt" ) );
1735 wxCHECK( file, false );
1736
1737 PLACE_FILE_EXPORTER exporter( brd,
1739 aPosJob->m_smdOnly,
1741 aPosJob->m_excludeDNP,
1742 frontSide,
1743 backSide,
1746 aPosJob->m_negateBottomX );
1747
1748 std::string data = exporter.GenPositionData();
1749 fputs( data.c_str(), file );
1750 fclose( file );
1751
1752 return true;
1753 };
1754
1755 if( aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH && !aPosJob->m_singleFile )
1756 {
1757 fn.SetName( PLACE_FILE_EXPORTER::DecorateFilename( baseName, true, false ) );
1758
1759 if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::CSV && !aPosJob->m_nakedFilename )
1760 fn.SetName( fn.GetName() + wxT( "-" ) + FILEEXT::FootprintPlaceFileExtension );
1761
1762 if( exportPlaceFile( true, false, fn.GetFullPath() ) )
1763 {
1764 m_reporter->Report( wxString::Format( _( "Wrote front position data to '%s'.\n" ),
1765 fn.GetFullPath() ),
1767
1768 aPosJob->AddOutput( fn.GetFullPath() );
1769 }
1770 else
1771 {
1773 }
1774
1775 fn.SetName( PLACE_FILE_EXPORTER::DecorateFilename( baseName, false, true ) );
1776
1777 if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::CSV && !aPosJob->m_nakedFilename )
1778 fn.SetName( fn.GetName() + wxT( "-" ) + FILEEXT::FootprintPlaceFileExtension );
1779
1780 if( exportPlaceFile( false, true, fn.GetFullPath() ) )
1781 {
1782 m_reporter->Report( wxString::Format( _( "Wrote back position data to '%s'.\n" ),
1783 fn.GetFullPath() ),
1785
1786 aPosJob->AddOutput( fn.GetFullPath() );
1787 }
1788 else
1789 {
1791 }
1792 }
1793 else
1794 {
1795 bool front = aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::FRONT
1797
1798 bool back = aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BACK
1800
1801 if( !aPosJob->m_nakedFilename )
1802 {
1803 fn.SetName( PLACE_FILE_EXPORTER::DecorateFilename( fn.GetName(), front, back ) );
1804
1806 fn.SetName( fn.GetName() + wxT( "-" ) + FILEEXT::FootprintPlaceFileExtension );
1807 }
1808
1809 if( exportPlaceFile( front, back, fn.GetFullPath() ) )
1810 {
1811 m_reporter->Report( wxString::Format( _( "Wrote position data to '%s'.\n" ),
1812 fn.GetFullPath() ),
1814
1815 aPosJob->AddOutput( fn.GetFullPath() );
1816 }
1817 else
1818 {
1820 }
1821 }
1822 }
1823 else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::GERBER )
1824 {
1825 PLACEFILE_GERBER_WRITER exporter( brd );
1826 PCB_LAYER_ID gbrLayer = F_Cu;
1827 wxString outPath_base = outPath;
1828
1830 || aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH )
1831 {
1832 if( aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH || !aPosJob->m_nakedFilename )
1833 outPath = exporter.GetPlaceFileName( outPath, gbrLayer );
1834
1835 if( exporter.CreatePlaceFile( outPath, gbrLayer, aPosJob->m_gerberBoardEdge, aPosJob->m_excludeDNP ) >= 0 )
1836 {
1837 m_reporter->Report( wxString::Format( _( "Wrote front position data to '%s'.\n" ), outPath ),
1839
1840 aPosJob->AddOutput( outPath );
1841 }
1842 else
1843 {
1845 }
1846 }
1847
1849 || aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH )
1850 {
1851 gbrLayer = B_Cu;
1852
1853 outPath = outPath_base;
1854
1855 if( aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BOTH || !aPosJob->m_nakedFilename )
1856 outPath = exporter.GetPlaceFileName( outPath, gbrLayer );
1857
1858 if( exporter.CreatePlaceFile( outPath, gbrLayer, aPosJob->m_gerberBoardEdge, aPosJob->m_excludeDNP ) >= 0 )
1859 {
1860 m_reporter->Report( wxString::Format( _( "Wrote back position data to '%s'.\n" ), outPath ),
1862
1863 aPosJob->AddOutput( outPath );
1864 }
1865 else
1866 {
1868 }
1869 }
1870 }
1871
1872 return CLI::EXIT_CODES::OK;
1873}
1874
1875
1877{
1878 JOB_FP_UPGRADE* upgradeJob = dynamic_cast<JOB_FP_UPGRADE*>( aJob );
1879
1880 if( upgradeJob == nullptr )
1882
1884
1885 if( !upgradeJob->m_outputLibraryPath.IsEmpty() )
1886 {
1887 if( wxFile::Exists( upgradeJob->m_outputLibraryPath )
1888 || wxDir::Exists( upgradeJob->m_outputLibraryPath) )
1889 {
1890 m_reporter->Report( _( "Output path must not conflict with existing path\n" ),
1893 }
1894 }
1895 else if( fileType != PCB_IO_MGR::KICAD_SEXP )
1896 {
1897 m_reporter->Report( _( "Output path must be specified to convert legacy and non-KiCad libraries\n" ),
1899
1901 }
1902
1904 {
1905 if( !wxDir::Exists( upgradeJob->m_libraryPath ) )
1906 {
1907 m_reporter->Report( _( "Footprint library path does not exist or is not accessible\n" ),
1910 }
1911
1913 FP_CACHE fpLib( &pcb_io, upgradeJob->m_libraryPath );
1914
1915 try
1916 {
1917 fpLib.Load();
1918 }
1919 catch( ... )
1920 {
1921 m_reporter->Report( _( "Unable to load library\n" ), RPT_SEVERITY_ERROR );
1923 }
1924
1925 if( m_progressReporter )
1927
1928 bool shouldSave = upgradeJob->m_force;
1929
1930 for( const auto& footprint : fpLib.GetFootprints() )
1931 {
1932 if( footprint.second->GetFootprint()->GetFileFormatVersionAtLoad() < SEXPR_BOARD_FILE_VERSION )
1933 shouldSave = true;
1934 }
1935
1936 if( shouldSave )
1937 {
1938 try
1939 {
1940 if( !upgradeJob->m_outputLibraryPath.IsEmpty() )
1941 fpLib.SetPath( upgradeJob->m_outputLibraryPath );
1942
1943 fpLib.Save();
1944 }
1945 catch( ... )
1946 {
1947 m_reporter->Report( _( "Unable to save library\n" ), RPT_SEVERITY_ERROR );
1949 }
1950 }
1951 else
1952 {
1953 m_reporter->Report( _( "Footprint library was not updated\n" ), RPT_SEVERITY_ERROR );
1954 }
1955 }
1956 else
1957 {
1958 if( !PCB_IO_MGR::ConvertLibrary( nullptr, upgradeJob->m_libraryPath,
1959 upgradeJob->m_outputLibraryPath, nullptr /* REPORTER */ ) )
1960 {
1961 m_reporter->Report( ( "Unable to convert library\n" ), RPT_SEVERITY_ERROR );
1963 }
1964 }
1965
1966 return CLI::EXIT_CODES::OK;
1967}
1968
1969
1971{
1972 JOB_FP_EXPORT_SVG* svgJob = dynamic_cast<JOB_FP_EXPORT_SVG*>( aJob );
1973
1974 if( svgJob == nullptr )
1976
1978 FP_CACHE fpLib( &pcb_io, svgJob->m_libraryPath );
1979
1980 if( svgJob->m_argLayers )
1981 {
1982 if( !svgJob->m_argLayers.value().empty() )
1983 svgJob->m_plotLayerSequence = convertLayerArg( svgJob->m_argLayers.value(), nullptr );
1984 else
1986 }
1987
1988 try
1989 {
1990 fpLib.Load();
1991 }
1992 catch( ... )
1993 {
1994 m_reporter->Report( _( "Unable to load library\n" ), RPT_SEVERITY_ERROR );
1996 }
1997
1998 wxString outPath = svgJob->GetFullOutputPath( nullptr );
1999
2000 if( !PATHS::EnsurePathExists( outPath, true ) )
2001 {
2002 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
2004 }
2005
2006 int exitCode = CLI::EXIT_CODES::OK;
2007 bool singleFpPlotted = false;
2008
2009 for( const auto& [fpName, fpCacheEntry] : fpLib.GetFootprints() )
2010 {
2011 if( m_progressReporter )
2012 {
2013 m_progressReporter->AdvancePhase( wxString::Format( _( "Exporting %s" ), fpName ) );
2015 }
2016
2017 if( !svgJob->m_footprint.IsEmpty() )
2018 {
2019 // skip until we find the right footprint
2020 if( fpName != svgJob->m_footprint )
2021 continue;
2022 else
2023 singleFpPlotted = true;
2024 }
2025
2026 exitCode = doFpExportSvg( svgJob, fpCacheEntry->GetFootprint().get() );
2027
2028 if( exitCode != CLI::EXIT_CODES::OK )
2029 break;
2030 }
2031
2032 if( !svgJob->m_footprint.IsEmpty() && !singleFpPlotted )
2033 {
2034 m_reporter->Report( _( "The given footprint could not be found to export." ) + wxS( "\n" ),
2036 }
2037
2038 return CLI::EXIT_CODES::OK;
2039}
2040
2041
2043{
2044 // the hack for now is we create fake boards containing the footprint and plot the board
2045 // until we refactor better plot api later
2046 std::unique_ptr<BOARD> brd;
2047 brd.reset( CreateEmptyBoard() );
2048 brd->GetProject()->ApplyTextVars( aSvgJob->GetVarOverrides() );
2049 brd->SynchronizeProperties();
2050
2051 FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( aFootprint->Clone() );
2052
2053 if( fp == nullptr )
2055
2056 fp->SetLink( niluuid );
2057 fp->SetFlags( IS_NEW );
2058 fp->SetParent( brd.get() );
2059
2060 for( PAD* pad : fp->Pads() )
2061 {
2062 pad->SetLocalRatsnestVisible( false );
2063 pad->SetNetCode( 0 );
2064 }
2065
2066 fp->SetOrientation( ANGLE_0 );
2067 fp->SetPosition( VECTOR2I( 0, 0 ) );
2068
2069 brd->Add( fp, ADD_MODE::INSERT, true );
2070
2071 wxFileName outputFile;
2072 outputFile.SetPath( aSvgJob->GetFullOutputPath(nullptr) );
2073 outputFile.SetName( aFootprint->GetFPID().GetLibItemName().wx_str() );
2074 outputFile.SetExt( FILEEXT::SVGFileExtension );
2075
2076 m_reporter->Report( wxString::Format( _( "Plotting footprint '%s' to '%s'\n" ),
2077 aFootprint->GetFPID().GetLibItemName().wx_str(),
2078 outputFile.GetFullPath() ),
2080
2081 PCB_PLOT_PARAMS plotOpts;
2082 PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, aSvgJob, *m_reporter );
2083
2084 // always fixed for the svg plot
2085 plotOpts.SetPlotFrameRef( false );
2086 plotOpts.SetSvgFitPageToBoard( true );
2087 plotOpts.SetMirror( false );
2088 plotOpts.SetSkipPlotNPTH_Pads( false );
2089
2090 if( plotOpts.GetSketchPadsOnFabLayers() )
2091 {
2092 plotOpts.SetPlotPadNumbers( true );
2093 }
2094
2095 PCB_PLOTTER plotter( brd.get(), m_reporter, plotOpts );
2096
2097 if( !plotter.Plot( outputFile.GetFullPath(),
2098 aSvgJob->m_plotLayerSequence,
2100 false,
2101 true,
2102 wxEmptyString, wxEmptyString,
2103 wxEmptyString ) )
2104 {
2105 m_reporter->Report( _( "Error creating svg file" ) + wxS( "\n" ), RPT_SEVERITY_ERROR );
2107 }
2108
2109 return CLI::EXIT_CODES::OK;
2110}
2111
2112
2114{
2115 JOB_PCB_DRC* drcJob = dynamic_cast<JOB_PCB_DRC*>( aJob );
2116
2117 if( drcJob == nullptr )
2119
2120 BOARD* brd = getBoard( drcJob->m_filename );
2121
2122 if( !brd )
2124
2125 aJob->SetTitleBlock( brd->GetTitleBlock() );
2126 brd->GetProject()->ApplyTextVars( aJob->GetVarOverrides() );
2127 brd->SynchronizeProperties();
2128
2129 if( drcJob->GetConfiguredOutputPath().IsEmpty() )
2130 {
2131 wxFileName fn = brd->GetFileName();
2132 fn.SetName( fn.GetName() + wxS( "-drc" ) );
2133
2135 fn.SetExt( FILEEXT::JsonFileExtension );
2136 else
2137 fn.SetExt( FILEEXT::ReportFileExtension );
2138
2139 drcJob->SetWorkingOutputPath( fn.GetFullName() );
2140 }
2141
2142 wxString outPath = drcJob->GetFullOutputPath( brd->GetProject() );
2143
2144 if( !PATHS::EnsurePathExists( outPath, true ) )
2145 {
2146 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
2148 }
2149
2150 EDA_UNITS units;
2151
2152 switch( drcJob->m_units )
2153 {
2154 case JOB_PCB_DRC::UNITS::INCH: units = EDA_UNITS::INCH; break;
2155 case JOB_PCB_DRC::UNITS::MILS: units = EDA_UNITS::MILS; break;
2156 case JOB_PCB_DRC::UNITS::MM: units = EDA_UNITS::MM; break;
2157 default: units = EDA_UNITS::MM; break;
2158 }
2159
2160 std::shared_ptr<DRC_ENGINE> drcEngine = brd->GetDesignSettings().m_DRCEngine;
2161 std::unique_ptr<NETLIST> netlist = std::make_unique<NETLIST>();
2162
2163 drcEngine->SetDrawingSheet( getDrawingSheetProxyView( brd ) );
2164
2165 // BOARD_COMMIT uses TOOL_MANAGER to grab the board internally so we must give it one
2166 TOOL_MANAGER* toolManager = getToolManager( brd );
2167
2168 BOARD_COMMIT commit( toolManager );
2169 bool checkParity = drcJob->m_parity;
2170 std::string netlist_str;
2171
2172 if( checkParity )
2173 {
2174 wxString annotateMsg = _( "Schematic parity tests require a fully annotated schematic." );
2175 netlist_str = annotateMsg;
2176
2177 // The KIFACE_NETLIST_SCHEMATIC function has some broken-ness that the schematic
2178 // frame's version does not, but it is the only one that works in CLI, so we use it
2179 // if we don't have the sch frame open.
2180 // TODO: clean this up, see https://gitlab.com/kicad/code/kicad/-/issues/19929
2181 if( m_kiway->Player( FRAME_SCH, false ) )
2182 {
2184 }
2185 else
2186 {
2187 wxFileName schematicPath( drcJob->m_filename );
2188 schematicPath.SetExt( FILEEXT::KiCadSchematicFileExtension );
2189
2190 if( !schematicPath.Exists() )
2191 schematicPath.SetExt( FILEEXT::LegacySchematicFileExtension );
2192
2193 if( !schematicPath.Exists() )
2194 {
2195 m_reporter->Report( _( "Failed to fetch schematic netlist for parity tests.\n" ),
2197 checkParity = false;
2198 }
2199 else
2200 {
2201 typedef bool ( *NETLIST_FN_PTR )( const wxString&, std::string& );
2203 NETLIST_FN_PTR netlister =
2204 (NETLIST_FN_PTR) eeschema->IfaceOrAddress( KIFACE_NETLIST_SCHEMATIC );
2205 ( *netlister )( schematicPath.GetFullPath(), netlist_str );
2206 }
2207 }
2208
2209 if( netlist_str == annotateMsg )
2210 {
2211 m_reporter->Report( wxString( netlist_str ) + wxT( "\n" ), RPT_SEVERITY_ERROR );
2212 checkParity = false;
2213 }
2214 }
2215
2216 if( checkParity )
2217 {
2218 try
2219 {
2220 STRING_LINE_READER* lineReader = new STRING_LINE_READER( netlist_str,
2221 _( "Eeschema netlist" ) );
2222 KICAD_NETLIST_READER netlistReader( lineReader, netlist.get() );
2223
2224 netlistReader.LoadNetlist();
2225 }
2226 catch( const IO_ERROR& )
2227 {
2228 m_reporter->Report( _( "Failed to fetch schematic netlist for parity tests.\n" ),
2230 checkParity = false;
2231 }
2232
2233 drcEngine->SetSchematicNetlist( netlist.get() );
2234 }
2235
2236 if( drcJob->m_refillZones )
2237 {
2238 if( !toolManager->FindTool( ZONE_FILLER_TOOL_NAME ) )
2239 toolManager->RegisterTool( new ZONE_FILLER_TOOL );
2240
2241 toolManager->GetTool<ZONE_FILLER_TOOL>()->FillAllZones( nullptr, m_progressReporter, true );
2242 }
2243
2244 drcEngine->SetProgressReporter( m_progressReporter );
2245 drcEngine->SetViolationHandler(
2246 [&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
2247 DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
2248 {
2249 PCB_MARKER* marker = new PCB_MARKER( aItem, aPos, aLayer );
2250 commit.Add( marker );
2251 } );
2252
2253 brd->RecordDRCExclusions();
2254 brd->DeleteMARKERs( true, true );
2255 drcEngine->RunTests( units, drcJob->m_reportAllTrackErrors, checkParity );
2256 drcEngine->ClearViolationHandler();
2257
2258 commit.Push( _( "DRC" ), SKIP_UNDO | SKIP_SET_DIRTY );
2259
2260 // Update the exclusion status on any excluded markers that still exist.
2261 brd->ResolveDRCExclusions( false );
2262
2263 std::shared_ptr<DRC_ITEMS_PROVIDER> markersProvider = std::make_shared<DRC_ITEMS_PROVIDER>(
2265
2266 std::shared_ptr<DRC_ITEMS_PROVIDER> ratsnestProvider =
2267 std::make_shared<DRC_ITEMS_PROVIDER>( brd, MARKER_BASE::MARKER_RATSNEST );
2268
2269 std::shared_ptr<DRC_ITEMS_PROVIDER> fpWarningsProvider =
2270 std::make_shared<DRC_ITEMS_PROVIDER>( brd, MARKER_BASE::MARKER_PARITY );
2271
2272 markersProvider->SetSeverities( drcJob->m_severity );
2273 ratsnestProvider->SetSeverities( drcJob->m_severity );
2274 fpWarningsProvider->SetSeverities( drcJob->m_severity );
2275
2276 m_reporter->Report( wxString::Format( _( "Found %d violations\n" ),
2277 markersProvider->GetCount() ),
2279 m_reporter->Report( wxString::Format( _( "Found %d unconnected items\n" ),
2280 ratsnestProvider->GetCount() ),
2282
2283 if( checkParity )
2284 {
2285 m_reporter->Report( wxString::Format( _( "Found %d schematic parity issues\n" ),
2286 fpWarningsProvider->GetCount() ),
2288 }
2289
2290 DRC_REPORT reportWriter( brd, units, markersProvider, ratsnestProvider, fpWarningsProvider );
2291
2292 bool wroteReport = false;
2293
2295 wroteReport = reportWriter.WriteJsonReport( outPath );
2296 else
2297 wroteReport = reportWriter.WriteTextReport( outPath );
2298
2299 if( !wroteReport )
2300 {
2301 m_reporter->Report( wxString::Format( _( "Unable to save DRC report to %s\n" ), outPath ),
2304 }
2305
2306 m_reporter->Report( wxString::Format( _( "Saved DRC Report to %s\n" ), outPath ),
2308
2309 if( drcJob->m_refillZones && drcJob->m_saveBoard )
2310 {
2311 if( SaveBoard( drcJob->m_filename, brd, true ) )
2312 {
2313 m_reporter->Report( _( "Saved board\n" ), RPT_SEVERITY_ACTION );
2314 }
2315 else
2316 {
2317 m_reporter->Report( _( "Failed to save board.\n" ), RPT_SEVERITY_ERROR );
2318
2320 }
2321 }
2322
2323 if( drcJob->m_exitCodeViolations )
2324 {
2325 if( markersProvider->GetCount() > 0 || ratsnestProvider->GetCount() > 0
2326 || fpWarningsProvider->GetCount() > 0 )
2327 {
2329 }
2330 }
2331
2333}
2334
2335
2337{
2338 JOB_EXPORT_PCB_IPC2581* job = dynamic_cast<JOB_EXPORT_PCB_IPC2581*>( aJob );
2339
2340 if( job == nullptr )
2342
2343 BOARD* brd = getBoard( job->m_filename );
2344
2345 if( !brd )
2347
2348 aJob->SetTitleBlock( brd->GetTitleBlock() );
2349
2350 if( job->GetConfiguredOutputPath().IsEmpty() )
2351 {
2352 wxFileName fn = brd->GetFileName();
2353 fn.SetName( fn.GetName() );
2354 fn.SetExt( FILEEXT::Ipc2581FileExtension );
2355
2356 job->SetWorkingOutputPath( fn.GetName() );
2357 }
2358
2359 wxString outPath = job->GetFullOutputPath( brd->GetProject() );
2360
2361 if( !PATHS::EnsurePathExists( outPath, true ) )
2362 {
2363 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
2365 }
2366
2367 std::map<std::string, UTF8> props;
2368 props["units"] = job->m_units == JOB_EXPORT_PCB_IPC2581::IPC2581_UNITS::MM ? "mm" : "inch";
2369 props["sigfig"] = wxString::Format( "%d", job->m_precision );
2370 props["version"] = job->m_version == JOB_EXPORT_PCB_IPC2581::IPC2581_VERSION::C ? "C" : "B";
2371 props["OEMRef"] = job->m_colInternalId;
2372 props["mpn"] = job->m_colMfgPn;
2373 props["mfg"] = job->m_colMfg;
2374 props["dist"] = job->m_colDist;
2375 props["distpn"] = job->m_colDistPn;
2376
2377 wxString tempFile = wxFileName::CreateTempFileName( wxS( "pcbnew_ipc" ) );
2378 try
2379 {
2381 pi->SetProgressReporter( m_progressReporter );
2382 pi->SaveBoard( tempFile, brd, &props );
2383 }
2384 catch( const IO_ERROR& ioe )
2385 {
2386 m_reporter->Report( wxString::Format( _( "Error generating IPC-2581 file '%s'.\n%s" ),
2387 job->m_filename,
2388 ioe.What() ),
2390
2391 wxRemoveFile( tempFile );
2392
2394 }
2395
2396 if( job->m_compress )
2397 {
2398 wxFileName tempfn = outPath;
2399 tempfn.SetExt( FILEEXT::Ipc2581FileExtension );
2400 wxFileName zipfn = tempFile;
2401 zipfn.SetExt( "zip" );
2402
2403 {
2404 wxFFileOutputStream fnout( zipfn.GetFullPath() );
2405 wxZipOutputStream zip( fnout );
2406 wxFFileInputStream fnin( tempFile );
2407
2408 zip.PutNextEntry( tempfn.GetFullName() );
2409 fnin.Read( zip );
2410 }
2411
2412 wxRemoveFile( tempFile );
2413 tempFile = zipfn.GetFullPath();
2414 }
2415
2416 // If save succeeded, replace the original with what we just wrote
2417 if( !wxRenameFile( tempFile, outPath ) )
2418 {
2419 m_reporter->Report( wxString::Format( _( "Error generating IPC-2581 file '%s'.\n"
2420 "Failed to rename temporary file '%s." ),
2421 outPath,
2422 tempFile ),
2424 }
2425
2427}
2428
2429
2431{
2432 JOB_EXPORT_PCB_IPCD356* job = dynamic_cast<JOB_EXPORT_PCB_IPCD356*>( aJob );
2433
2434 if( job == nullptr )
2436
2437 BOARD* brd = getBoard( job->m_filename );
2438
2439 if( !brd )
2441
2442 aJob->SetTitleBlock( brd->GetTitleBlock() );
2443
2444 if( job->GetConfiguredOutputPath().IsEmpty() )
2445 {
2446 wxFileName fn = brd->GetFileName();
2447 fn.SetName( fn.GetName() );
2448 fn.SetExt( FILEEXT::IpcD356FileExtension );
2449
2450 job->SetWorkingOutputPath( fn.GetFullName() );
2451 }
2452
2453 wxString outPath = job->GetFullOutputPath( brd->GetProject() );
2454
2455 if( !PATHS::EnsurePathExists( outPath, true ) )
2456 {
2457 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
2459 }
2460
2461 IPC356D_WRITER exporter( brd );
2462
2463 bool success = exporter.Write( outPath );
2464
2465 if( success )
2466 {
2467 m_reporter->Report( _( "Successfully created IPC-D-356 file\n" ), RPT_SEVERITY_INFO );
2469 }
2470 else
2471 {
2472 m_reporter->Report( _( "Failed to create IPC-D-356 file\n" ), RPT_SEVERITY_ERROR );
2474 }
2475}
2476
2477
2479{
2480 JOB_EXPORT_PCB_ODB* job = dynamic_cast<JOB_EXPORT_PCB_ODB*>( aJob );
2481
2482 if( job == nullptr )
2484
2485 BOARD* brd = getBoard( job->m_filename );
2486
2487 if( !brd )
2489
2490 aJob->SetTitleBlock( brd->GetTitleBlock() );
2491
2492 wxString path = job->GetConfiguredOutputPath();
2493
2494 if( job->GetConfiguredOutputPath().IsEmpty() )
2495 {
2497 {
2498 // just basic folder name
2499 job->SetWorkingOutputPath( "odb" );
2500 }
2501 else
2502 {
2503 wxFileName fn( brd->GetFileName() );
2504 fn.SetName( fn.GetName() + wxS( "-odb" ) );
2505
2506 switch( job->m_compressionMode )
2507 {
2509 fn.SetExt( FILEEXT::ArchiveFileExtension );
2510 break;
2512 fn.SetExt( "tgz" );
2513 break;
2514 default:
2515 break;
2516 };
2517
2518 job->SetWorkingOutputPath( fn.GetFullName() );
2519 }
2520 }
2521
2523
2525}
2526
2527
2529{
2531 &aBrd->GetPageSettings(),
2532 aBrd->GetProject(),
2533 &aBrd->GetTitleBlock(),
2534 &aBrd->GetProperties() );
2535
2536 drawingSheet->SetSheetName( std::string() );
2537 drawingSheet->SetSheetPath( std::string() );
2538 drawingSheet->SetIsFirstPage( true );
2539
2540 drawingSheet->SetFileName( TO_UTF8( aBrd->GetFileName() ) );
2541
2542 return drawingSheet;
2543}
2544
2545
2546void PCBNEW_JOBS_HANDLER::loadOverrideDrawingSheet( BOARD* aBrd, const wxString& aSheetPath )
2547{
2548 // dont bother attempting to load a empty path, if there was one
2549 if( aSheetPath.IsEmpty() )
2550 return;
2551
2552 auto loadSheet =
2553 [&]( const wxString& path ) -> bool
2554 {
2557 resolver.SetProject( aBrd->GetProject() );
2559
2561 aBrd->GetProject()->GetProjectPath(),
2562 { aBrd->GetEmbeddedFiles() } );
2563 wxString msg;
2564
2565 if( !DS_DATA_MODEL::GetTheInstance().LoadDrawingSheet( filename, &msg ) )
2566 {
2567 m_reporter->Report( wxString::Format( _( "Error loading drawing sheet '%s'." ),
2568 path )
2569 + wxS( "\n" ) + msg + wxS( "\n" ),
2571 return false;
2572 }
2573
2574 return true;
2575 };
2576
2577 if( loadSheet( aSheetPath ) )
2578 return;
2579
2580 // failed loading custom path, revert back to default
2581 loadSheet( aBrd->GetProject()->GetProjectFile().m_BoardDrawingSheetFile );
2582}
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.
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:2657
const PAGE_INFO & GetPageSettings() const
Definition: board.h:742
void RecordDRCExclusions()
Scan existing markers and record data from any that are Excluded.
Definition: board.cpp:329
TITLE_BLOCK & GetTitleBlock()
Definition: board.h:748
BOX2I ComputeBoundingBox(bool aBoardEdgesOnly=false) const
Calculate the bounding box containing all board items (or board edge segments).
Definition: board.cpp:1851
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:386
const PCB_PLOT_PARAMS & GetPlotOptions() const
Definition: board.h:745
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:680
PROJECT * GetProject() const
Definition: board.h:538
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:1024
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:907
void SynchronizeProperties()
Copy the current project's text variables into the boards property cache.
Definition: board.cpp:2221
void DeleteMARKERs()
Delete all MARKERS from the board.
Definition: board.cpp:1530
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:118
bool WriteTextReport(const wxString &aFullFileName)
Definition: drc_report.cpp:48
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:142
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:113
Create Excellon drill, drill map, and drill report files.
void SetFormat(bool aMetric, ZEROS_FMT aZerosFmt=DECIMAL_FORMAT, int aLeftDigits=0, int aRightDigits=0)
Initialize internal parameters to match the given format.
bool CreateDrillandMapFilesSet(const wxString &aPlotDirectory, bool aGenDrill, bool aGenMap, REPORTER *aReporter=nullptr)
Create the full set of Excellon drill file for the board.
void SetOptions(bool aMirror, bool aMinimalHeader, const VECTOR2I &aOffset, bool aMerge_PTH_NPTH)
Initialize internal parameters to match drill options.
void SetRouteModeForOvalHoles(bool aUseRouteModeForOvalHoles)
wxString m_outputFile
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:2513
void SetLink(const KIID &aLink)
Definition: footprint.h:844
void SetOrientation(const EDA_ANGLE &aNewAngle)
Definition: footprint.cpp:2595
EDA_ITEM * Clone() const override
Invoke a function on all children.
Definition: footprint.cpp:2250
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.
wxString GetSettingsDialogTitle() const override
ODB_COMPRESSION m_compressionMode
@ ALL_LAYERS_ONE_FILE
DEPRECATED MODE.
GEN_MODE m_pdfGenMode
The background color specified in a hex string.
LSEQ m_plotOnAllLayersSequence
Used by SVG & PDF.
std::optional< wxString > m_argLayers
std::optional< wxString > m_argCommonLayers
LSEQ m_plotLayerSequence
Layers to include on all individual layer prints.
wxString m_libraryPath
wxString m_outputLibraryPath
bool m_parity
Definition: job_pcb_drc.h:33
bool m_saveBoard
Definition: job_pcb_drc.h:36
bool m_reportAllTrackErrors
Definition: job_pcb_drc.h:32
bool m_refillZones
Definition: job_pcb_drc.h:35
VECTOR3D m_lightBottomIntensity
VECTOR3D m_lightTopIntensity
BG_STYLE m_bgStyle
VECTOR3D m_lightCameraIntensity
VECTOR3D m_rotation
bool m_proceduralTextures
wxString m_filename
bool m_useBoardStackupColors
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:215
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:232
void SetTitleBlock(const TITLE_BLOCK &aTitleBlock)
Definition: job.h:203
void SetWorkingOutputPath(const wxString &aPath)
Sets a transient output path for the job, it takes priority over the configured output path when GetF...
Definition: job.h:238
const std::map< wxString, wxString > & GetVarOverrides() const
Definition: job.h:196
Read the new s-expression based KiCad netlist format.
virtual void LoadNetlist() override
Load the contents of the netlist file into aNetlist.
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h: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:477
int JobExportFpUpgrade(JOB *aJob)
DS_PROXY_VIEW_ITEM * getDrawingSheetProxyView(BOARD *aBrd)
void loadOverrideDrawingSheet(BOARD *brd, const wxString &aSheetPath)
PCBNEW_JOBS_HANDLER(KIWAY *aKiway)
TOOL_MANAGER * getToolManager(BOARD *aBrd)
BOARD * getBoard(const wxString &aPath=wxEmptyString)
std::unique_ptr< TOOL_MANAGER > m_toolManager
LSEQ convertLayerArg(wxString &aLayerString, BOARD *aBoard) const
int 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:68
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:190
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:135
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:170
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:143
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition: project.cpp:149
virtual void ApplyTextVars(const std::map< wxString, wxString > &aVarsMap)
Applies the given var map, it will create or update existing vars.
Definition: project.cpp:104
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
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:55
Master controller class:
Definition: tool_manager.h:62
TOOL_BASE * FindTool(int aId) const
Search for a tool with given ID.
void RegisterTool(TOOL_BASE *aTool)
Add a tool to the manager set and sets it up.
void SetEnvironment(EDA_ITEM *aModel, KIGFX::VIEW *aView, KIGFX::VIEW_CONTROLS *aViewControls, APP_SETTINGS_BASE *aSettings, TOOLS_HOLDER *aFrame)
Set the work environment (model, view, view controls and the parent window).
void Pan_T1(const SFVEC3F &aDeltaOffsetInc) override
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
Handle actions specific to filling copper zones.
wxString GetDefaultPlotExtension(PLOT_FORMAT aFormat)
Return the default plot extension for a format.
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp: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.
bool SaveBoard(wxString &aFileName, BOARD *aBoard, PCB_IO_MGR::PCB_FILE_T aFormat, bool aSkipSettings)
BOARD * LoadBoard(const wxString &aFileName, bool aSetActive)
Loads a board from file This function identifies the file type by extension and determines the correc...
const wxString GetGerberProtelExtension(int aLayer)
Definition: pcbplot.cpp:43
void BuildPlotFileName(wxFileName *aFilename, const wxString &aOutputDir, const wxString &aSuffix, const wxString &aExtension)
Complete a plot filename.
Definition: pcbplot.cpp:379
PLOTTER * StartPlotBoard(BOARD *aBoard, const PCB_PLOT_PARAMS *aPlotOpts, int aLayer, const wxString &aLayerName, const wxString &aFullFileName, const wxString &aSheetName, const wxString &aSheetPath, const wxString &aPageName=wxT("1"), const wxString &aPageNumber=wxEmptyString, const int aPageCount=1)
Open a new plotfile using the options (and especially the format) specified in the options and prepar...
void PlotBoardLayers(BOARD *aBoard, PLOTTER *aPlotter, const LSEQ &aLayerSequence, const PCB_PLOT_PARAMS &aPlotOptions)
Plot a sequence of board layer IDs.
PGM_BASE & Pgm()
The global program "get" accessor.
Definition: pgm_base.cpp:902
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
#define ZONE_FILLER_TOOL_NAME