From 2f7ac2b5b47058089980ce551df3eed7780d4f78 Mon Sep 17 00:00:00 2001 From: Andrew Downing Date: Sat, 29 Feb 2020 02:21:18 +0000 Subject: [PATCH] Don't truncate polar coordinates in position relative dialog/move exact dialog --- common/widgets/unit_binder.cpp | 28 +++++++ include/widgets/unit_binder.h | 13 ++++ pcbnew/dialogs/dialog_move_exact.cpp | 86 +++++++++++++-------- pcbnew/dialogs/dialog_move_exact.h | 8 +- pcbnew/dialogs/dialog_position_relative.cpp | 81 ++++++++++++------- pcbnew/dialogs/dialog_position_relative.h | 8 +- 6 files changed, 163 insertions(+), 61 deletions(-) diff --git a/common/widgets/unit_binder.cpp b/common/widgets/unit_binder.cpp index 355f40bfde..1f1eefdd7e 100644 --- a/common/widgets/unit_binder.cpp +++ b/common/widgets/unit_binder.cpp @@ -195,6 +195,12 @@ void UNIT_BINDER::SetValue( int aValue ) } +void UNIT_BINDER::SetDoubleValue( double aValue ) +{ + SetValue( StringFromValue( m_units, aValue, false, m_useMils ) ); +} + + void UNIT_BINDER::SetValue( wxString aValue ) { auto textEntry = dynamic_cast( m_value ); @@ -257,6 +263,28 @@ long long int UNIT_BINDER::GetValue() } +double UNIT_BINDER::GetDoubleValue() +{ + auto textEntry = dynamic_cast( m_value ); + auto staticText = dynamic_cast( m_value ); + wxString value; + + if( textEntry ) + { + if( m_needsEval && m_eval.Process( textEntry->GetValue() ) ) + value = m_eval.Result(); + else + value = textEntry->GetValue(); + } + else if( staticText ) + value = staticText->GetLabel(); + else + return 0.0; + + return DoubleValueFromString( m_units, value, m_useMils ); +} + + bool UNIT_BINDER::IsIndeterminate() const { auto textEntry = dynamic_cast( m_value ); diff --git a/include/widgets/unit_binder.h b/include/widgets/unit_binder.h index 028d767d30..d4cef5e1ba 100644 --- a/include/widgets/unit_binder.h +++ b/include/widgets/unit_binder.h @@ -71,6 +71,13 @@ public: void SetValue( wxString aValue ); + /** + * Function SetDoubleValue + * Sets new value (in Internal Units) for the text field, taking care of units conversion. + * @param aValue is the new value. + */ + virtual void SetDoubleValue( double aValue ); + /** * Function ChangeValue * Changes the value (in Internal Units) for the text field, taking care of units conversion @@ -87,6 +94,12 @@ public: */ virtual long long int GetValue(); + /** + * Function GetValue + * Returns the current value in Internal Units. + */ + virtual double GetDoubleValue(); + /** * Function IsIndeterminate * Returns true if the control holds the indeterminate value (for instance, if it diff --git a/pcbnew/dialogs/dialog_move_exact.cpp b/pcbnew/dialogs/dialog_move_exact.cpp index 294d8b12c6..e1569c6407 100644 --- a/pcbnew/dialogs/dialog_move_exact.cpp +++ b/pcbnew/dialogs/dialog_move_exact.cpp @@ -41,7 +41,11 @@ DIALOG_MOVE_EXACT::DIALOG_MOVE_EXACT( PCB_BASE_FRAME *aParent, wxPoint& aTransla m_bbox( aBbox ), m_moveX( aParent, m_xLabel, m_xEntry, m_xUnit ), m_moveY( aParent, m_yLabel, m_yEntry, m_yUnit ), - m_rotate( aParent, m_rotLabel, m_rotEntry, m_rotUnit ) + m_rotate( aParent, m_rotLabel, m_rotEntry, m_rotUnit ), + m_stateX( 0.0 ), + m_stateY( 0.0 ), + m_stateRadius( 0.0 ), + m_stateTheta( 0.0 ) { // We can't set the tab order through wxWidgets due to shortcomings in their mnemonics // implementation on MSW @@ -66,8 +70,8 @@ DIALOG_MOVE_EXACT::DIALOG_MOVE_EXACT( PCB_BASE_FRAME *aParent, wxPoint& aTransla // and set up the entries according to the saved options m_polarCoords->SetValue( m_options.polarCoords ); - m_moveX.SetValue( m_options.entry1 ); - m_moveY.SetValue( m_options.entry2 ); + m_moveX.SetDoubleValue( m_options.entry1 ); + m_moveY.SetDoubleValue( m_options.entry2 ); m_rotate.SetUnits( EDA_UNITS::DEGREES ); m_rotate.SetValue( m_options.entryRotation ); @@ -115,12 +119,12 @@ void DIALOG_MOVE_EXACT::ToPolarDeg( double x, double y, double& r, double& q ) } -bool DIALOG_MOVE_EXACT::GetTranslationInIU ( wxPoint& val, bool polar ) +bool DIALOG_MOVE_EXACT::GetTranslationInIU( wxRealPoint& val, bool polar ) { if( polar ) { - const int r = m_moveX.GetValue(); - const double q = m_moveY.GetValue(); + const double r = m_moveX.GetDoubleValue(); + const double q = m_moveY.GetDoubleValue(); val.x = r * cos( DEG2RAD( q / 10.0 ) ); val.y = r * sin( DEG2RAD( q / 10.0 ) ); @@ -128,8 +132,8 @@ bool DIALOG_MOVE_EXACT::GetTranslationInIU ( wxPoint& val, bool polar ) else { // direct read - val.x = m_moveX.GetValue(); - val.y = m_moveY.GetValue(); + val.x = m_moveX.GetDoubleValue(); + val.y = m_moveY.GetDoubleValue(); } // no validation to do here, but in future, you could return false here @@ -140,33 +144,50 @@ bool DIALOG_MOVE_EXACT::GetTranslationInIU ( wxPoint& val, bool polar ) void DIALOG_MOVE_EXACT::OnPolarChanged( wxCommandEvent& event ) { bool newPolar = m_polarCoords->IsChecked(); - wxPoint val; - - // get the value as previously stored - GetTranslationInIU( val, !newPolar ); - - // now switch the controls to the new representations + double moveX = m_moveX.GetDoubleValue(); + double moveY = m_moveY.GetDoubleValue(); updateDialogControls( newPolar ); if( newPolar ) { - // convert to polar coordinates - double r, q; - ToPolarDeg( val.x, val.y, r, q ); + if( moveX != m_stateX || moveY != m_stateY ) + { + m_stateX = moveX; + m_stateY = moveY; + ToPolarDeg( m_stateX, m_stateY, m_stateRadius, m_stateTheta ); + m_stateTheta *= 10.0; - m_moveX.SetValue( KiROUND( r / 10.0) * 10 ); - m_moveY.SetValue( q * 10 ); + m_moveX.SetDoubleValue( m_stateRadius ); + m_stateRadius = m_moveX.GetDoubleValue(); + m_moveY.SetDoubleValue( m_stateTheta ); + m_stateTheta = m_moveY.GetDoubleValue(); + } + else + { + m_moveX.SetDoubleValue( m_stateRadius ); + m_moveY.SetDoubleValue( m_stateTheta ); + } } else { - // vector is already in Cartesian, so just render out - // note - round off the last decimal place (10nm) to prevent - // (some) rounding causing errors when round-tripping - // you can never eliminate entirely, however - m_moveX.SetValue( KiROUND( val.x / 10.0 ) * 10 ); - m_moveY.SetValue( KiROUND( val.y / 10.0 ) * 10 ); - } + if( moveX != m_stateRadius || moveY != m_stateTheta ) + { + m_stateRadius = moveX; + m_stateTheta = moveY; + m_stateX = m_stateRadius * cos( DEG2RAD( m_stateTheta / 10.0 ) ); + m_stateY = m_stateRadius * sin( DEG2RAD( m_stateTheta / 10.0 ) ); + m_moveX.SetDoubleValue( m_stateX ); + m_stateX = m_moveX.GetDoubleValue(); + m_moveY.SetDoubleValue( m_stateY ); + m_stateY = m_moveY.GetDoubleValue(); + } + else + { + m_moveX.SetDoubleValue( m_stateX ); + m_moveY.SetDoubleValue( m_stateY ); + } + } } @@ -214,7 +235,10 @@ void DIALOG_MOVE_EXACT::OnClear( wxCommandEvent& event ) bool DIALOG_MOVE_EXACT::TransferDataFromWindow() { // for the output, we only deliver a Cartesian vector - bool ok = GetTranslationInIU( m_translation, m_polarCoords->IsChecked() ); + wxRealPoint translation; + bool ok = GetTranslationInIU( translation, m_polarCoords->IsChecked() ); + m_translation.x = KiROUND(translation.x); + m_translation.y = KiROUND(translation.y); m_rotation = m_rotate.GetValue(); m_rotationAnchor = m_menuIDs[ m_anchorOptions->GetSelection() ]; @@ -222,8 +246,8 @@ bool DIALOG_MOVE_EXACT::TransferDataFromWindow() { // save the settings m_options.polarCoords = m_polarCoords->GetValue(); - m_options.entry1 = m_moveX.GetValue(); - m_options.entry2 = m_moveY.GetValue(); + m_options.entry1 = m_moveX.GetDoubleValue(); + m_options.entry2 = m_moveY.GetDoubleValue(); m_options.entryRotation = m_rotate.GetValue(); m_options.entryAnchorSelection = (size_t) std::max( m_anchorOptions->GetSelection(), 0 ); return true; @@ -247,8 +271,8 @@ void DIALOG_MOVE_EXACT::OnTextFocusLost( wxFocusEvent& event ) void DIALOG_MOVE_EXACT::OnTextChanged( wxCommandEvent& event ) { - double delta_x = m_moveX.GetValue(); - double delta_y = m_moveY.GetValue(); + double delta_x = m_moveX.GetDoubleValue(); + double delta_y = m_moveY.GetDoubleValue(); double max_border = std::numeric_limits::max() * 0.7071; if( m_bbox.GetLeft() + delta_x < -max_border || diff --git a/pcbnew/dialogs/dialog_move_exact.h b/pcbnew/dialogs/dialog_move_exact.h index 31690601a3..b9f694e01a 100644 --- a/pcbnew/dialogs/dialog_move_exact.h +++ b/pcbnew/dialogs/dialog_move_exact.h @@ -57,6 +57,12 @@ private: std::vector m_menuIDs; + double m_stateX; + double m_stateY; + double m_stateRadius; + double m_stateTheta; + + public: // Constructor and destructor DIALOG_MOVE_EXACT(PCB_BASE_FRAME *aParent, wxPoint& aTranslate, @@ -92,7 +98,7 @@ private: * @param polar interpret as polar coords * @return false if error (though the text conversion functions don't report errors) */ - bool GetTranslationInIU ( wxPoint& val, bool polar ); + bool GetTranslationInIU( wxRealPoint& val, bool polar ); void buildRotationAnchorMenu(); diff --git a/pcbnew/dialogs/dialog_position_relative.cpp b/pcbnew/dialogs/dialog_position_relative.cpp index a5f6c544d1..719e1c1979 100644 --- a/pcbnew/dialogs/dialog_position_relative.cpp +++ b/pcbnew/dialogs/dialog_position_relative.cpp @@ -38,7 +38,11 @@ DIALOG_POSITION_RELATIVE::DIALOG_POSITION_RELATIVE( PCB_BASE_FRAME* aParent, wxP m_translation( translation ), m_anchor_position( anchor ), m_xOffset( aParent, m_xLabel, m_xEntry, m_xUnit ), - m_yOffset( aParent, m_yLabel, m_yEntry, m_yUnit ) + m_yOffset( aParent, m_yLabel, m_yEntry, m_yUnit ), + m_stateX( 0.0 ), + m_stateY( 0.0 ), + m_stateRadius( 0.0 ), + m_stateTheta( 0.0 ) { // We can't set the tab order through wxWidgets due to shortcomings in their mnemonics // implementation on MSW @@ -55,8 +59,8 @@ DIALOG_POSITION_RELATIVE::DIALOG_POSITION_RELATIVE( PCB_BASE_FRAME* aParent, wxP m_polarCoords->SetValue( m_options.polarCoords ); updateDialogControls( m_polarCoords->IsChecked() ); - m_xOffset.SetValue( m_options.entry1 ); - m_yOffset.SetValue( m_options.entry2 ); + m_xOffset.SetDoubleValue( m_options.entry1 ); + m_yOffset.SetDoubleValue( m_options.entry2 ); m_stdButtonsOK->SetDefault(); @@ -73,12 +77,12 @@ void DIALOG_POSITION_RELATIVE::ToPolarDeg( double x, double y, double& r, double } -bool DIALOG_POSITION_RELATIVE::GetTranslationInIU ( wxPoint& val, bool polar ) +bool DIALOG_POSITION_RELATIVE::GetTranslationInIU( wxRealPoint& val, bool polar ) { if( polar ) { - const int r = m_xOffset.GetValue(); - const double q = m_yOffset.GetValue(); + const double r = m_xOffset.GetDoubleValue(); + const double q = m_yOffset.GetDoubleValue(); val.x = r * cos( DEG2RAD( q / 10.0 ) ); val.y = r * sin( DEG2RAD( q / 10.0 ) ); @@ -86,8 +90,8 @@ bool DIALOG_POSITION_RELATIVE::GetTranslationInIU ( wxPoint& val, bool polar ) else { // direct read - val.x = m_xOffset.GetValue(); - val.y = m_yOffset.GetValue(); + val.x = m_xOffset.GetDoubleValue(); + val.y = m_yOffset.GetDoubleValue(); } // no validation to do here, but in future, you could return false here @@ -98,31 +102,49 @@ bool DIALOG_POSITION_RELATIVE::GetTranslationInIU ( wxPoint& val, bool polar ) void DIALOG_POSITION_RELATIVE::OnPolarChanged( wxCommandEvent& event ) { bool newPolar = m_polarCoords->IsChecked(); - wxPoint val; - - // get the value as previously stored - GetTranslationInIU( val, !newPolar ); - - // now switch the controls to the new representations + double xOffset = m_xOffset.GetDoubleValue(); + double yOffset = m_yOffset.GetDoubleValue(); updateDialogControls( newPolar ); if( newPolar ) { - // convert to polar coordinates - double r, q; - ToPolarDeg( val.x, val.y, r, q ); + if( xOffset != m_stateX || yOffset != m_stateY ) + { + m_stateX = xOffset; + m_stateY = yOffset; + ToPolarDeg( m_stateX, m_stateY, m_stateRadius, m_stateTheta ); + m_stateTheta *= 10.0; - m_xOffset.SetValue( KiROUND( r / 10.0) * 10 ); - m_yOffset.SetValue( q * 10 ); + m_xOffset.SetDoubleValue( m_stateRadius ); + m_stateRadius = m_xOffset.GetDoubleValue(); + m_yOffset.SetDoubleValue( m_stateTheta ); + m_stateTheta = m_yOffset.GetDoubleValue(); + } + else + { + m_xOffset.SetDoubleValue( m_stateRadius ); + m_yOffset.SetDoubleValue( m_stateTheta ); + } } else { - // vector is already in Cartesian, so just render out - // note - round off the last decimal place (10nm) to prevent - // (some) rounding causing errors when round-tripping - // you can never eliminate entirely, however - m_xOffset.SetValue( KiROUND( val.x / 10.0 ) * 10 ); - m_yOffset.SetValue( KiROUND( val.y / 10.0 ) * 10 ); + if( xOffset != m_stateRadius || yOffset != m_stateTheta ) + { + m_stateRadius = xOffset; + m_stateTheta = yOffset; + m_stateX = m_stateRadius * cos( DEG2RAD( m_stateTheta / 10.0 ) ); + m_stateY = m_stateRadius * sin( DEG2RAD( m_stateTheta / 10.0 ) ); + + m_xOffset.SetDoubleValue( m_stateX ); + m_stateX = m_xOffset.GetDoubleValue(); + m_yOffset.SetDoubleValue( m_stateY ); + m_stateY = m_yOffset.GetDoubleValue(); + } + else + { + m_xOffset.SetDoubleValue( m_stateX ); + m_yOffset.SetDoubleValue( m_stateY ); + } } } @@ -209,14 +231,17 @@ void DIALOG_POSITION_RELATIVE::UpdateAnchor( EDA_ITEM* aItem ) void DIALOG_POSITION_RELATIVE::OnOkClick( wxCommandEvent& event ) { // for the output, we only deliver a Cartesian vector - bool ok = GetTranslationInIU( m_translation, m_polarCoords->IsChecked() ); + wxRealPoint translation; + bool ok = GetTranslationInIU( translation, m_polarCoords->IsChecked() ); + m_translation.x = KiROUND( translation.x ); + m_translation.y = KiROUND( translation.y ); if( ok ) { // save the settings m_options.polarCoords = m_polarCoords->GetValue(); - m_options.entry1 = m_xOffset.GetValue(); - m_options.entry2 = m_yOffset.GetValue(); + m_options.entry1 = m_xOffset.GetDoubleValue(); + m_options.entry2 = m_yOffset.GetDoubleValue(); POSITION_RELATIVE_TOOL* posrelTool = m_toolMgr->GetTool(); wxASSERT( posrelTool ); diff --git a/pcbnew/dialogs/dialog_position_relative.h b/pcbnew/dialogs/dialog_position_relative.h index fa142aa6e4..8debc6656c 100644 --- a/pcbnew/dialogs/dialog_position_relative.h +++ b/pcbnew/dialogs/dialog_position_relative.h @@ -43,6 +43,12 @@ private: UNIT_BINDER m_xOffset; UNIT_BINDER m_yOffset; + double m_stateX; + double m_stateY; + double m_stateRadius; + double m_stateTheta; + + public: // Constructor and destructor DIALOG_POSITION_RELATIVE( PCB_BASE_FRAME* aParent, wxPoint& translation, wxPoint& anchor ); @@ -79,7 +85,7 @@ private: * @param polar interpret as polar coords * @return false if error (though the text conversion functions don't report errors) */ - bool GetTranslationInIU( wxPoint& val, bool polar ); + bool GetTranslationInIU( wxRealPoint& val, bool polar ); // Update controls and their labels after changing the coordinates type (polar/cartesian) void updateDialogControls( bool aPolar );