KiCad PCB EDA Suite
Loading...
Searching...
No Matches
command_pcb_render.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 (C) 2024 Alex Shvartzkop <[email protected]>
6 * Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software: you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include "command_pcb_render.h"
23#include <cli/exit_codes.h>
24#include "jobs/job_pcb_render.h"
25#include <kiface_base.h>
26#include <layer_ids.h>
27#include <string_utils.h>
28#include <wx/crt.h>
29#include <magic_enum.hpp>
30
31#include <macros.h>
32#include <wx/tokenzr.h>
33#include "../../3d-viewer/3d_viewer/eda_3d_viewer_settings.h"
34#include <math/vector3.h>
35
36#define ARG_BACKGROUND "--background"
37#define ARG_QUALITY "--quality"
38
39#define ARG_WIDTH "--width"
40#define ARG_WIDTH_SHORT "-w"
41
42#define ARG_HEIGHT "--height"
43#define ARG_HEIGHT_SHORT "-h"
44
45#define ARG_SIDE "--side"
46#define ARG_PRESET "--preset"
47#define ARG_PAN "--pan"
48#define ARG_PIVOT "--pivot"
49#define ARG_ROTATE "--rotate"
50#define ARG_ZOOM "--zoom"
51#define ARG_PERSPECTIVE "--perspective"
52#define ARG_FLOOR "--floor"
53
54
55template <typename T>
56static wxString enumString()
57{
58 wxString str;
59 auto names = magic_enum::enum_names<T>();
60
61 for( size_t i = 0; i < names.size(); i++ )
62 {
63 std::string name = { names[i].begin(), names[i].end() };
64
65 if( i > 0 )
66 str << ", ";
67
68 std::transform( name.begin(), name.end(), name.begin(),
69 []( unsigned char c )
70 {
71 return std::tolower( c );
72 } );
73
74 str << name;
75 }
76
77 return str;
78}
79
80
81template <typename T>
82static std::vector<std::string> enumChoices()
83{
84 std::vector<std::string> out;
85
86 for( auto& strView : magic_enum::enum_names<T>() )
87 {
88 std::string name = { strView.begin(), strView.end() };
89
90 std::transform( name.begin(), name.end(), name.begin(),
91 []( unsigned char c )
92 {
93 return std::tolower( c );
94 } );
95
96 out.emplace_back( name );
97 }
98
99 return out;
100}
101
102
103template <typename T>
104static std::optional<T> strToEnum( std::string& aInput )
105{
106 return magic_enum::enum_cast<T>( aInput, magic_enum::case_insensitive );
107}
108
109
110template <typename T>
111static bool getToEnum( const std::string& aInput, T& aOutput )
112{
113 // If not specified, leave at default
114 if( aInput.empty() )
115 return true;
116
117 if( auto opt = magic_enum::enum_cast<T>( aInput, magic_enum::case_insensitive ) )
118 {
119 aOutput = *opt;
120 return true;
121 }
122
123 return false;
124}
125
126
127static bool getToVector3( const std::string& aInput, VECTOR3D& aOutput )
128{
129 // If not specified, leave at default
130 if( aInput.empty() )
131 return true;
132
133 // Remove potential quotes
134 wxString wxStr = From_UTF8( aInput );
135
136 if( wxStr[0] == '\'' )
137 wxStr = wxStr.AfterFirst( '\'' );
138
139 if( wxStr[wxStr.length() - 1] == '\'' )
140 wxStr = wxStr.BeforeLast( '\'' );
141
142 wxArrayString arr = wxSplit( wxStr, ',', 0 );
143
144 if( arr.size() != 3 )
145 return false;
146
147 VECTOR3D vec;
148 bool success = true;
149 success &= arr[0].Trim().ToCDouble( &vec.x );
150 success &= arr[1].Trim().ToCDouble( &vec.y );
151 success &= arr[2].Trim().ToCDouble( &vec.z );
152
153 if( !success )
154 return false;
155
156 aOutput = vec;
157 return true;
158}
159
160
162{
163 addCommonArgs( true, true, false, false );
164 addDefineArg();
165
166 m_argParser.add_description(
167 UTF8STDSTR( _( "Renders the PCB in 3D view to PNG or JPEG image" ) ) );
168
169 m_argParser.add_argument( ARG_WIDTH, ARG_WIDTH_SHORT )
170 .default_value( 1600 )
171 .scan<'i', int>()
172 .metavar( "WIDTH" )
173 .help( UTF8STDSTR( _( "Image width" ) ) );
174
176 .default_value( 900 )
177 .scan<'i', int>()
178 .metavar( "HEIGHT" )
179 .help( UTF8STDSTR( _( "Image height" ) ) );
180
181 m_argParser.add_argument( ARG_SIDE )
182 .default_value( std::string( "top" ) )
183 .add_choices( enumChoices<JOB_PCB_RENDER::SIDE>() )
184 .metavar( "SIDE" )
185 .help( UTF8STDSTR( wxString::Format( _( "Render from side. Options: %s" ),
186 enumString<JOB_PCB_RENDER::SIDE>() ) ) );
187
188 m_argParser.add_argument( ARG_BACKGROUND )
189 .default_value( std::string( "" ) )
190 .help( UTF8STDSTR( _( "Image background. Options: transparent, opaque. Default: "
191 "transparent for PNG, opaque for JPEG" ) ) )
192 .metavar( "BG" );
193
194 m_argParser.add_argument( ARG_QUALITY )
195 .default_value( std::string( "basic" ) )
196 .add_choices( enumChoices<JOB_PCB_RENDER::QUALITY>() )
197 .metavar( "QUALITY" )
198 .help( UTF8STDSTR( wxString::Format( _( "Render quality. Options: %s" ),
199 enumString<JOB_PCB_RENDER::QUALITY>() ) ) );
200
201 m_argParser.add_argument( ARG_PRESET )
202 .default_value( std::string( wxString( FOLLOW_PLOT_SETTINGS ) ) )
203 .metavar( "PRESET" )
204 .help( UTF8STDSTR( wxString::Format( _( "Color preset. Options: %s, %s, %s, ..." ),
206 LEGACY_PRESET_FLAG ) ) );
207
208 m_argParser.add_argument( ARG_FLOOR )
209 .flag()
210 .help( UTF8STDSTR( _( "Enables floor, shadows and post-processing, even if disabled in "
211 "quality preset" ) ) );
212
213 m_argParser.add_argument( ARG_PERSPECTIVE )
214 .flag()
215 .help( UTF8STDSTR( _( "Use perspective projection instead of orthogonal" ) ) );
216
217 m_argParser.add_argument( ARG_ZOOM )
218 .default_value( 1.0 )
219 .scan<'g', double>()
220 .metavar( "ZOOM" )
221 .help( UTF8STDSTR( _( "Camera zoom" ) ) );
222
223 m_argParser.add_argument( ARG_PAN )
224 .default_value( std::string( "" ) )
225 .metavar( "VECTOR" )
226 .help( UTF8STDSTR( _( "Pan camera, format 'X,Y,Z' e.g.: '3,0,0'" ) ) );
227
228 m_argParser.add_argument( ARG_PIVOT )
229 .default_value( std::string( "" ) )
230 .metavar( "PIVOT" )
231 .help( UTF8STDSTR( _( "Set pivot point relative to the board center in centimeters, format 'X,Y,Z' "
232 "e.g.: '-10,2,0'" ) ) );
233
234 m_argParser.add_argument( ARG_ROTATE )
235 .default_value( std::string( "" ) )
236 .metavar( "ANGLES" )
237 .help( UTF8STDSTR(
238 _( "Rotate board, format 'X,Y,Z' e.g.: '-45,0,45' for isometric view" ) ) );
239}
240
241
243{
244 std::unique_ptr<JOB_PCB_RENDER> renderJob( new JOB_PCB_RENDER() );
245
246 renderJob->m_outputFile = m_argOutput;
247 renderJob->m_filename = m_argInput;
248 renderJob->SetVarOverrides( m_argDefineVars );
249
250 renderJob->m_colorPreset = m_argParser.get<std::string>( ARG_PRESET );
251 renderJob->m_width = m_argParser.get<int>( ARG_WIDTH );
252 renderJob->m_height = m_argParser.get<int>( ARG_HEIGHT );
253 renderJob->m_zoom = m_argParser.get<double>( ARG_ZOOM );
254 renderJob->m_perspective = m_argParser.get<bool>( ARG_PERSPECTIVE );
255 renderJob->m_floor = m_argParser.get<bool>( ARG_FLOOR );
256
257 getToEnum( m_argParser.get<std::string>( ARG_QUALITY ), renderJob->m_quality );
258 getToEnum( m_argParser.get<std::string>( ARG_SIDE ), renderJob->m_side );
259
260 if( !getToEnum( m_argParser.get<std::string>( ARG_BACKGROUND ), renderJob->m_bgStyle ) )
261 {
262 wxFprintf( stderr, _( "Invalid background\n" ) );
264 }
265
266 if( !getToVector3( m_argParser.get<std::string>( ARG_ROTATE ), renderJob->m_rotation ) )
267 {
268 wxFprintf( stderr, _( "Invalid rotation format\n" ) );
270 }
271
272 if( !getToVector3( m_argParser.get<std::string>( ARG_PAN ), renderJob->m_pan ) )
273 {
274 wxFprintf( stderr, _( "Invalid pan format\n" ) );
276 }
277
278 if( !getToVector3( m_argParser.get<std::string>( ARG_PIVOT ), renderJob->m_pivot ) )
279 {
280 wxFprintf( stderr, _( "Invalid pivot format\n" ) );
282 }
283
284 if( m_argOutput.Lower().EndsWith( wxS( ".png" ) ) )
285 {
286 renderJob->m_format = JOB_PCB_RENDER::FORMAT::PNG;
287 }
288 else if( m_argOutput.Lower().EndsWith( wxS( ".jpg" ) )
289 || m_argOutput.Lower().EndsWith( wxS( ".jpeg" ) ) )
290 {
291 renderJob->m_format = JOB_PCB_RENDER::FORMAT::JPEG;
292 }
293 else
294 {
295 wxFprintf( stderr, _( "Invalid image format\n" ) );
297 }
298
299 int exitCode = aKiway.ProcessJob( KIWAY::FACE_PCB, renderJob.get() );
300
301 return exitCode;
302}
const char * name
Definition: DXF_plotter.cpp:57
argparse::ArgumentParser m_argParser
Definition: command.h:100
void addDefineArg()
Set up the drawing sheet arg used by many of the export commands.
Definition: command.cpp:169
void addCommonArgs(bool aInput, bool aOutput, bool aInputIsDir, bool aOutputIsDir)
Set up the most common of args used across cli.
Definition: command.cpp:115
int doPerform(KIWAY &aKiway) override
The internal handler that should be overloaded to implement command specific processing and work.
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition: kiway.h:285
@ FACE_PCB
pcbnew DSO
Definition: kiway.h:293
int ProcessJob(KIWAY::FACE_T aFace, JOB *aJob, REPORTER *aReporter=nullptr)
Definition: kiway.cpp:709
T y
Definition: vector3.h:64
T z
Definition: vector3.h:65
T x
Definition: vector3.h:63
#define UTF8STDSTR(s)
Definition: command.h:27
#define ARG_SIDE
#define ARG_FLOOR
#define ARG_WIDTH_SHORT
static bool getToVector3(const std::string &aInput, VECTOR3D &aOutput)
#define ARG_HEIGHT_SHORT
#define ARG_PRESET
#define ARG_ROTATE
#define ARG_BACKGROUND
#define ARG_PERSPECTIVE
#define ARG_HEIGHT
#define ARG_PAN
#define ARG_PIVOT
#define ARG_WIDTH
static bool getToEnum(const std::string &aInput, T &aOutput)
static std::vector< std::string > enumChoices()
static wxString enumString()
#define ARG_ZOOM
#define ARG_QUALITY
static std::optional< T > strToEnum(std::string &aInput)
#define _(s)
#define FOLLOW_PLOT_SETTINGS
#define LEGACY_PRESET_FLAG
#define FOLLOW_PCB
This file contains miscellaneous commonly used macros and functions.
static const int ERR_ARGS
Definition: exit_codes.h:31
wxString From_UTF8(const char *cstring)