KiCad PCB EDA Suite
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-2019 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/stdpaths.h>
27 #include <wx/process.h>
28 
29 #include "pcb_edit_frame.h"
30 #include "kiface_i.h"
31 #include "confirm.h"
32 #include "reporter.h"
33 #include "class_board.h"
35 #include <pcbnew_settings.h>
36 #include <project/project_file.h> // LAST_PATH_TYPE
37 #include <widgets/text_ctrl_eval.h>
38 #include <wx_html_report_panel.h>
39 
40 
42 {
43 public:
45  {
46  STEP_ORG_0, // absolute coordinates
47  STEP_ORG_PLOT_AXIS, // origin is plot/drill axis origin
48  STEP_ORG_GRID_AXIS, // origin is grid origin
49  STEP_ORG_BOARD_CENTER, // origin is board center
50  STEP_ORG_USER, // origin is entered by user
51  };
52 
53 private:
55  // The last preference for STEP Origin:
57  bool m_noVirtual; // remember last preference for No Virtual Component
58  static bool m_overwriteFile; // remember last preference for overwrite file
59  int m_OrgUnits; // remember last units for User Origin
60  double m_XOrg; // remember last User Origin X value
61  double m_YOrg; // remember last User Origin Y value
62  wxString m_boardPath; // path to the exported board file
63 
64 protected:
65  void onUpdateUnits( wxUpdateUIEvent& aEvent ) override;
66  void onUpdateXPos( wxUpdateUIEvent& aEvent ) override;
67  void onUpdateYPos( wxUpdateUIEvent& aEvent ) override;
68  void onExportButton( wxCommandEvent& aEvent ) override;
69 
70  int GetOrgUnitsChoice() const
71  {
72  return m_STEP_OrgUnitChoice->GetSelection();
73  }
74 
75  double GetXOrg() const
76  {
78  }
79 
80  double GetYOrg()
81  {
83  }
84 
86 
88  {
89  return m_cbRemoveVirtual->GetValue();
90  }
91 
93  {
94  return m_cbOverwriteFile->GetValue();
95  }
96 
97 public:
98  DIALOG_EXPORT_STEP( PCB_EDIT_FRAME* aParent, const wxString& aBoardPath );
99 
101  {
102  GetOriginOption(); // Update m_STEP_org_opt member.
103 
104  auto cfg = m_parent->GetPcbNewSettings();
105 
106  cfg->m_ExportStep.origin_mode = static_cast<int>( m_STEP_org_opt );
107  cfg->m_ExportStep.origin_units = m_STEP_OrgUnitChoice->GetSelection();
108 
109  double val = 0.0;
110 
111  m_STEP_Xorg->GetValue().ToDouble( &val );
112  cfg->m_ExportStep.origin_x = val;
113 
114  m_STEP_Yorg->GetValue().ToDouble( &val );
115  cfg->m_ExportStep.origin_y = val;
116 
117  cfg->m_ExportStep.no_virtual = m_cbRemoveVirtual->GetValue();
118  }
119 };
120 
122 
123 
124 DIALOG_EXPORT_STEP::DIALOG_EXPORT_STEP( PCB_EDIT_FRAME* aParent, const wxString& aBoardPath ) :
125  DIALOG_EXPORT_STEP_BASE( aParent )
126 {
127  m_parent = aParent;
128  m_boardPath = aBoardPath;
129  m_sdbSizerCancel->SetLabel( _( "Close" ) );
130  m_sdbSizerOK->SetLabel( _( "Export" ) );
131  m_sdbSizer->Layout();
132 
133  // Build default output file name
134  wxString path = m_parent->GetLastPath( LAST_PATH_STEP );
135 
136  if( path.IsEmpty() )
137  {
138  wxFileName brdFile = m_parent->GetBoard()->GetFileName();
139  brdFile.SetExt( "step" );
140  path = brdFile.GetFullPath();
141  }
142 
143  m_filePickerSTEP->SetPath( path );
144 
145  SetFocus();
146 
147  auto cfg = m_parent->GetPcbNewSettings();
148 
149  m_STEP_org_opt = static_cast<STEP_ORG_OPT>( cfg->m_ExportStep.origin_mode );
150 
151  switch( m_STEP_org_opt )
152  {
153  default: break;
154  case STEP_ORG_PLOT_AXIS: m_rbDrillAndPlotOrigin->SetValue( true ); break;
155  case STEP_ORG_GRID_AXIS: m_rbGridOrigin->SetValue( true ); break;
156  case STEP_ORG_USER: m_rbUserDefinedOrigin->SetValue( true ); break;
157  case STEP_ORG_BOARD_CENTER: m_rbBoardCenterOrigin->SetValue( true ); break;
158  }
159 
160  m_OrgUnits = cfg->m_ExportStep.origin_units;
161  m_XOrg = cfg->m_ExportStep.origin_x;
162  m_YOrg = cfg->m_ExportStep.origin_y;
163  m_noVirtual = cfg->m_ExportStep.no_virtual;
164 
165  m_cbRemoveVirtual->SetValue( m_noVirtual );
166  m_cbOverwriteFile->SetValue( m_overwriteFile );
167 
168  m_STEP_OrgUnitChoice->SetSelection( m_OrgUnits );
169  wxString tmpStr;
170  tmpStr << m_XOrg;
171  m_STEP_Xorg->SetValue( tmpStr );
172  tmpStr = "";
173  tmpStr << m_YOrg;
174  m_STEP_Yorg->SetValue( tmpStr );
175 
176  // Now all widgets have the size fixed, call FinishDialogSettings
178 }
179 
180 
182 {
184 
185  if( m_rbDrillAndPlotOrigin->GetValue() )
187  else if( m_rbGridOrigin->GetValue() )
189  else if( m_rbUserDefinedOrigin->GetValue() )
191  else if( m_rbBoardCenterOrigin->GetValue() )
193 
194  return m_STEP_org_opt;
195 }
196 
197 
198 void PCB_EDIT_FRAME::OnExportSTEP( wxCommandEvent& event )
199 {
200  wxFileName brdFile = GetBoard()->GetFileName();
201 
202  if( GetScreen()->IsModify() || brdFile.GetFullPath().empty() )
203  {
204  if( !doAutoSave() )
205  {
206  DisplayErrorMessage( this,
207  _( "STEP export failed! Please save the PCB and try again" ) );
208  return;
209  }
210 
211  // Use auto-saved board for export
212  brdFile.SetName( GetAutoSaveFilePrefix() + brdFile.GetName() );
213  }
214 
215  DIALOG_EXPORT_STEP dlg( this, brdFile.GetFullPath() );
216  dlg.ShowModal();
217 }
218 
219 
220 void DIALOG_EXPORT_STEP::onUpdateUnits( wxUpdateUIEvent& aEvent )
221 {
222  aEvent.Enable( m_rbUserDefinedOrigin->GetValue() );
223 }
224 
225 
226 void DIALOG_EXPORT_STEP::onUpdateXPos( wxUpdateUIEvent& aEvent )
227 {
228  aEvent.Enable( m_rbUserDefinedOrigin->GetValue() );
229 }
230 
231 
232 void DIALOG_EXPORT_STEP::onUpdateYPos( wxUpdateUIEvent& aEvent )
233 {
234  aEvent.Enable( m_rbUserDefinedOrigin->GetValue() );
235 }
236 
237 extern bool BuildBoardPolygonOutlines( BOARD* aBoard, SHAPE_POLY_SET& aOutlines,
238  wxString* aErrorText, unsigned int aTolerance,
239  wxPoint* aErrorLocation = nullptr );
240 
241 void DIALOG_EXPORT_STEP::onExportButton( wxCommandEvent& aEvent )
242 {
244 
245  SHAPE_POLY_SET outline;
246  wxString msg;
247 
248  // Check if the board outline is continuous
249  if( !BuildBoardPolygonOutlines( m_parent->GetBoard(), outline, &msg, Millimeter2iu( 0.01 ) ) )
250  {
251  DisplayErrorMessage( this, _( "Cannot determine the board outline." ), msg );
252  return;
253  }
254 
255  wxFileName fn = m_filePickerSTEP->GetFileName();
256 
257  if( fn.FileExists() && !GetOverwriteFile() )
258  {
259  msg.Printf( _( "File '%s' already exists. Do you want overwrite this file?" ),
260  fn.GetFullPath().GetData() );
261 
262  if( wxMessageBox( msg, _( "STEP Export" ), wxYES_NO | wxICON_QUESTION, this ) == wxNO )
263  return;
264  }
265 
267  double xOrg = 0.0;
268  double yOrg = 0.0;
269 
270  wxFileName appK2S( wxStandardPaths::Get().GetExecutablePath() );
271 
272 #ifdef __WXMAC__
273  // On macOS, we have standalone applications inside the main bundle, so we handle that here:
274  if( appK2S.GetPath().find( "/Contents/Applications/pcbnew.app/Contents/MacOS" ) != wxNOT_FOUND )
275  {
276  appK2S.AppendDir( ".." );
277  appK2S.AppendDir( ".." );
278  appK2S.AppendDir( ".." );
279  appK2S.AppendDir( ".." );
280  appK2S.AppendDir( "MacOS" );
281  }
282 #endif
283 
284  appK2S.SetName( "kicad2step" );
285 
286  wxString cmdK2S = "\"";
287  cmdK2S.Append( appK2S.GetFullPath() );
288  cmdK2S.Append( "\"" );
289 
290  if( GetNoVirtOption() )
291  cmdK2S.Append( " --no-virtual" );
292 
293  switch( orgOpt )
294  {
296  break;
297 
299  cmdK2S.Append( " --drill-origin" );
300  break;
301 
303  cmdK2S.Append( " --grid-origin" );
304  break;
305 
307  {
308  xOrg = GetXOrg();
309  yOrg = GetYOrg();
310 
311  if( GetOrgUnitsChoice() == 1 )
312  {
313  // selected reference unit is in inches, and STEP units are mm
314  xOrg *= 25.4;
315  yOrg *= 25.4;
316  }
317 
319  cmdK2S.Append( wxString::Format( " --user-origin=\"%.6f x %.6f\"", xOrg, yOrg ) );
320  }
321  break;
322 
324  {
325  EDA_RECT bbox = m_parent->GetBoard()->ComputeBoundingBox( true );
326  xOrg = Iu2Millimeter( bbox.GetCenter().x );
327  yOrg = Iu2Millimeter( bbox.GetCenter().y );
329  cmdK2S.Append( wxString::Format( " --user-origin=\"%.6f x %.6f\"", xOrg, yOrg ) );
330  }
331  break;
332  }
333 
334  if( m_tolerance->GetSelection() != 1 )
335  {
337  double tolerance = 0.001 * std::pow<double>( 10.0, m_tolerance->GetSelection() - 1 );
338  cmdK2S.Append( wxString::Format( " --min-distance=\"%.4f mm\"", tolerance ) );
339  }
340 
341  cmdK2S.Append( " -f -o " );
342  cmdK2S.Append( wxString::Format("\"%s\"", m_filePickerSTEP->GetPath() ) ); // input file path
343 
344  cmdK2S.Append( " " );
345  cmdK2S.Append( wxString::Format("\"%s\"", m_boardPath ) ); // output file path
346 
347  wxExecute( cmdK2S, wxEXEC_ASYNC | wxEXEC_SHOW_CONSOLE );
348 
349  aEvent.Skip(); // Close the dialog
350 }
DIALOG_EXPORT_STEP m_ExportStep
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:252
void onUpdateXPos(wxUpdateUIEvent &aEvent) override
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: common.h:216
This file is part of the common library.
bool doAutoSave() override
Function doAutoSave performs auto save when the board has been modified and not saved within the auto...
void OnExportSTEP(wxCommandEvent &event)
Function OnExportSTEP Exports the current BOARD to a STEP assembly.
wxRadioButton * m_rbDrillAndPlotOrigin
PCB_EDIT_FRAME * m_parent
void FinishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
double DoubleValueFromString(EDA_UNITS aUnits, const wxString &aTextValue, bool aUseMils, EDA_DATA_TYPE aType)
Function DoubleValueFromString converts aTextValue to a double.
Definition: base_units.cpp:346
PCBNEW_SETTINGS * GetPcbNewSettings()
const wxString & GetFileName() const
Definition: class_board.h:255
void SetValue(const wxString &aValue) override
Set a new value in evaluator buffer, and display it in the wxTextCtrl.
wxString GetLastPath(LAST_PATH_TYPE aType)
Get the last path for a particular type.
STEP_ORG_OPT GetOriginOption()
void onExportButton(wxCommandEvent &aEvent) override
wxFilePickerCtrl * m_filePickerSTEP
SHAPE_POLY_SET.
void onUpdateUnits(wxUpdateUIEvent &aEvent) override
wxStdDialogButtonSizer * m_sdbSizer
static wxString GetAutoSaveFilePrefix()
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
static LIB_PART * dummy()
Used to draw a dummy shape when a LIB_PART is not found in library.
BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:180
#define _(s)
Definition: 3d_actions.cpp:33
Class DIALOG_EXPORT_STEP_BASE.
EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
PCB_EDIT_FRAME is the main frame for Pcbnew.
PCB_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
bool BuildBoardPolygonOutlines(BOARD *aBoard, SHAPE_POLY_SET &aOutlines, wxString *aErrorText, unsigned int aTolerance, wxPoint *aErrorLocation=nullptr)
void onUpdateYPos(wxUpdateUIEvent &aEvent) override
EDA_RECT ComputeBoundingBox(bool aBoardEdgesOnly=false) const
Function ComputeBoundingBox calculates the bounding box containing all board items (or board edge seg...
BOARD * GetBoard() const
const wxPoint GetCenter() const
Definition: eda_rect.h:117
void SetLastPath(LAST_PATH_TYPE aType, const wxString &aLastPath)
Set the path of the last file successfully read.
DIALOG_EXPORT_STEP(PCB_EDIT_FRAME *aParent, const wxString &aBoardPath)