KiCad PCB EDA Suite
dialog_move_exact.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) 2014 John Beard, john.j.beard@gmail.com
5  * Copyright (C) 2018 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 <pcb_edit_frame.h>
26 
27 #include "dialog_move_exact.h"
28 
29 // initialise statics
31 
32 
34  double& aRotate, ROTATION_ANCHOR& aAnchor ) :
35  DIALOG_MOVE_EXACT_BASE( aParent ),
36  m_translation( aTranslate ),
37  m_rotation( aRotate ),
38  m_rotationAnchor( aAnchor ),
39  m_moveX( aParent, m_xLabel, m_xEntry, m_xUnit ),
40  m_moveY( aParent, m_yLabel, m_yEntry, m_yUnit ),
41  m_rotate( aParent, m_rotLabel, m_rotEntry, m_rotUnit )
42 {
43  // tabbing goes through the entries in sequence
44  m_yEntry->MoveAfterInTabOrder( m_xEntry );
45  m_rotEntry->MoveAfterInTabOrder( m_yEntry );
46 
48 
49  m_menuIDs.push_back( aAnchor );
51 
52  if( aParent->IsType( FRAME_PCB ) )
54 
56 
57  // and set up the entries according to the saved options
58  m_polarCoords->SetValue( m_options.polarCoords );
61 
65 
66  m_stdButtonsOK->SetDefault();
67 
69 }
70 
71 
73 {
74  wxArrayString menuItems;
75 
76  for( auto anchorID : m_menuIDs )
77  {
78  switch( anchorID )
79  {
81  menuItems.push_back( _( "Rotate around item anchor" ) );
82  break;
84  menuItems.push_back( _( "Rotate around selection center" ) );
85  break;
87  menuItems.push_back( _( "Rotate around user origin" ) );
88  break;
90  menuItems.push_back( _( "Rotate around drill/place origin" ) );
91  break;
92  }
93  }
94 
95  m_anchorOptions->Set( menuItems );
96 }
97 
98 
99 void DIALOG_MOVE_EXACT::ToPolarDeg( double x, double y, double& r, double& q )
100 {
101  // convert to polar coordinates
102  r = hypot( x, y );
103 
104  q = ( r != 0) ? RAD2DEG( atan2( y, x ) ) : 0;
105 }
106 
107 
109 {
110  if( polar )
111  {
112  const int r = m_moveX.GetValue();
113  const double q = m_moveY.GetValue();
114 
115  val.x = r * cos( DEG2RAD( q / 10.0 ) );
116  val.y = r * sin( DEG2RAD( q / 10.0 ) );
117  }
118  else
119  {
120  // direct read
121  val.x = m_moveX.GetValue();
122  val.y = m_moveY.GetValue();
123  }
124 
125  // no validation to do here, but in future, you could return false here
126  return true;
127 }
128 
129 
130 void DIALOG_MOVE_EXACT::OnPolarChanged( wxCommandEvent& event )
131 {
132  bool newPolar = m_polarCoords->IsChecked();
133  wxPoint val;
134 
135  // get the value as previously stored
136  GetTranslationInIU( val, !newPolar );
137 
138  // now switch the controls to the new representations
139  updateDialogControls( newPolar );
140 
141  if( newPolar )
142  {
143  // convert to polar coordinates
144  double r, q;
145  ToPolarDeg( val.x, val.y, r, q );
146 
147  m_moveX.SetValue( KiROUND( r / 10.0) * 10 );
148  m_moveY.SetValue( q * 10 );
149  }
150  else
151  {
152  // vector is already in Cartesian, so just render out
153  // note - round off the last decimal place (10nm) to prevent
154  // (some) rounding causing errors when round-tripping
155  // you can never eliminate entirely, however
156  m_moveX.SetValue( KiROUND( val.x / 10.0 ) * 10 );
157  m_moveY.SetValue( KiROUND( val.y / 10.0 ) * 10 );
158  }
159 
160 }
161 
162 
164 {
165  if( aPolar )
166  {
167  m_moveX.SetLabel( _( "Distance:" ) ); // Polar radius
168  m_moveY.SetLabel( _( "Angle:" ) ); // Polar theta or angle
170  }
171  else
172  {
173  m_moveX.SetLabel( _( "Move X:" ) );
174  m_moveY.SetLabel( _( "Move Y:" ) );
176  }
177 
178  Layout();
179 }
180 
181 
182 void DIALOG_MOVE_EXACT::OnClear( wxCommandEvent& event )
183 {
184  wxObject* obj = event.GetEventObject();
185 
186  if( obj == m_clearX )
187  {
188  m_moveX.SetValue( 0 );
189  }
190  else if( obj == m_clearY )
191  {
192  m_moveY.SetValue( 0 );
193  }
194  else if( obj == m_clearRot )
195  {
196  m_rotate.SetValue( 0 );
197  }
198 
199  // Keep m_stdButtonsOK focused to allow enter key actiavte the OK button
200  m_stdButtonsOK->SetFocus();
201 }
202 
203 
205 {
206  // for the output, we only deliver a Cartesian vector
207  bool ok = GetTranslationInIU( m_translation, m_polarCoords->IsChecked() );
209  m_rotationAnchor = m_menuIDs[ m_anchorOptions->GetSelection() ];
210 
211  if( ok )
212  {
213  // save the settings
214  m_options.polarCoords = m_polarCoords->GetValue();
218  m_options.entryAnchorSelection = (size_t) std::max( m_anchorOptions->GetSelection(), 0 );
219  return true;
220  }
221 
222  return false;
223 }
224 
225 
226 void DIALOG_MOVE_EXACT::OnTextFocusLost( wxFocusEvent& event )
227 {
228  wxTextCtrl* obj = static_cast<wxTextCtrl*>( event.GetEventObject() );
229 
230  if( obj->GetValue().IsEmpty() )
231  obj->SetValue( "0" );
232 
233  event.Skip();
234 }
static int KiROUND(double v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: common.h:120
ROTATION_ANCHOR & m_rotationAnchor
std::vector< ROTATION_ANCHOR > m_menuIDs
Class DIALOG_MOVE_EXACT_BASE.
double RAD2DEG(double rad)
Definition: trigo.h:200
void FinishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
virtual void SetUnits(EDA_UNITS_T aUnits, bool aUseMils=false)
Function SetUnits Normally not needed (as the UNIT_BINDER inherits from the parent frame)...
Definition: unit_binder.cpp:64
virtual int GetValue()
Function GetValue Returns the current value in Internal Units.
void OnPolarChanged(wxCommandEvent &event) override
bool GetTranslationInIU(wxPoint &val, bool polar)
Get the (Cartesian) translation described by the text entries.
DIALOG_MOVE_EXACT(PCB_BASE_FRAME *aParent, wxPoint &aTranslate, double &aRotate, ROTATION_ANCHOR &aAnchor)
ROTATION_ANCHOR
void OnTextFocusLost(wxFocusEvent &event) override
void OnClear(wxCommandEvent &event) override
void updateDialogControls(bool aPolar)
void SetLabel(const wxString &aLabel)
double DEG2RAD(double deg)
Definition: trigo.h:199
#define max(a, b)
Definition: auxiliary.h:86
virtual void SetValue(int aValue)
Function SetValue Sets new value (in Internal Units) for the text field, taking care of units convers...
bool TransferDataFromWindow() override
void ToPolarDeg(double x, double y, double &r, double &q)
Convert a given Cartesian point into a polar representation.
static MOVE_EXACT_OPTIONS m_options
bool IsType(FRAME_T aType) const
class PCB_BASE_FRAME basic PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer...
#define min(a, b)
Definition: auxiliary.h:85
EDA_UNITS_T GetUserUnits() const override
Definition: dialog_shim.h:132