KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_export_step.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) 2016 Cirilo Bernardo
5 * Copyright (C) 2016-2022 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include <wx/choicdlg.h>
26#include <wx/log.h>
27#include <wx/stdpaths.h>
28#include <wx/process.h>
29#include <wx/string.h>
30
31#include <pgm_base.h>
32#include <board.h>
33#include <confirm.h>
36#include <footprint.h>
37#include <kiface_base.h>
38#include <locale_io.h>
39#include <math/vector3.h>
40#include <pcb_edit_frame.h>
41#include <pcbnew_settings.h>
42#include <project/project_file.h> // LAST_PATH_TYPE
43#include <reporter.h>
44#include <trace_helpers.h>
47#include <filename_resolver.h>
48
49
51{
52public:
54 {
55 STEP_ORIGIN_0, // absolute coordinates
56 STEP_ORIGIN_PLOT_AXIS, // origin is plot/drill axis origin
57 STEP_ORIGIN_GRID_AXIS, // origin is grid origin
58 STEP_ORIGIN_BOARD_CENTER, // origin is board center
59 STEP_ORIGIN_USER, // origin is entered by user
60 };
61
62 DIALOG_EXPORT_STEP( PCB_EDIT_FRAME* aParent, const wxString& aBoardPath );
64
65protected:
66 void onUpdateUnits( wxUpdateUIEvent& aEvent ) override;
67 void onUpdateXPos( wxUpdateUIEvent& aEvent ) override;
68 void onUpdateYPos( wxUpdateUIEvent& aEvent ) override;
69 void onExportButton( wxCommandEvent& aEvent ) override;
70
72 {
73 return m_STEP_OrgUnitChoice->GetSelection();
74 }
75
76 double GetXOrg() const
77 {
79 }
80
81 double GetYOrg()
82 {
84 }
85
87
89 {
90 return m_cbRemoveUnspecified->GetValue();
91 }
92
94 {
95 return m_cbRemoveDNP->GetValue();
96 }
97
99 {
100 return m_cbSubstModels->GetValue();
101 }
102
104 {
105 return m_cbOverwriteFile->GetValue();
106 }
107
108private:
110 STEP_ORIGIN_OPTION m_origin; // The last preference for STEP origin option
111 double m_userOriginX; // remember last User Origin X value
112 double m_userOriginY; // remember last User Origin Y value
113 int m_originUnits; // remember last units for User Origin
114 bool m_noUnspecified; // remember last preference for No Unspecified Component
115 bool m_noDNP; // remember last preference for No DNP Component
116 static bool m_exportTracks; // remember last preference to export tracks
117 // (stored only for the session)
118 wxString m_boardPath; // path to the exported board file
119 static int m_toleranceLastChoice; // Store m_tolerance option during a session
120};
121
122
123int DIALOG_EXPORT_STEP::m_toleranceLastChoice = -1; // Use default
125
126DIALOG_EXPORT_STEP::DIALOG_EXPORT_STEP( PCB_EDIT_FRAME* aParent, const wxString& aBoardPath ) :
127 DIALOG_EXPORT_STEP_BASE( aParent )
128{
129 m_parent = aParent;
130 m_boardPath = aBoardPath;
131 m_sdbSizerCancel->SetLabel( _( "Close" ) );
132 m_sdbSizerOK->SetLabel( _( "Export" ) );
133 m_sdbSizer->Layout();
134
135 // Build default output file name
137
138 if( path.IsEmpty() )
139 {
140 wxFileName brdFile = m_parent->GetBoard()->GetFileName();
141 brdFile.SetExt( wxT( "step" ) );
142 path = brdFile.GetFullPath();
143 }
144
145 // Reset this picker bc wxFormBuilder doesn't allow untranslated strings
146 wxSizerItem* sizer_item = bSizerTop->GetItem( 1UL );
147 wxWindow* widget = sizer_item->GetWindow();
148 bSizerTop->Hide( widget );
149 widget->Destroy();
150
151 m_filePickerSTEP = new wxFilePickerCtrl( this, wxID_ANY, wxEmptyString,
152 _( "Select a STEP export filename" ),
153 _( "STEP files" ) + AddFileExtListToFilter( { "STEP", "STP" } ),
154 wxDefaultPosition,
155 wxSize( -1, -1 ), wxFLP_SAVE | wxFLP_USE_TEXTCTRL );
156 bSizerTop->Add( m_filePickerSTEP, 1, wxTOP | wxRIGHT | wxLEFT | wxALIGN_CENTER_VERTICAL, 5 );
157
158 m_filePickerSTEP->SetPath( path );
159
160 Layout();
161 bSizerSTEPFile->Fit( this );
162
163 SetFocus();
164
166
168
169 switch( m_origin )
170 {
171 default:
172 case STEP_ORIGIN_PLOT_AXIS: m_rbDrillAndPlotOrigin->SetValue( true ); break;
173 case STEP_ORIGIN_GRID_AXIS: m_rbGridOrigin->SetValue( true ); break;
174 case STEP_ORIGIN_USER: m_rbUserDefinedOrigin->SetValue( true ); break;
175 case STEP_ORIGIN_BOARD_CENTER: m_rbBoardCenterOrigin->SetValue( true ); break;
176 }
177
183
184 m_cbExportTracks->SetValue( m_exportTracks );
186 m_cbRemoveDNP->SetValue( m_noDNP );
189
190 m_STEP_OrgUnitChoice->SetSelection( m_originUnits );
191 wxString tmpStr;
192 tmpStr << m_userOriginX;
193 m_STEP_Xorg->SetValue( tmpStr );
194 tmpStr = wxEmptyString;
195 tmpStr << m_userOriginY;
196 m_STEP_Yorg->SetValue( tmpStr );
197
198 wxString bad_scales;
199 size_t bad_count = 0;
200
201 for( FOOTPRINT* fp : aParent->GetBoard()->Footprints() )
202 {
203 for( const FP_3DMODEL& model : fp->Models() )
204 {
205
206 if( model.m_Scale.x != 1.0 ||
207 model.m_Scale.y != 1.0 ||
208 model.m_Scale.z != 1.0 )
209 {
210 bad_scales.Append( wxS("\n") );
211 bad_scales.Append( model.m_Filename );
212 bad_count++;
213 }
214 }
215
216 if( bad_count >= 5 )
217 break;
218 }
219
220 if( !bad_scales.empty()
221 && !Pgm().GetCommonSettings()->m_DoNotShowAgain.scaled_3d_models_warning )
222 {
223 wxString extendedMsg = _( "Non-unity scaled models:" ) + wxT( "\n" ) + bad_scales;
224
225 KIDIALOG msgDlg( m_parent, _( "Scaled models detected. "
226 "Model scaling is not reliable for mechanical export." ),
227 _( "Model Scale Warning" ), wxOK | wxICON_WARNING );
228 msgDlg.SetExtendedMessage( extendedMsg );
229 msgDlg.DoNotShowCheckbox( __FILE__, __LINE__ );
230
231 msgDlg.ShowModal();
232
233 if( msgDlg.DoNotShowAgain() )
234 Pgm().GetCommonSettings()->m_DoNotShowAgain.scaled_3d_models_warning = true;
235 }
236
237 if( m_toleranceLastChoice >= 0 )
239
240 // Now all widgets have the size fixed, call FinishDialogSettings
242}
243
244
246{
247 GetOriginOption(); // Update m_origin member.
248
250
251 cfg->m_ExportStep.origin_mode = static_cast<int>( m_origin );
252 cfg->m_ExportStep.origin_units = m_STEP_OrgUnitChoice->GetSelection();
255
256 double val = 0.0;
257
258 m_STEP_Xorg->GetValue().ToDouble( &val );
259 cfg->m_ExportStep.origin_x = val;
260
261 m_STEP_Yorg->GetValue().ToDouble( &val );
262 cfg->m_ExportStep.origin_y = val;
263
265 cfg->m_ExportStep.no_dnp = m_cbRemoveDNP->GetValue();
266
268 m_exportTracks = m_cbExportTracks->GetValue();
269}
270
271
273{
275
276 if( m_rbDrillAndPlotOrigin->GetValue() )
278 else if( m_rbGridOrigin->GetValue() )
280 else if( m_rbUserDefinedOrigin->GetValue() )
282 else if( m_rbBoardCenterOrigin->GetValue() )
284
285 return m_origin;
286}
287
288
289void PCB_EDIT_FRAME::OnExportSTEP( wxCommandEvent& event )
290{
291 wxFileName brdFile = GetBoard()->GetFileName();
292
293 if( GetScreen()->IsContentModified() || brdFile.GetFullPath().empty() )
294 {
295 if( !doAutoSave() )
296 {
297 DisplayErrorMessage( this, _( "STEP export failed! "
298 "Please save the PCB and try again" ) );
299 return;
300 }
301
302 // Use auto-saved board for export
303 brdFile.SetName( GetAutoSaveFilePrefix() + brdFile.GetName() );
304 }
305
306 DIALOG_EXPORT_STEP dlg( this, brdFile.GetFullPath() );
307 dlg.ShowModal();
308}
309
310
311void DIALOG_EXPORT_STEP::onUpdateUnits( wxUpdateUIEvent& aEvent )
312{
313 aEvent.Enable( m_rbUserDefinedOrigin->GetValue() );
314}
315
316
317void DIALOG_EXPORT_STEP::onUpdateXPos( wxUpdateUIEvent& aEvent )
318{
319 aEvent.Enable( m_rbUserDefinedOrigin->GetValue() );
320}
321
322
323void DIALOG_EXPORT_STEP::onUpdateYPos( wxUpdateUIEvent& aEvent )
324{
325 aEvent.Enable( m_rbUserDefinedOrigin->GetValue() );
326}
327
328
329void DIALOG_EXPORT_STEP::onExportButton( wxCommandEvent& aEvent )
330{
332
333 double tolerance; // default value in mm
335 m_exportTracks = m_cbExportTracks->GetValue();
336
337 switch( m_choiceTolerance->GetSelection() )
338 {
339 case 0: tolerance = 0.001; break;
340 default:
341 case 1: tolerance = 0.01; break;
342 case 2: tolerance = 0.1; break;
343 }
344
345 SHAPE_POLY_SET outline;
346 wxString msg;
347
348 // Check if the board outline is continuous
349 // max dist from one endPt to next startPt to build a closed shape:
350 int chainingEpsilon = pcbIUScale.mmToIU( tolerance );
351
352 // Arc to segment approx error (not critical here: we do not use the outline shape):
353 int maxError = pcbIUScale.mmToIU( 0.005 );
354 bool success = BuildBoardPolygonOutlines( m_parent->GetBoard(), outline, maxError,
355 chainingEpsilon, nullptr );
356 if( !success )
357 {
358 DisplayErrorMessage( this, wxString::Format(
359 _( "Board outline is missing or not closed using %.3f mm tolerance.\n"
360 "Run DRC for a full analysis." ), tolerance ) );
361 return;
362 }
363
364 wxFileName fn = m_filePickerSTEP->GetFileName();
365
366 if( fn.FileExists() && !GetOverwriteFile() )
367 {
368 msg.Printf( _( "File '%s' already exists. Do you want overwrite this file?" ),
369 fn.GetFullPath() );
370
371 if( wxMessageBox( msg, _( "STEP Export" ), wxYES_NO | wxICON_QUESTION, this ) == wxNO )
372 return;
373 }
374
375 wxFileName appK2S( wxStandardPaths::Get().GetExecutablePath() );
376#ifdef __WXMAC__
377 // On macOS, we have standalone applications inside the main bundle, so we handle that here:
378 if( appK2S.GetPath().Find( "/Contents/Applications/pcbnew.app/Contents/MacOS" ) != wxNOT_FOUND )
379 {
380 appK2S.AppendDir( wxT( ".." ) );
381 appK2S.AppendDir( wxT( ".." ) );
382 appK2S.AppendDir( wxT( ".." ) );
383 appK2S.AppendDir( wxT( ".." ) );
384 appK2S.AppendDir( wxT( "MacOS" ) );
385 }
386#else
387 if( wxGetEnv( wxT( "KICAD_RUN_FROM_BUILD_DIR" ), nullptr ) )
388 {
389 appK2S.RemoveLastDir();
390 appK2S.AppendDir( "kicad" );
391 }
392#endif
393
394 appK2S.SetName( wxT( "kicad-cli" ) );
395 appK2S.Normalize( FN_NORMALIZE_FLAGS );
396
397 wxString cmdK2S = wxT( "\"" );
398 cmdK2S.Append( appK2S.GetFullPath() );
399 cmdK2S.Append( wxT( "\"" ) );
400
401 cmdK2S.Append( wxT( " pcb" ) );
402 cmdK2S.Append( wxT( " export" ) );
403 cmdK2S.Append( wxT( " step" ) );
404
406 cmdK2S.Append( wxT( " --no-unspecified" ) );
407
408 if( GetNoDNPOption() )
409 cmdK2S.Append( wxT( " --no-dnp" ) );
410
411 if( GetSubstOption() )
412 cmdK2S.Append( wxT( " --subst-models" ) );
413
414 if( m_exportTracks )
415 cmdK2S.Append( wxT( " --export-tracks" ) );
416
417 // Note: for some reason, using \" to insert a quote in a format string, under MacOS
418 // wxString::Format does not work. So use a %c format in string
419 int quote = '\'';
420 int dblquote = '"';
421
422 switch( GetOriginOption() )
423 {
424 case STEP_ORIGIN_0:
425 wxFAIL_MSG( wxT( "Unsupported origin option: how did we get here?" ) );
426 break;
427
429 cmdK2S.Append( wxT( " --drill-origin" ) );
430 break;
431
433 cmdK2S.Append( wxT( " --grid-origin" ) );
434 break;
435
436 case STEP_ORIGIN_USER:
437 {
438 double xOrg = GetXOrg();
439 double yOrg = GetYOrg();
440
441 if( GetOrgUnitsChoice() == 1 )
442 {
443 // selected reference unit is in inches, and STEP units are mm
444 xOrg *= 25.4;
445 yOrg *= 25.4;
446 }
447
449 cmdK2S.Append( wxString::Format( wxT( " --user-origin=%c%.6fx%.6fmm%c" ),
450 quote, xOrg, yOrg, quote ) );
451 break;
452 }
453
455 {
456 BOX2I bbox = m_parent->GetBoard()->ComputeBoundingBox( true );
457 double xOrg = pcbIUScale.IUTomm( bbox.GetCenter().x );
458 double yOrg = pcbIUScale.IUTomm( bbox.GetCenter().y );
460
461 cmdK2S.Append( wxString::Format( wxT( " --user-origin=%c%.6fx%.6fmm%c" ),
462 quote, xOrg, yOrg, quote ) );
463 break;
464 }
465 }
466
467 {
469 cmdK2S.Append( wxString::Format( wxT( " --min-distance=%c%.3fmm%c" ),
470 quote, tolerance, quote ) );
471 }
472
473 // Input file path.
474 cmdK2S.Append( wxString::Format( wxT( " -f -o %c%s%c" ),
475 dblquote, m_filePickerSTEP->GetPath(), dblquote ) );
476
477
478 // Output file path.
479 cmdK2S.Append( wxString::Format( wxT( " %c%s%c" ), dblquote, m_boardPath, dblquote ) );
480
481 wxLogTrace( traceKiCad2Step, wxT( "export step command: %s" ), cmdK2S );
482
483 DIALOG_EXPORT_STEP_LOG* log = new DIALOG_EXPORT_STEP_LOG( this, cmdK2S );
484 log->ShowModal();
485 Close();
486}
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:109
BOX2I ComputeBoundingBox(bool aBoardEdgesOnly=false) const
Calculate the bounding box containing all board items (or board edge segments).
Definition: board.cpp:1303
FOOTPRINTS & Footprints()
Definition: board.h:312
const wxString & GetFileName() const
Definition: board.h:307
const Vec GetCenter() const
Definition: box2.h:195
Class DIALOG_EXPORT_STEP_BASE.
wxStdDialogButtonSizer * m_sdbSizer
wxFilePickerCtrl * m_filePickerSTEP
wxRadioButton * m_rbDrillAndPlotOrigin
STEP_ORIGIN_OPTION GetOriginOption()
PCB_EDIT_FRAME * m_parent
void onUpdateXPos(wxUpdateUIEvent &aEvent) override
STEP_ORIGIN_OPTION m_origin
void onExportButton(wxCommandEvent &aEvent) override
DIALOG_EXPORT_STEP(PCB_EDIT_FRAME *aParent, const wxString &aBoardPath)
void onUpdateUnits(wxUpdateUIEvent &aEvent) override
void onUpdateYPos(wxUpdateUIEvent &aEvent) override
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
static wxString GetAutoSaveFilePrefix()
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition: confirm.h:46
bool DoNotShowAgain() const
Definition: confirm.cpp:67
void DoNotShowCheckbox(wxString file, int line)
Checks the 'do not show again' setting for the dialog.
Definition: confirm.cpp:59
int ShowModal() override
Definition: confirm.cpp:103
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:41
DIALOG_EXPORT_STEP m_ExportStep
PCBNEW_SETTINGS * GetPcbNewSettings() const
PCB_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
BOARD * GetBoard() const
The main frame for Pcbnew.
void SetLastPath(LAST_PATH_TYPE aType, const wxString &aLastPath)
Set the path of the last file successfully read.
bool doAutoSave() override
Perform auto save when the board has been modified and not saved within the auto save interval.
void OnExportSTEP(wxCommandEvent &event)
Export the current BOARD to a STEP assembly.
wxString GetLastPath(LAST_PATH_TYPE aType)
Get the last path for a particular type.
bool IsContentModified() const override
Get if the current board has been modified but not saved.
Represent a set of closed polygons.
void SetValue(const wxString &aValue) override
Set a new value in evaluator buffer, and display it in the wxTextCtrl.
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:308
This file is part of the common library.
bool BuildBoardPolygonOutlines(BOARD *aBoard, SHAPE_POLY_SET &aOutlines, int aErrorMax, int aChainingEpsilon, OUTLINE_ERROR_HANDLER *aErrorHandler, bool aAllowUseArcsInPolygons)
Extracts the board outlines and build a closed polygon from lines, arcs and circle items on edge cut ...
#define _(s)
wxString AddFileExtListToFilter(const std::vector< std::string > &aExts)
Build the wildcard extension file dialog wildcard filter to add to the base message dialog.
const wxChar *const traceKiCad2Step
Flag to enable KiCad2Step debug tracing.
double DoubleValueFromString(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, const wxString &aTextValue, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Function DoubleValueFromString converts aTextValue to a double.
Definition: eda_units.cpp:445
see class PGM_BASE
@ LAST_PATH_STEP
Definition: project_file.h:49
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:115
std::vector< FAB_LAYER_COLOR > dummy
constexpr double IUTomm(int iu) const
Definition: base_units.h:87
constexpr int mmToIU(double mm) const
Definition: base_units.h:89
wxLogTrace helper definitions.
Definition of file extensions used in Kicad.
#define FN_NORMALIZE_FLAGS
Default flags to pass to wxFileName::Normalize().
Definition: wx_filename.h:38