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& aSize ) :
35 DIALOG_SHIM( aParent, wxID_ANY, _( "Export 3D View" ), wxDefaultPosition, wxDefaultSize,
36 wxDEFAULT_DIALOG_STYLE ),
38 m_originalSize( aSize ),
39 m_width( aSize.GetWidth() ),
40 m_height( aSize.GetHeight() ),
41 m_xResolution( 300.0 ),
42 m_yResolution( 300.0 ),
43 m_lockAspectRatio( true ),
46{
47 m_aspectRatio = static_cast<double>(m_width) / static_cast<double>(m_height);
48
49 wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL );
50
51 // Image Size section
52 wxStaticText* imageSizeHeader = new wxStaticText( this, wxID_ANY, _( "Image Size" ) );
53 imageSizeHeader->SetFont( imageSizeHeader->GetFont().Bold() );
54 mainSizer->Add( imageSizeHeader, 0, wxLEFT | wxTOP, 10 );
55
56 wxFlexGridSizer* sizeGrid = new wxFlexGridSizer( 2, 4, 5, 5 );
57 sizeGrid->AddGrowableCol( 1 );
58
59 // Width row
60 sizeGrid->Add( new wxStaticText( this, wxID_ANY, _( "Width:" ) ), 0, wxALIGN_CENTER_VERTICAL );
61 m_spinWidth = new wxSpinCtrlDouble( this, wxID_ANY );
62 m_spinWidth->SetRange( 1, 50000 );
63 m_spinWidth->SetDigits( 0 );
64 sizeGrid->Add( m_spinWidth, 1, wxEXPAND );
65
66 // Lock button - will span 2 rows
67 m_lockButton = new wxBitmapButton( this, wxID_ANY, KiBitmapBundle( BITMAPS::locked ) );
68 sizeGrid->Add( m_lockButton, 0, wxALIGN_CENTER | wxALL, 2 );
69
70 // Size units choice
71 m_choiceSizeUnits = new wxChoice( this, wxID_ANY );
72 m_choiceSizeUnits->Append( _( "pixels" ) );
73 m_choiceSizeUnits->Append( _( "%" ) );
74 m_choiceSizeUnits->Append( _( "mm" ) );
75 m_choiceSizeUnits->Append( _( "in" ) );
76 m_choiceSizeUnits->SetSelection( 0 ); // pixels
77 sizeGrid->Add( m_choiceSizeUnits, 0, wxEXPAND );
78
79 // Height row
80 sizeGrid->Add( new wxStaticText( this, wxID_ANY, _( "Height:" ) ), 0, wxALIGN_CENTER_VERTICAL );
81 m_spinHeight = new wxSpinCtrlDouble( this, wxID_ANY );
82 m_spinHeight->SetRange( 1, 50000 );
83 m_spinHeight->SetDigits( 0 );
84 sizeGrid->Add( m_spinHeight, 1, wxEXPAND );
85
86 sizeGrid->AddSpacer( 0 ); // Empty space where lock button is
87 sizeGrid->AddSpacer( 0 ); // Empty space for units column
88
89 mainSizer->Add( sizeGrid, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 10 );
90
91 // Pixel size display
92 m_pixelSizeLabel = new wxStaticText( this, wxID_ANY, wxEmptyString );
93 m_pixelSizeLabel->SetFont( m_pixelSizeLabel->GetFont().Smaller() );
94 mainSizer->Add( m_pixelSizeLabel, 0, wxLEFT | wxTOP, 10 );
95
96 // Separator
97 wxStaticLine* line = new wxStaticLine( this );
98 mainSizer->Add( line, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 10 );
99
100 // Resolution section
101 wxStaticText* resolutionHeader = new wxStaticText( this, wxID_ANY, _( "Resolution" ) );
102 resolutionHeader->SetFont( resolutionHeader->GetFont().Bold() );
103 mainSizer->Add( resolutionHeader, 0, wxLEFT | wxTOP, 10 );
104
105 wxFlexGridSizer* resGrid = new wxFlexGridSizer( 2, 3, 5, 5 );
106 resGrid->AddGrowableCol( 1 );
107
108 // X Resolution row
109 resGrid->Add( new wxStaticText( this, wxID_ANY, _( "X resolution:" ) ), 0, wxALIGN_CENTER_VERTICAL );
110 m_spinXResolution = new wxSpinCtrlDouble( this, wxID_ANY );
111 m_spinXResolution->SetRange( 1, 10000 );
112 m_spinXResolution->SetDigits( 3 );
113 resGrid->Add( m_spinXResolution, 1, wxEXPAND );
114
115 // Resolution units choice
116 m_choiceResolutionUnits = new wxChoice( this, wxID_ANY );
117 m_choiceResolutionUnits->Append( _( "pixels/in" ) );
118 m_choiceResolutionUnits->Append( _( "pixels/mm" ) );
119 m_choiceResolutionUnits->SetSelection( 0 ); // pixels/in
120 resGrid->Add( m_choiceResolutionUnits, 0, wxEXPAND );
121
122 // Y Resolution row
123 resGrid->Add( new wxStaticText( this, wxID_ANY, _( "Y resolution:" ) ), 0, wxALIGN_CENTER_VERTICAL );
124 m_spinYResolution = new wxSpinCtrlDouble( this, wxID_ANY );
125 m_spinYResolution->SetRange( 1, 10000 );
126 m_spinYResolution->SetDigits( 3 );
127 resGrid->Add( m_spinYResolution, 1, wxEXPAND );
128 resGrid->AddSpacer( 0 ); // Empty space for units column
129
130 mainSizer->Add( resGrid, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 10 );
131
132 // Dialog buttons
133 wxStdDialogButtonSizer* btnSizer = CreateStdDialogButtonSizer( wxOK | wxCANCEL );
134 mainSizer->Add( btnSizer, 0, wxEXPAND | wxALL, 10 );
135
136 SetSizerAndFit( mainSizer );
137 Centre();
138
139 // Set initial values AFTER creating all controls
140 m_spinWidth->SetValue( m_width );
141 m_spinHeight->SetValue( m_height );
142 m_spinXResolution->SetValue( m_xResolution );
143 m_spinYResolution->SetValue( m_yResolution );
145
146 // Bind events AFTER setting initial values
147 m_lockButton->Bind( wxEVT_BUTTON, &DIALOG_EXPORT_3D_IMAGE::OnLockToggle, this );
148 m_spinWidth->Bind( wxEVT_SPINCTRLDOUBLE, &DIALOG_EXPORT_3D_IMAGE::OnWidthChange, this );
149 m_spinHeight->Bind( wxEVT_SPINCTRLDOUBLE, &DIALOG_EXPORT_3D_IMAGE::OnHeightChange, this );
150 m_spinXResolution->Bind( wxEVT_SPINCTRLDOUBLE, &DIALOG_EXPORT_3D_IMAGE::OnXResolutionChange, this );
151 m_spinYResolution->Bind( wxEVT_SPINCTRLDOUBLE, &DIALOG_EXPORT_3D_IMAGE::OnYResolutionChange, this );
154}
155
156
158{
159 // Convert current values back to pixels if needed
160 double width = m_spinWidth->GetValue();
161 double height = m_spinHeight->GetValue();
162
163 switch( m_sizeUnits )
164 {
166 m_width = static_cast<int>( width );
167 m_height = static_cast<int>( height );
168 break;
170 // Assume 100% = original size
171 m_width = static_cast<int>( width * m_originalSize.GetWidth() / 100.0 );
172 m_height = static_cast<int>( height * m_originalSize.GetHeight() / 100.0 );
173 break;
174 case SIZE_UNITS::MM:
175 // Convert mm to pixels using resolution
176 m_width = static_cast<int>( width * m_xResolution / 25.4 );
177 m_height = static_cast<int>( height * m_yResolution / 25.4 );
178 break;
180 // Convert inches to pixels using resolution
181 m_width = static_cast<int>( width * m_xResolution );
182 m_height = static_cast<int>( height * m_yResolution );
183 break;
184 }
185
186 m_xResolution = m_spinXResolution->GetValue();
187 m_yResolution = m_spinYResolution->GetValue();
188
189 return true;
190}
191
192
193void DIALOG_EXPORT_3D_IMAGE::OnLockToggle( wxCommandEvent& aEvent )
194{
196
198 {
201 }
202 else
203 {
205 }
206}
207
208
209void DIALOG_EXPORT_3D_IMAGE::OnWidthChange( wxSpinDoubleEvent& aEvent )
210{
212 {
213 double width = m_spinWidth->GetValue();
214 double height;
215
217 height = m_originalSize.GetWidth() * width / 100.0 / m_aspectRatio;
218 else
219 height = width / m_aspectRatio;
220
221 // Ensure height is not less than 1
222 if( height < 1 )
223 height = 1;
224
225 m_spinHeight->SetValue( height );
226 }
227
229}
230
231
232void DIALOG_EXPORT_3D_IMAGE::OnHeightChange( wxSpinDoubleEvent& aEvent )
233{
235 {
236 double height = m_spinHeight->GetValue();
237 double width;
238
240 width = m_originalSize.GetHeight() * height / 100.0 * m_aspectRatio;
241 else
242 width = height * m_aspectRatio;
243
244 // Ensure width is not less than 1
245 if( width < 1 )
246 width = 1;
247
248 m_spinWidth->SetValue( width );
249 }
250
252}
253
254
255void DIALOG_EXPORT_3D_IMAGE::OnXResolutionChange( wxSpinDoubleEvent& aEvent )
256{
258}
259
260
261void DIALOG_EXPORT_3D_IMAGE::OnYResolutionChange( wxSpinDoubleEvent& aEvent )
262{
264}
265
266
267void DIALOG_EXPORT_3D_IMAGE::OnSizeUnitChange( wxCommandEvent& aEvent )
268{
269 SIZE_UNITS oldUnits = m_sizeUnits;
270 m_sizeUnits = static_cast<SIZE_UNITS>( m_choiceSizeUnits->GetSelection() );
271 ConvertSizeUnits( oldUnits, m_sizeUnits );
273}
274
275
277{
279 m_resolutionUnits = static_cast<RESOLUTION_UNITS>( m_choiceResolutionUnits->GetSelection() );
282}
283
284
285wxSize DIALOG_EXPORT_3D_IMAGE::GetPixelSize( double aWidth, double aHeight, double aXResolution, double aYResolution, SIZE_UNITS aSizeUnits ) const
286{
287 switch( aSizeUnits )
288 {
290 return wxSize( static_cast<int>( aWidth ), static_cast<int>( aHeight ) );
292 return wxSize( static_cast<int>( 100.0 * m_originalSize.GetWidth() ),
293 static_cast<int>( 100.0 * m_originalSize.GetHeight() ) );
294 case SIZE_UNITS::MM:
295 return wxSize( static_cast<int>( aWidth * aXResolution / 25.4 ),
296 static_cast<int>( aHeight * aYResolution / 25.4 ) );
298 return wxSize( static_cast<int>( aWidth * aXResolution ),
299 static_cast<int>( aHeight * aYResolution ) );
300 default:
301 break;
302 }
303
304 return wxSize( 10, 10 ); // Should not happen
305}
306
307
309{
310 double width = m_spinWidth->GetValue();
311 double height = m_spinHeight->GetValue();
312 double xRes = m_spinXResolution->GetValue();
313 double yRes = m_spinYResolution->GetValue();
314
315 // Convert resolution to standard pixels/inch
317 {
318 xRes *= 25.4; // Convert mm to inches
319 yRes *= 25.4;
320 }
321
322 wxSize pixelSize = GetPixelSize( width, height, xRes, yRes, m_sizeUnits );
323
324 m_pixelSizeLabel->SetLabel( wxString::Format( _( "%d × %d pixels" ), pixelSize.GetWidth(), pixelSize.GetHeight() ) );
325}
326
327
329{
330 m_aspectRatio = m_spinWidth->GetValue() / m_spinHeight->GetValue();
331}
332
333
335{
336 if( aFromUnit == aToUnit )
337 return;
338
339 double width = m_spinWidth->GetValue();
340 double height = m_spinHeight->GetValue();
341 double xRes = m_spinXResolution->GetValue();
342 double yRes = m_spinYResolution->GetValue();
343
344 // Convert resolution to standard pixels/inch
346 {
347 xRes *= 25.4; // Convert mm to inches
348 yRes *= 25.4;
349 }
350
351 // Convert to pixels first
352 wxSize pixelSize = GetPixelSize( width, height, xRes, yRes, aFromUnit );
353
354 // Convert from pixels to target unit
355 switch( aToUnit )
356 {
358 m_spinWidth->SetValue( pixelSize.GetWidth() );
359 m_spinHeight->SetValue( pixelSize.GetHeight() );
360 break;
362 m_spinWidth->SetValue( pixelSize.GetWidth() * 100.0 / m_originalSize.GetWidth() );
363 m_spinHeight->SetValue( pixelSize.GetHeight() * 100.0 / m_originalSize.GetHeight() );
364 break;
365 case SIZE_UNITS::MM:
366 m_spinWidth->SetValue( pixelSize.GetWidth() * 25.4 / xRes );
367 m_spinHeight->SetValue( pixelSize.GetHeight() * 25.4 / yRes );
368 break;
370 m_spinWidth->SetValue( pixelSize.GetWidth() / xRes );
371 m_spinHeight->SetValue( pixelSize.GetHeight() / yRes );
372 break;
373 }
374}
375
376
378{
379 if( aFromUnit == aToUnit )
380 return;
381
382 double xRes = m_spinXResolution->GetValue();
383 double yRes = m_spinYResolution->GetValue();
384
386 {
387 // Convert from pixels/inch to pixels/mm
388 m_spinXResolution->SetValue( xRes / 25.4 );
389 m_spinYResolution->SetValue( yRes / 25.4 );
390 }
391 else if( aFromUnit == RESOLUTION_UNITS::PIXELS_PER_MM && aToUnit == RESOLUTION_UNITS::PIXELS_PER_INCH )
392 {
393 // Convert from pixels/mm to pixels/inch
394 m_spinXResolution->SetValue( xRes * 25.4 );
395 m_spinYResolution->SetValue( yRes * 25.4 );
396 }
397}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
DIALOG_EXPORT_3D_IMAGE(wxWindow *aParent, const wxSize &aSize)
EDA_3D_VIEWER_EXPORT_FORMAT m_format
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)
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)
EDA_3D_VIEWER_EXPORT_FORMAT