KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_export_3d_image.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 3
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/gpl-3.0.html
19 * or you may search the http://www.gnu.org website for the version 3 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
26#include <wx/sizer.h>
27#include <wx/stattext.h>
28#include <wx/button.h>
29#include <wx/spinctrl.h>
30#include <wx/choice.h>
31#include <wx/bmpbuttn.h>
32#include <wx/statline.h>
33
34DIALOG_EXPORT_3D_IMAGE::DIALOG_EXPORT_3D_IMAGE( wxWindow* aParent, const wxSize& aCanvasSize,
36 DIALOG_SHIM( aParent, wxID_ANY, _( "Export 3D View" ), wxDefaultPosition, wxDefaultSize,
37 wxDEFAULT_DIALOG_STYLE ),
38 m_cfg( aCfg ),
39 m_originalSize( aCanvasSize ),
40 m_width( aCfg && aCfg->width > 0 ? aCfg->width : aCanvasSize.GetWidth() ),
41 m_height( aCfg && aCfg->height > 0 ? aCfg->height : aCanvasSize.GetHeight() ),
42 m_xResolution( aCfg ? aCfg->x_resolution : 300.0 ),
43 m_yResolution( aCfg ? aCfg->y_resolution : 300.0 ),
44 m_lockAspectRatio( aCfg ? aCfg->lock_aspect_ratio : true ),
45 m_sizeUnits( aCfg ? static_cast<SIZE_UNITS>( aCfg->size_units ) : SIZE_UNITS::PIXELS ),
46 m_resolutionUnits( aCfg ? static_cast<RESOLUTION_UNITS>( aCfg->resolution_units )
48{
49 m_aspectRatio = static_cast<double>(m_width) / static_cast<double>(m_height);
50
51 wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL );
52
53 // Image Size section
54 wxStaticText* imageSizeHeader = new wxStaticText( this, wxID_ANY, _( "Image Size" ) );
55 imageSizeHeader->SetFont( imageSizeHeader->GetFont().Bold() );
56 mainSizer->Add( imageSizeHeader, 0, wxLEFT | wxTOP, 10 );
57
58 wxFlexGridSizer* sizeGrid = new wxFlexGridSizer( 2, 4, 5, 5 );
59 sizeGrid->AddGrowableCol( 1 );
60
61 // Width row
62 sizeGrid->Add( new wxStaticText( this, wxID_ANY, _( "Width:" ) ), 0, wxALIGN_CENTER_VERTICAL );
63 m_spinWidth = new wxSpinCtrlDouble( this, wxID_ANY );
64 m_spinWidth->SetRange( 1, 50000 );
65 m_spinWidth->SetDigits( 0 );
66 sizeGrid->Add( m_spinWidth, 1, wxEXPAND );
67
68 // Lock button - will span 2 rows
69 m_lockButton = new wxBitmapButton( this, wxID_ANY,
71 sizeGrid->Add( m_lockButton, 0, wxALIGN_CENTER | wxALL, 2 );
72
73 // Size units choice
74 m_choiceSizeUnits = new wxChoice( this, wxID_ANY );
75 m_choiceSizeUnits->Append( _( "pixels" ) );
76 m_choiceSizeUnits->Append( _( "%" ) );
77 m_choiceSizeUnits->Append( _( "mm" ) );
78 m_choiceSizeUnits->Append( _( "in" ) );
79 m_choiceSizeUnits->SetSelection( static_cast<int>( m_sizeUnits ) );
80 sizeGrid->Add( m_choiceSizeUnits, 0, wxEXPAND );
81
82 // Height row
83 sizeGrid->Add( new wxStaticText( this, wxID_ANY, _( "Height:" ) ), 0, wxALIGN_CENTER_VERTICAL );
84 m_spinHeight = new wxSpinCtrlDouble( this, wxID_ANY );
85 m_spinHeight->SetRange( 1, 50000 );
86 m_spinHeight->SetDigits( 0 );
87 sizeGrid->Add( m_spinHeight, 1, wxEXPAND );
88
89 sizeGrid->AddSpacer( 0 ); // Empty space where lock button is
90 sizeGrid->AddSpacer( 0 ); // Empty space for units column
91
92 mainSizer->Add( sizeGrid, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 10 );
93
94 // Pixel size display
95 m_pixelSizeLabel = new wxStaticText( this, wxID_ANY, wxEmptyString );
96 m_pixelSizeLabel->SetFont( m_pixelSizeLabel->GetFont().Smaller() );
97 mainSizer->Add( m_pixelSizeLabel, 0, wxLEFT | wxTOP, 10 );
98
99 // Separator
100 wxStaticLine* line = new wxStaticLine( this );
101 mainSizer->Add( line, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 10 );
102
103 // Resolution section
104 wxStaticText* resolutionHeader = new wxStaticText( this, wxID_ANY, _( "Resolution" ) );
105 resolutionHeader->SetFont( resolutionHeader->GetFont().Bold() );
106 mainSizer->Add( resolutionHeader, 0, wxLEFT | wxTOP, 10 );
107
108 wxFlexGridSizer* resGrid = new wxFlexGridSizer( 2, 3, 5, 5 );
109 resGrid->AddGrowableCol( 1 );
110
111 // X Resolution row
112 resGrid->Add( new wxStaticText( this, wxID_ANY, _( "X resolution:" ) ), 0, wxALIGN_CENTER_VERTICAL );
113 m_spinXResolution = new wxSpinCtrlDouble( this, wxID_ANY );
114 m_spinXResolution->SetRange( 1, 10000 );
115 m_spinXResolution->SetDigits( 3 );
116 resGrid->Add( m_spinXResolution, 1, wxEXPAND );
117
118 // Resolution units choice
119 m_choiceResolutionUnits = new wxChoice( this, wxID_ANY );
120 m_choiceResolutionUnits->Append( _( "pixels/in" ) );
121 m_choiceResolutionUnits->Append( _( "pixels/mm" ) );
122 m_choiceResolutionUnits->SetSelection( static_cast<int>( m_resolutionUnits ) );
123 resGrid->Add( m_choiceResolutionUnits, 0, wxEXPAND );
124
125 // Y Resolution row
126 resGrid->Add( new wxStaticText( this, wxID_ANY, _( "Y resolution:" ) ), 0, wxALIGN_CENTER_VERTICAL );
127 m_spinYResolution = new wxSpinCtrlDouble( this, wxID_ANY );
128 m_spinYResolution->SetRange( 1, 10000 );
129 m_spinYResolution->SetDigits( 3 );
130 resGrid->Add( m_spinYResolution, 1, wxEXPAND );
131 resGrid->AddSpacer( 0 ); // Empty space for units column
132
133 mainSizer->Add( resGrid, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 10 );
134
135 // Dialog buttons
136 wxStdDialogButtonSizer* btnSizer = CreateStdDialogButtonSizer( wxOK | wxCANCEL );
137 mainSizer->Add( btnSizer, 0, wxEXPAND | wxALL, 10 );
138
139 SetSizerAndFit( mainSizer );
140 Centre();
141
142 // Set initial values AFTER creating all controls
143 m_spinWidth->SetValue( m_width );
144 m_spinHeight->SetValue( m_height );
145 m_spinXResolution->SetValue( m_xResolution );
146 m_spinYResolution->SetValue( m_yResolution );
148
149 // Bind events AFTER setting initial values
150 m_lockButton->Bind( wxEVT_BUTTON, &DIALOG_EXPORT_3D_IMAGE::OnLockToggle, this );
151 m_spinWidth->Bind( wxEVT_SPINCTRLDOUBLE, &DIALOG_EXPORT_3D_IMAGE::OnWidthChange, this );
152 m_spinHeight->Bind( wxEVT_SPINCTRLDOUBLE, &DIALOG_EXPORT_3D_IMAGE::OnHeightChange, this );
153 m_spinXResolution->Bind( wxEVT_SPINCTRLDOUBLE, &DIALOG_EXPORT_3D_IMAGE::OnXResolutionChange, this );
154 m_spinYResolution->Bind( wxEVT_SPINCTRLDOUBLE, &DIALOG_EXPORT_3D_IMAGE::OnYResolutionChange, this );
157}
158
159
161{
162 m_spinWidth->SetValue( m_width );
163 m_spinHeight->SetValue( m_height );
164 m_spinXResolution->SetValue( m_xResolution );
165 m_spinYResolution->SetValue( m_yResolution );
166
167 m_choiceSizeUnits->SetSelection( static_cast<int>( m_sizeUnits ) );
168 m_choiceResolutionUnits->SetSelection( static_cast<int>( m_resolutionUnits ) );
169
171
174 return true;
175}
176
177
179{
180 double width = m_spinWidth->GetValue();
181 double height = m_spinHeight->GetValue();
182 double xRes = m_spinXResolution->GetValue();
183 double yRes = m_spinYResolution->GetValue();
184
186 {
187 xRes *= 25.4;
188 yRes *= 25.4;
189 }
190
191 wxSize pixelSize = GetPixelSize( width, height, xRes, yRes, m_sizeUnits );
192 m_width = pixelSize.GetWidth();
193 m_height = pixelSize.GetHeight();
194
195 m_xResolution = m_spinXResolution->GetValue();
196 m_yResolution = m_spinYResolution->GetValue();
197
198 if( m_cfg )
199 {
200 m_cfg->width = m_width;
201 m_cfg->height = m_height;
202 m_cfg->x_resolution = m_xResolution;
203 m_cfg->y_resolution = m_yResolution;
204 m_cfg->size_units = static_cast<int>( m_sizeUnits );
205 m_cfg->resolution_units = static_cast<int>( m_resolutionUnits );
206 m_cfg->lock_aspect_ratio = m_lockAspectRatio;
207 }
208
209 return true;
210}
211
212
213void DIALOG_EXPORT_3D_IMAGE::OnLockToggle( wxCommandEvent& aEvent )
214{
216
218 {
221 }
222 else
223 {
225 }
226}
227
228
229void DIALOG_EXPORT_3D_IMAGE::OnWidthChange( wxSpinDoubleEvent& aEvent )
230{
232 {
233 double width = m_spinWidth->GetValue();
234 double height;
235
237 height = m_originalSize.GetWidth() * width / 100.0 / m_aspectRatio;
238 else
239 height = width / m_aspectRatio;
240
241 // Ensure height is not less than 1
242 if( height < 1 )
243 height = 1;
244
245 m_spinHeight->SetValue( height );
246 }
247
249}
250
251
252void DIALOG_EXPORT_3D_IMAGE::OnHeightChange( wxSpinDoubleEvent& aEvent )
253{
255 {
256 double height = m_spinHeight->GetValue();
257 double width;
258
260 width = m_originalSize.GetHeight() * height / 100.0 * m_aspectRatio;
261 else
262 width = height * m_aspectRatio;
263
264 // Ensure width is not less than 1
265 if( width < 1 )
266 width = 1;
267
268 m_spinWidth->SetValue( width );
269 }
270
272}
273
274
275void DIALOG_EXPORT_3D_IMAGE::OnXResolutionChange( wxSpinDoubleEvent& aEvent )
276{
278}
279
280
281void DIALOG_EXPORT_3D_IMAGE::OnYResolutionChange( wxSpinDoubleEvent& aEvent )
282{
284}
285
286
287void DIALOG_EXPORT_3D_IMAGE::OnSizeUnitChange( wxCommandEvent& aEvent )
288{
289 SIZE_UNITS oldUnits = m_sizeUnits;
290 m_sizeUnits = static_cast<SIZE_UNITS>( m_choiceSizeUnits->GetSelection() );
291 ConvertSizeUnits( oldUnits, m_sizeUnits );
293}
294
295
297{
299 m_resolutionUnits = static_cast<RESOLUTION_UNITS>( m_choiceResolutionUnits->GetSelection() );
302}
303
304
305wxSize DIALOG_EXPORT_3D_IMAGE::GetPixelSize( double aWidth, double aHeight, double aXResolution, double aYResolution, SIZE_UNITS aSizeUnits ) const
306{
307 switch( aSizeUnits )
308 {
310 return wxSize( static_cast<int>( aWidth ), static_cast<int>( aHeight ) );
312 return wxSize( static_cast<int>( aWidth * m_originalSize.GetWidth() / 100.0 ),
313 static_cast<int>( aHeight * m_originalSize.GetHeight() / 100.0 ) );
314 case SIZE_UNITS::MM:
315 return wxSize( static_cast<int>( aWidth * aXResolution / 25.4 ),
316 static_cast<int>( aHeight * aYResolution / 25.4 ) );
318 return wxSize( static_cast<int>( aWidth * aXResolution ),
319 static_cast<int>( aHeight * aYResolution ) );
320 default:
321 break;
322 }
323
324 return wxSize( 10, 10 ); // Should not happen
325}
326
327
329{
330 double width = m_spinWidth->GetValue();
331 double height = m_spinHeight->GetValue();
332 double xRes = m_spinXResolution->GetValue();
333 double yRes = m_spinYResolution->GetValue();
334
335 // Convert resolution to standard pixels/inch
337 {
338 xRes *= 25.4; // Convert mm to inches
339 yRes *= 25.4;
340 }
341
342 wxSize pixelSize = GetPixelSize( width, height, xRes, yRes, m_sizeUnits );
343
344 m_pixelSizeLabel->SetLabel( wxString::Format( _( "%d × %d pixels" ), pixelSize.GetWidth(), pixelSize.GetHeight() ) );
345}
346
347
349{
350 m_aspectRatio = m_spinWidth->GetValue() / m_spinHeight->GetValue();
351}
352
353
355{
356 if( aFromUnit == aToUnit )
357 return;
358
359 double width = m_spinWidth->GetValue();
360 double height = m_spinHeight->GetValue();
361 double xRes = m_spinXResolution->GetValue();
362 double yRes = m_spinYResolution->GetValue();
363
364 // Convert resolution to standard pixels/inch
366 {
367 xRes *= 25.4; // Convert mm to inches
368 yRes *= 25.4;
369 }
370
371 // Convert to pixels first
372 wxSize pixelSize = GetPixelSize( width, height, xRes, yRes, aFromUnit );
373
374 // Convert from pixels to target unit
375 switch( aToUnit )
376 {
378 m_spinWidth->SetValue( pixelSize.GetWidth() );
379 m_spinHeight->SetValue( pixelSize.GetHeight() );
380 break;
382 m_spinWidth->SetValue( pixelSize.GetWidth() * 100.0 / m_originalSize.GetWidth() );
383 m_spinHeight->SetValue( pixelSize.GetHeight() * 100.0 / m_originalSize.GetHeight() );
384 break;
385 case SIZE_UNITS::MM:
386 m_spinWidth->SetValue( pixelSize.GetWidth() * 25.4 / xRes );
387 m_spinHeight->SetValue( pixelSize.GetHeight() * 25.4 / yRes );
388 break;
390 m_spinWidth->SetValue( pixelSize.GetWidth() / xRes );
391 m_spinHeight->SetValue( pixelSize.GetHeight() / yRes );
392 break;
393 }
394}
395
396
398{
399 if( aFromUnit == aToUnit )
400 return;
401
402 double xRes = m_spinXResolution->GetValue();
403 double yRes = m_spinYResolution->GetValue();
404
406 {
407 // Convert from pixels/inch to pixels/mm
408 m_spinXResolution->SetValue( xRes / 25.4 );
409 m_spinYResolution->SetValue( yRes / 25.4 );
410 }
411 else if( aFromUnit == RESOLUTION_UNITS::PIXELS_PER_MM && aToUnit == RESOLUTION_UNITS::PIXELS_PER_INCH )
412 {
413 // Convert from pixels/mm to pixels/inch
414 m_spinXResolution->SetValue( xRes * 25.4 );
415 m_spinYResolution->SetValue( yRes * 25.4 );
416 }
417}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
DIALOG_EXPORT_3D_IMAGE(wxWindow *aParent, const wxSize &aCanvasSize, EDA_3D_VIEWER_SETTINGS::EXPORT_IMAGE_SETTINGS *aCfg)
void OnWidthChange(wxSpinDoubleEvent &aEvent)
void OnXResolutionChange(wxSpinDoubleEvent &aEvent)
void OnLockToggle(wxCommandEvent &aEvent)
void OnHeightChange(wxSpinDoubleEvent &aEvent)
wxSize GetPixelSize(double aWidth, double aHeight, double aXResolution, double aYResolution, SIZE_UNITS aSizeUnits) const
void OnResolutionUnitChange(wxCommandEvent &aEvent)
void OnYResolutionChange(wxSpinDoubleEvent &aEvent)
wxSpinCtrlDouble * m_spinYResolution
wxSpinCtrlDouble * m_spinHeight
void ConvertSizeUnits(SIZE_UNITS aFromUnit, SIZE_UNITS aToUnit)
wxSpinCtrlDouble * m_spinXResolution
void OnSizeUnitChange(wxCommandEvent &aEvent)
EDA_3D_VIEWER_SETTINGS::EXPORT_IMAGE_SETTINGS * m_cfg
void ConvertResolutionUnits(RESOLUTION_UNITS aFromUnit, RESOLUTION_UNITS aToUnit)
DIALOG_SHIM(wxWindow *aParent, wxWindowID id, const wxString &title, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER, const wxString &name=wxDialogNameStr)
#define _(s)